Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
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 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "ninput.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
;
}
#include "input_internal.h"
/*****************************************************************************
* access2_New:
...
...
src/input/
input_
clock.c
→
src/input/clock.c
View file @
68d21786
...
...
@@ -24,14 +24,11 @@
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <string.h>
/* memcpy(), memset() */
#include <stdlib.h>
#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include <vlc/input.h>
#include "input_internal.h"
/*
* DISCUSSION : SYNCHRONIZATION METHOD
...
...
@@ -67,7 +64,8 @@
* 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
);
/*****************************************************************************
...
...
@@ -84,19 +82,19 @@ static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
/*****************************************************************************
* ClockToSysdate: converts a movie clock to system date
*****************************************************************************/
static
mtime_t
ClockToSysdate
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_clock
)
static
mtime_t
ClockToSysdate
(
input_thread_t
*
p_input
,
input_clock_t
*
cl
,
mtime_t
i_clock
)
{
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
)
*
(
mtime_t
)
p_input
->
stream
.
control
.
i_rate
i_sysdate
=
(
mtime_t
)(
i_clock
-
cl
->
cr_ref
)
*
(
mtime_t
)
p_input
->
i_rate
*
(
mtime_t
)
300
;
i_sysdate
/=
27
;
i_sysdate
/=
1000
;
i_sysdate
+=
(
mtime_t
)
p_pgrm
->
sysdate_ref
;
i_sysdate
+=
(
mtime_t
)
cl
->
sysdate_ref
;
}
return
(
i_sysdate
);
...
...
@@ -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.
*****************************************************************************/
static
mtime_t
ClockCurrent
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
)
static
mtime_t
ClockCurrent
(
input_thread_t
*
p_input
,
input_clock_t
*
cl
)
{
return
(
(
mdate
()
-
p_pgrm
->
sysdate_ref
)
*
27
*
DEFAULT_RATE
/
p_input
->
stream
.
control
.
i_rate
/
300
+
p_pgrm
->
cr_ref
);
return
(
(
mdate
()
-
cl
->
sysdate_ref
)
*
27
*
INPUT_RATE_DEFAULT
/
p_input
->
i_rate
/
300
+
cl
->
cr_ref
);
}
/*****************************************************************************
* 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
)
{
p_pgrm
->
cr_ref
=
i_clock
;
p_pgrm
->
sysdate_ref
=
i_sysdate
;
cl
->
cr_ref
=
i_clock
;
cl
->
sysdate_ref
=
i_sysdate
;
}
/*****************************************************************************
* input_ClockInit: reinitializes the clock reference after a stream
* 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
;
p_pgrm
->
last_pts
=
0
;
p_pgrm
->
cr_ref
=
0
;
p_pgrm
->
sysdate_ref
=
0
;
p_pgrm
->
delta_cr
=
0
;
p_pgrm
->
c_average_count
=
0
;
cl
->
i_synchro_state
=
SYNCHRO_START
;
cl
->
last_cr
=
0
;
cl
->
last_pts
=
0
;
cl
->
cr_ref
=
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
*****************************************************************************
* Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
*****************************************************************************/
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;
int i_return_value = UNDEF_S;
...
...
@@ -221,36 +227,32 @@ int input_ClockManageControl( input_thread_t * p_input,
vlc_mutex_unlock( &p_input->stream.stream_lock );
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
,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_clock
)
void
input_Clock
SetPCR
(
input_thread_t
*
p_input
,
input_clock_t
*
cl
,
mtime_t
i_clock
)
{
/* take selected program if none specified */
if
(
!
p_pgrm
)
{
p_pgrm
=
p_input
->
stream
.
p_selected_program
;
}
if
(
(
p_pgrm
->
i_synchro_state
!=
SYNCHRO_OK
)
||
(
i_clock
==
0
&&
p_pgrm
->
last_cr
!=
0
)
)
if
(
(
cl
->
i_synchro_state
!=
SYNCHRO_OK
)
||
(
i_clock
==
0
&&
cl
->
last_cr
!=
0
)
)
{
/* Feed synchro with a new reference point. */
ClockNewRef
(
p_pgrm
,
i_clock
,
p_pgrm
->
last_pts
+
CR_MEAN_PTS_GAP
>
mdate
()
?
p_pgrm
->
last_pts
+
CR_MEAN_PTS_GAP
:
mdate
()
);
p_pgrm
->
i_synchro_state
=
SYNCHRO_OK
;
ClockNewRef
(
cl
,
i_clock
,
cl
->
last_pts
+
CR_MEAN_PTS_GAP
>
mdate
()
?
cl
->
last_pts
+
CR_MEAN_PTS_GAP
:
mdate
()
);
cl
->
i_synchro_state
=
SYNCHRO_OK
;
if
(
p_input
->
stream
.
b_pace_control
&&
p_input
->
stream
.
p_selected_program
==
p_pgrm
)
if
(
p_input
->
b_can_pace_control
&&
cl
->
b_master
)
{
p_pgrm
->
last_cr
=
i_clock
;
cl
->
last_cr
=
i_clock
;
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
)
{
msleep
(
CLOCK_FREQ
);
...
...
@@ -261,37 +263,38 @@ void input_ClockManageRef( input_thread_t * p_input,
}
else
{
p_pgrm
->
last_cr
=
0
;
p_pgrm
->
delta_cr
=
0
;
p_pgrm
->
c_average_count
=
0
;
cl
->
last_cr
=
0
;
cl
->
delta_cr
=
0
;
cl
->
c_average_count
=
0
;
}
}
else
{
if
(
p_pgrm
->
last_cr
!=
0
&&
(
(
p_pgrm
->
last_cr
-
i_clock
)
>
CR_MAX_GAP
||
(
p_pgrm
->
last_cr
-
i_clock
)
<
-
CR_MAX_GAP
)
)
if
(
cl
->
last_cr
!=
0
&&
(
(
cl
->
last_cr
-
i_clock
)
>
CR_MAX_GAP
||
(
cl
->
last_cr
-
i_clock
)
<
-
CR_MAX_GAP
)
)
{
/* Stream discontinuity, for which we haven't received a
* warning from the stream control facilities (dd-edited
* stream ?). */
msg_Warn
(
p_input
,
"clock gap, unexpected stream discontinuity"
);
input_ClockInit
(
p_pgrm
);
p_pgrm
->
i_synchro_state
=
SYNCHRO_START
;
input_ClockInit
(
cl
,
cl
->
b_master
,
cl
->
i_cr_average
);
/* FIXME needed ? */
#if 0
input_EscapeDiscontinuity( p_input );
#endif
}
p_pgrm
->
last_cr
=
i_clock
;
cl
->
last_cr
=
i_clock
;
if
(
p_input
->
stream
.
b_pace_control
&&
p_input
->
stream
.
p_selected_program
==
p_pgrm
)
if
(
p_input
->
b_can_pace_control
&&
cl
->
b_master
)
{
/* Wait a while before delivering the packets to the decoder.
* In case of multiple programs, we arbitrarily follow the
* clock of the selected program. */
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
)
{
msleep
(
CLOCK_FREQ
);
...
...
@@ -299,30 +302,32 @@ void input_ClockManageRef( input_thread_t * p_input,
}
mwait
(
i_wakeup
);
}
/* FIXME Not needed anymore ? */
#if 0
/* Now take into account interface changes. */
input_ClockManageControl
(
p_input
,
p_pgrm
,
i_clock
);
input_ClockManageControl( p_input, cl, i_clock );
#endif
}
else
{
/* 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. */
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
*
(
p_input
->
i_cr_average
-
1
)
cl
->
delta_cr
=
(
cl
->
delta_cr
*
(
cl
->
i_cr_average
-
1
)
+
(
i_extrapoled_clock
-
i_clock
)
)
/
p_input
->
i_cr_average
;
/
cl
->
i_cr_average
;
}
else
{
p_pgrm
->
delta_cr
=
(
p_pgrm
->
delta_cr
*
p_pgrm
->
c_average_count
cl
->
delta_cr
=
(
cl
->
delta_cr
*
cl
->
c_average_count
+
(
i_extrapoled_clock
-
i_clock
)
)
/
(
p_pgrm
->
c_average_count
+
1
);
p_pgrm
->
c_average_count
++
;
/
(
cl
->
c_average_count
+
1
);
cl
->
c_average_count
++
;
}
}
}
...
...
@@ -332,23 +337,12 @@ void input_ClockManageRef( input_thread_t * p_input,
* input_ClockGetTS: manages a PTS or DTS
*****************************************************************************/
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
(
!
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
{
if
(
cl
->
i_synchro_state
!=
SYNCHRO_OK
)
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 @@
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "input_internal.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
*
);
...
...
@@ -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
i_ret
;
seekpoint_t
*
p_bkmk
,
***
ppp_bkmk
;
int
i_bkmk
=
0
;
int
*
pi_bkmk
;
...
...
@@ -75,54 +64,50 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
double
f
,
*
pf
;
int64_t
i_64
,
*
pi_64
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
switch
(
i_query
)
{
case
INPUT_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
*
pf
=
var_GetFloat
(
p_input
,
"position"
);
i_ret
=
VLC_SUCCESS
;
break
;
return
VLC_SUCCESS
;
case
INPUT_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
i_ret
=
var_SetFloat
(
p_input
,
"position"
,
f
);
break
;
return
var_SetFloat
(
p_input
,
"position"
,
f
);
case
INPUT_GET_LENGTH
:
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
var_GetTime
(
p_input
,
"length"
);
i_ret
=
VLC_SUCCESS
;
break
;
return
VLC_SUCCESS
;
case
INPUT_GET_TIME
:
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
var_GetTime
(
p_input
,
"time"
);
i_ret
=
VLC_SUCCESS
;
break
;
return
VLC_SUCCESS
;
case
INPUT_SET_TIME
:
i_64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
i_ret
=
var_SetTime
(
p_input
,
"time"
,
i_64
);
break
;
return
var_SetTime
(
p_input
,
"time"
,
i_64
);
case
INPUT_GET_RATE
:
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
pi_int
=
var_GetInteger
(
p_input
,
"rate"
);
i_ret
=
VLC_SUCCESS
;
break
;
return
VLC_SUCCESS
;
case
INPUT_SET_RATE
:
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_ret
=
var_SetInteger
(
p_input
,
"rate"
,
i_int
);
break
;
return
var_SetInteger
(
p_input
,
"rate"
,
i_int
);
case
INPUT_GET_STATE
:
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
pi_int
=
var_GetInteger
(
p_input
,
"state"
);
i_ret
=
VLC_SUCCESS
;
break
;
return
VLC_SUCCESS
;
case
INPUT_SET_STATE
:
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_ret
=
var_SetInteger
(
p_input
,
"state"
,
i_int
);
break
;
return
var_SetInteger
(
p_input
,
"state"
,
i_int
);
#if 0
case INPUT_ADD_OPTION:
{
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 )
i_ret = VLC_EGENERIC;
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++ )
{
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 )
i_ret = VLC_EGENERIC;
}
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:
msg_Err
(
p_input
,
"unknown query in input_vaControl"
);
i_ret
=
VLC_EGENERIC
;
break
;
return
VLC_EGENERIC
;
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
i_ret
;
}
static
void
UpdateBookmarksOption
(
input_thread_t
*
p_input
)
{
int
i
,
i_len
=
0
;
char
*
psz_value
=
NULL
,
*
psz_next
=
NULL
;
/* FIXME */
#if 0
vlc_mutex_unlock( &p_input->stream.stream_lock );
for( i = 0; i < p_input->i_bookmarks; i++ )
...
...
@@ -546,4 +542,5 @@ static void UpdateBookmarksOption( input_thread_t *p_input )
psz_value ? psz_value : "" );
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
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@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
...
...
@@ -26,25 +27,20 @@
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
/* memcpy(), memset() */
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include <vlc/vout.h>
#include <vlc/input.h>
#include "stream_output.h"
#include "input_internal.h"
#include "input_ext-intf.h"
#include "input_ext-plugins.h"
#include "codecs.h"
static
void
input_NullPacket
(
input_thread_t
*
,
es_descriptor_t
*
);
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
,
es_format_t
*
,
int
);
static
void
DeleteDecoder
(
decoder_t
*
);
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
,
es_descriptor_t
*
,
int
);
static
int
DecoderThread
(
decoder_t
*
);
static
int
DecoderDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
);
static
void
DeleteDecoder
(
decoder_t
*
);
/* Buffers allocation callbacks for the decoders */
static
aout_buffer_t
*
aout_new_buffer
(
decoder_t
*
,
int
);
...
...
@@ -81,10 +77,6 @@ struct decoder_owner_sys_t
/* 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
* \param p_es the es descriptor
* \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
;
vlc_value_t
val
;
/* 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 */
p_dec
=
CreateDecoder
(
p_input
,
p_es
,
VLC_OBJECT_PACKETIZER
);
p_dec
=
CreateDecoder
(
p_input
,
fmt
,
VLC_OBJECT_PACKETIZER
);
if
(
p_dec
==
NULL
)
{
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 )
else
{
/* 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
)
{
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 )
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"
);
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 )
if
(
p_dec
->
p_owner
->
b_own_thread
)
{
int
i_priority
;
if
(
p_es
->
i_cat
==
AUDIO_ES
)
{
if
(
fmt
->
i_cat
==
AUDIO_ES
)
i_priority
=
VLC_THREAD_PRIORITY_AUDIO
;
}
else
{
i_priority
=
VLC_THREAD_PRIORITY_VIDEO
;
}
/* Spawn the decoder thread */
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 )
}
}
/* 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
;
}
...
...
@@ -187,10 +169,8 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
* \param p_es the es descriptor
* \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
;
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 )
/* Make sure the thread leaves the function by
* sending it an empty block. */
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
);
...
...
@@ -215,55 +195,6 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
/* Delete the decoder */
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 )
* \param p_dec the decoder object
* \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
)
{
...
...
@@ -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
*
...
...
@@ -311,6 +261,7 @@ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
static void input_NullPacket( input_thread_t * p_input,
es_descriptor_t * p_es )
{
#if 0
block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
if( p_block )
{
...
...
@@ -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 );
}
#endif
}
/**
...
...
@@ -329,6 +281,7 @@ static void input_NullPacket( input_thread_t * p_input,
*/
void input_EscapeDiscontinuity( input_thread_t * p_input )
{
#if 0
unsigned int i_es, i;
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 )
}
}
}
#endif
}
/**
...
...
@@ -353,6 +307,7 @@ void input_EscapeDiscontinuity( input_thread_t * p_input )
*/
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
{
#if 0
unsigned int i_es, i;
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 )
}
}
}
#endif
}
#endif
/**
* Create a decoder object
...
...
@@ -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
* \return the decoder object
*/
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
p_input
,
es_
descriptor_t
*
p_es
,
int
i_object_type
)
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
p_input
,
es_
format_t
*
fmt
,
int
i_object_type
)
{
decoder_t
*
p_dec
;
...
...
@@ -397,67 +354,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
/* Initialize the decoder fifo */
p_dec
->
p_module
=
NULL
;
es_format_Copy
(
&
p_dec
->
fmt_in
,
&
p_es
->
fmt
);
if
(
p_es
->
p_waveformatex
)
{
#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
;
es_format_Copy
(
&
p_dec
->
fmt_in
,
fmt
);
es_format_Copy
(
&
p_dec
->
fmt_out
,
&
null_es_format
);
/* 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
)
{
msg_Err
(
p_dec
,
"out of memory"
);
...
...
@@ -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_input
=
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_packetizer
=
NULL
;
p_dec
->
p_owner
->
p_es_descriptor
=
p_es
;
/* decoder fifo */
...
...
@@ -480,8 +381,6 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
msg_Err
(
p_dec
,
"out of memory"
);
return
NULL
;
}
p_dec
->
p_owner
->
p_method_data
=
p_input
->
p_method_data
;
/* Set buffers allocation callbacks for the decoders */
p_dec
->
pf_aout_buffer_new
=
aout_new_buffer
;
p_dec
->
pf_aout_buffer_del
=
aout_del_buffer
;
...
...
@@ -506,11 +405,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
vlc_object_create
(
p_input
,
VLC_OBJECT_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
,
&
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
);
p_dec
->
p_owner
->
p_packetizer
->
p_module
=
...
...
@@ -591,13 +491,9 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
if
(
!
p_dec
->
p_owner
->
p_sout_input
)
{
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
->
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
;
p_dec
->
p_owner
->
sout
.
i_group
=
p_dec
->
fmt_in
.
i_group
;
p_dec
->
p_owner
->
sout
.
i_id
=
p_dec
->
fmt_in
.
i_id
;
if
(
p_dec
->
fmt_in
.
psz_language
)
{
p_dec
->
p_owner
->
sout
.
psz_language
=
...
...
src/input/demux.c
View file @
68d21786
...
...
@@ -25,148 +25,11 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "ninput.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
);
}
#include "input_internal.h"
/*****************************************************************************
* demux2_New:
* if s is NULL then load a access_demux
*****************************************************************************/
demux_t
*
__demux2_New
(
vlc_object_t
*
p_obj
,
char
*
psz_access
,
char
*
psz_demux
,
char
*
psz_path
,
...
...
@@ -198,8 +61,12 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
p_demux
->
info
.
i_title
=
0
;
p_demux
->
info
.
i_seekpoint
=
0
;
psz_module
=
p_demux
->
psz_demux
;
if
(
*
psz_module
==
'\0'
&&
strrchr
(
p_demux
->
psz_path
,
'.'
)
)
if
(
s
)
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.
* - 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,
/* Before module_Need (for var_Create...) */
vlc_object_attach
(
p_demux
,
p_obj
);
p_demux
->
p_module
=
module_Need
(
p_demux
,
"demux2"
,
psz_module
,
!
strcmp
(
psz_module
,
p_demux
->
psz_demux
)
?
VLC_TRUE
:
VLC_FALSE
);
if
(
s
)
{
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
)
{
...
...
@@ -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 @@
#include <vlc/input.h>
#include <vlc/decoder.h>
#include "input_internal.h"
#include "vlc_playlist.h"
#include "codecs.h"
#include "iso_lang.h"
/*****************************************************************************
* 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
{
int
i_channel
;
es_descriptor_t
*
p_es
;
/* ES ID */
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
{
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 */
int
i_id
;
int
i_es
;
es_out_id_t
**
es
;
...
...
@@ -75,16 +102,17 @@ struct es_out_sys_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
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
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
);
/**
* Create a new es_out structure
*
* \param p_input The related input thread
* \return the new es_out_t
*/
/*****************************************************************************
* input_EsOutNew:
*****************************************************************************/
es_out_t
*
input_EsOutNew
(
input_thread_t
*
p_input
)
{
es_out_t
*
out
=
malloc
(
sizeof
(
es_out_t
)
);
...
...
@@ -102,8 +130,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
p_sys
->
b_active
=
VLC_FALSE
;
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
->
es
=
NULL
;
...
...
@@ -124,12 +156,9 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
return
out
;
}
/**
* Deletes an es_out structure
*
* \param out the es_out structure to destroy
* \return nothing
*/
/*****************************************************************************
* input_EsOutDelete:
*****************************************************************************/
void
input_EsOutDelete
(
es_out_t
*
out
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
...
...
@@ -137,191 +166,249 @@ void input_EsOutDelete( es_out_t *out )
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
]
);
}
if
(
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
(
out
);
}
/**
* 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
)
es_out_id_t
*
input_EsOutGetFromID
(
es_out_t
*
out
,
int
i_id
)
{
input_thread_t
*
p_input
=
out
->
p_sys
->
p_input
;
pgrm_descriptor_t
*
p_pgrm
;
es_descriptor_t
*
p_pmt
;
/* FIXME we should use a object variable but a lot of place in src/input
* have to be changed */
int
i_select
=
config_GetInt
(
p_input
,
"program"
);
int
i
;
if
(
i_id
<
0
)
{
/* Special HACK, -i_id is tha cat of the stream */
return
(
es_out_id_t
*
)((
uint8_t
*
)
NULL
-
i_id
);
}
/* create it */
p_pgrm
=
input_AddProgram
(
p_input
,
i_group
,
0
);
for
(
i
=
0
;
i
<
out
->
p_sys
->
i_es
;
i
++
)
{
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
* 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
* the old ts demuxer */
p_pmt
=
input_AddES
(
p_input
,
p_pgrm
,
0
,
UNKNOWN_ES
,
NULL
,
0
);
p_pmt
->
i_fourcc
=
VLC_FOURCC
(
'n'
,
'u'
,
'l'
,
'l'
);
void
input_EsOutDiscontinuity
(
es_out_t
*
out
,
vlc_bool_t
b_audio
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
int
i
;
/* Select i_select or the first by default */
if
(
p_input
->
stream
.
p_selected_program
==
NULL
&&
(
i_select
<=
0
||
i_select
==
i_group
)
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
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
* \param b_force ...
* \return nothing
*/
static
void
EsOutSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_force
)
*****************************************************************************/
static
void
EsOutESVarUpdate
(
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
,
text
;
int
i_cat
=
es
->
p_es
->
i_cat
;
char
*
psz_var
;
if
(
!
p_sys
->
b_active
||
(
!
b_force
&&
es
->
p_es
->
fmt
.
i_priority
<
0
)
)
{
if
(
es
->
fmt
.
i_cat
==
AUDIO_ES
)
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
;
/* 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
)
{
input_SelectES
(
p_input
,
es
->
p_es
);
}
text
.
psz_string
=
strdup
(
es
->
psz_description
);
}
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
&&
es
->
p_es
->
p_pgrm
!=
p_input
->
stream
.
p_selected_program
)
{
return
;
}
val
.
i_int
=
es
->
i_id
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
if
(
i_cat
==
AUDIO_ES
)
{
if
(
p_sys
->
p_es_audio
&&
p_sys
->
p_es_audio
->
p_es
->
fmt
.
i_priority
>=
es
->
p_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
->
p_es
->
fmt
.
i_priority
>=
es
->
p_es
->
fmt
.
i_priority
)
{
return
;
}
i_wanted
=
p_sys
->
i_sub_last
;
}
else
if
(
i_cat
==
VIDEO_ES
)
{
i_wanted
=
es
->
i_channel
;
}
free
(
text
.
psz_string
);
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
}
/* EsOutProgramSelect:
* Select a program and update the object variable
*/
static
void
EsOutProgramSelect
(
es_out_t
*
out
,
es_out_pgrm_t
*
p_pgrm
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
vlc_value_t
val
;
int
i
;
if
(
p_sys
->
p_pgrm
==
p_pgrm
)
return
;
/* Nothing to do */
if
(
p_sys
->
p_pgrm
)
{
es_out_pgrm_t
*
old
=
p_sys
->
p_pgrm
;
msg_Dbg
(
p_input
,
"Unselecting program id=%d"
,
old
->
i_id
);
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 */
if
(
es
->
p_es
->
p_dec
)
msg_Dbg
(
p_input
,
"Selecting program id=%d"
,
p_pgrm
->
i_id
);
/* 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
)
{
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
&&
p_sys
->
p_es_audio
&&
p_sys
->
p_es_audio
->
p_es
->
p_dec
)
{
input_UnselectES
(
p_input
,
p_sys
->
p_es_audio
->
p_es
);
}
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_es
->
p_dec
)
{
input_UnselectES
(
p_input
,
p_sys
->
p_es_sub
->
p_es
);
}
p_sys
->
p_es_sub
=
es
;
}
else
if
(
i_cat
==
VIDEO_ES
)
{
p_sys
->
p_es_video
=
es
;
}
p_sys
->
p_pgrm
->
clock
.
b_master
=
VLC_FALSE
;
}
p_pgrm
->
clock
.
b_master
=
VLC_TRUE
;
p_sys
->
p_pgrm
=
p_pgrm
;
/* Update "program" */
val
.
i_int
=
p_pgrm
->
i_id
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* Update "es-*" */
var_Change
(
p_input
,
"audio-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
var_Change
(
p_input
,
"video-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
var_Change
(
p_input
,
"spu-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
EsOutESVarUpdate
(
out
,
p_sys
->
es
[
i
]
);
EsOutSelect
(
out
,
p_sys
->
es
[
i
],
VLC_FALSE
);
}
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
}
/* 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
;
}
/**
* 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
/* EsOutAdd:
* Add an es_out
*/
static
es_out_id_t
*
EsOutAdd
(
es_out_t
*
out
,
es_format_t
*
fmt
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
es_out_id_t
*
es
=
malloc
(
sizeof
(
es_out_id_t
)
);
pgrm_descriptor_t
*
p_pgrm
=
NULL
;
char
psz_cat
[
sizeof
(
_
(
"Stream "
)
)
+
10
];
char
*
psz_description
;
es_out_pgrm_t
*
p_pgrm
=
NULL
;
int
i
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
fmt
->
i_group
>=
0
)
if
(
fmt
->
i_group
<
0
)
{
/* search program */
p_pgrm
=
input_FindProgram
(
p_input
,
fmt
->
i_group
);
msg_Err
(
p_input
,
"invakud group number"
);
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
=
EsOutAddProgram
(
out
,
fmt
->
i_group
)
;
p_pgrm
=
p_sys
->
pgrm
[
i
];
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
);
es
->
p_es
=
input_AddES
(
p_input
,
p_pgrm
,
fmt
->
i_id
+
1
,
fmt
->
i_cat
,
psz_description
,
0
);
es
->
p_es
->
i_stream_id
=
fmt
->
i_id
;
es
->
p_es
->
i_fourcc
=
fmt
->
i_codec
;
/* Increase ref count for program */
p_pgrm
->
i_es
++
;
/* 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
)
{
case
AUDIO_ES
:
...
...
@@ -340,9 +427,14 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
es
->
i_channel
=
0
;
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 */
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
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 )
default:
break;
}
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
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
);
p_sys
->
i_id
++
;
/* always incremented */
...
...
@@ -438,6 +523,186 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
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
*
...
...
@@ -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
)
{
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
;
if
(
p_pgrm
==
NULL
)
{
p_pgrm
=
p_sys
->
p_input
->
stream
.
p_selected_program
;
}
es_out_pgrm_t
*
p_pgrm
=
es
->
p_pgrm
;
/* +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
=
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
=
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
=
out
->
p_sys
->
p_input
->
stream
.
control
.
i_rate
;
if
(
es
->
p_es
->
p_dec
&&
(
es
->
p_es
->
i_cat
!=
AUDIO_ES
||
!
p_sys
->
p_input
->
stream
.
control
.
b_mute
)
)
p_block
->
i_rate
=
p_input
->
i_rate
;
/* TODO handle 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_DecodeBlock
(
es
->
p_es
->
p_dec
,
p_block
);
input_DecoderDecode
(
es
->
p_dec
,
p_block
);
}
else
{
vlc_mutex_unlock
(
&
out
->
p_sys
->
p_input
->
stream
.
stream_lock
);
block_Release
(
p_block
);
}
...
...
@@ -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
;
/* 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
);
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
:
p_sys
->
i_audio
--
;
...
...
@@ -507,30 +779,10 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
break
;
}
/* We don't try to reselect */
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
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
(
es
->
psz_description
)
free
(
es
->
psz_description
);
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
;
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
es_format_Clean
(
&
es
->
fmt
);
free
(
es
);
}
...
...
@@ -554,42 +806,34 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
switch
(
i_query
)
{
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
*
);
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
);
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
return
es
->
p_es
->
p_dec
?
VLC_SUCCESS
:
VLC_EGENERIC
;
EsSelect
(
out
,
es
);
return
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
);
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
EsUnselect
(
out
,
es
,
es
->
p_pgrm
==
p_sys
->
p_pgrm
);
return
VLC_SUCCESS
;
}
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
case
ES_OUT_GET_ES_STATE
:
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_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
;
case
ES_OUT_SET_ACTIVE
:
{
b
=
(
vlc_bool_t
)
va_arg
(
args
,
vlc_bool_t
);
p_sys
->
b_active
=
b
;
/* Needed ? */
if
(
b
)
{
vlc_value_t
val
;
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_sys
->
p_input
,
"intf-change"
,
val
);
}
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
return
VLC_SUCCESS
;
}
...
...
@@ -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
||
i
==
ES_OUT_MODE_AUTO
)
{
vlc_value_t
val
;
p_sys
->
i_mode
=
i
;
/* Reapply policy mode */
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
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
++
)
{
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_EGENERIC
;
...
...
@@ -636,65 +872,119 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
case
ES_OUT_SET_ES
:
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
/* Special case NULL, NULL+i_cat */
if
(
es
==
NULL
)
{
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_es
->
p_dec
)
{
input_UnselectES
(
p_sys
->
p_input
,
p_sys
->
es
[
i
]
->
p_es
);
}
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
if
(
p_sys
->
es
[
i
]
->
p_dec
)
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
+
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
{
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
EsOutSelect
(
out
,
es
,
VLC_TRUE
);
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
if
(
es
==
p_sys
->
es
[
i
]
)
{
EsOutSelect
(
out
,
es
,
VLC_TRUE
);
break
;
}
}
}
return
VLC_SUCCESS
;
case
ES_OUT_SET_PCR
:
case
ES_OUT_SET_GROUP_PCR
:
{
pgrm_descriptor_t
*
p_pgrm
=
NULL
;
int64_t
i_pcr
;
es_out_pgrm_t
*
p_pgrm
=
NULL
;
int
i_group
=
0
;
int64_t
i_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
{
int
i
_group
=
(
int
)
va_arg
(
args
,
int
)
;
p_pgrm
=
input_FindProgram
(
p_sys
->
p_input
,
i_group
);
if
(
p_pgrm
==
NULL
)
int
i
;
i_group
=
(
int
)
va_arg
(
args
,
int
);
for
(
i
=
0
;
i
<
p_sys
->
i_pgrm
;
i
++
)
{
/* we create the requested program */
p_pgrm
=
EsOutAddProgram
(
out
,
i_group
);
if
(
p_sys
->
pgrm
[
i
]
->
i_id
==
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
);
/* search program */
if
(
p_pgrm
)
{
/* 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
;
}
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
=
SYNCHRO_REINIT
;
p_sys
->
p_input
->
stream
.
pp_programs
[
i
]
->
last_pts
=
0
;
p_sys
->
pgrm
[
i
]
->
clock
.
i_synchro_state
=
SYNCHRO_REINIT
;
p_sys
->
pgrm
[
i
]
->
clock
.
last_pts
=
0
;
}
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:
msg_Err
(
p_sys
->
p_input
,
"unknown query in es_out_Control"
);
return
VLC_EGENERIC
;
...
...
src/input/input.c
View file @
68d21786
/*****************************************************************************
* input.c: input thread
* Read a stream, demultiplex and parse it before sending it to
* decoders.
*****************************************************************************
* Copyright (C) 1998-2004 VideoLAN
* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by
...
...
@@ -33,64 +32,63 @@
#include <vlc/decoder.h>
#include <vlc/vout.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include "input_internal.h"
#include "stream_output.h"
#include "vlc_interface.h"
#include "codecs.h"
#include "vlc_meta.h"
#include "../../modules/demux/util/sub.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
struct
input_thread_sys_t
{
/* subtitles */
int
i_sub
;
subtitle_demux_t
**
sub
;
static
int
Run
(
input_thread_t
*
p_input
);
static
int
Init
(
input_thread_t
*
p_input
);
static
void
Error
(
input_thread_t
*
p_input
);
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
int
InitThread
(
input_thread_t
*
p_input
);
static
void
ErrorThread
(
input_thread_t
*
p_input
);
static
void
EndThread
(
input_thread_t
*
p_input
);
static
void
UpdateFromAccess
(
input_thread_t
*
);
static
void
UpdateFromDemux
(
input_thread_t
*
);
static
void
ParseOption
(
input_thread_t
*
p_input
,
const
char
*
psz_option
);
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
*****************************************************************************
* This function creates a new input, and returns a pointer
* 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_item_t
*
p_item
)
{
input_thread_t
*
p_input
;
/* thread descriptor */
vlc_value_t
val
;
int
i
;
/* Allocate descriptor */
...
...
@@ -101,8 +99,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
return
NULL
;
}
/* Store pointer to input item descriptor */
p_input
->
p_item
=
p_item
;
/* Init Common fields */
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 */
vlc_mutex_lock
(
&
p_item
->
lock
);
...
...
@@ -113,166 +143,15 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
}
vlc_mutex_unlock
(
&
p_item
->
lock
);
/* Create a few object variables we'll need later on */
var_Create
(
p_input
,
"video"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
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
);
/* Create Object Variables for private use only */
input_ConfigVarInit
(
p_input
);
/* Bookmarks */
var_Create
(
p_input
,
"bookmarks"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"bookmark"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
|
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
;
/* Create Objects variables for public Get and Set */
input_ControlVarInit
(
p_input
);
p_input
->
input
.
i_cr_average
=
var_GetInteger
(
p_input
,
"cr-average"
);
#if 0
/* TODO */
var_Get( p_input, "bookmarks", &val );
if( val.psz_string )
{
...
...
@@ -319,15 +198,18 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
}
free( val.psz_string );
}
#endif
/* Now we can attach our new input */
vlc_object_attach
(
p_input
,
p_parent
);
/* 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
)
)
{
msg_Err
(
p_input
,
"cannot create input thread"
);
free
(
p_input
);
vlc_object_detach
(
p_input
);
vlc_object_destroy
(
p_input
);
return
NULL
;
}
...
...
@@ -341,34 +223,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
*****************************************************************************/
void
input_StopThread
(
input_thread_t
*
p_input
)
{
demux_t
*
p_demux
;
access_t
*
p_access
;
vlc_list_t
*
p_list
;
int
i
;
/*
Make the thread exit from a possible vlc_cond_wait()
*/
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
)
;
/*
Set die for input
*/
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
*/
p_
demux
=
(
demux_t
*
)
vlc_object_find
(
p_input
,
VLC_OBJECT_DEMUX
,
FIND_CHILD
);
if
(
p_demux
)
/*
Set die for all access
*/
p_
list
=
vlc_list_find
(
p_input
,
VLC_OBJECT_ACCESS
,
FIND_CHILD
);
for
(
i
=
0
;
i
<
p_list
->
i_count
;
i
++
)
{
p_demux
->
b_die
=
1
;
vlc_object_release
(
p_demux
);
p_list
->
p_values
[
i
].
p_object
->
b_die
=
VLC_TRUE
;
}
vlc_list_release
(
p_list
);
/*
Temporary access2 hack
*/
p_
access
=
(
access_t
*
)
vlc_object_find
(
p_input
,
VLC_OBJECT_ACCESS
,
FIND_CHILD
);
if
(
p_access
)
/*
Set die for all stream
*/
p_
list
=
vlc_list_find
(
p_input
,
VLC_OBJECT_STREAM
,
FIND_CHILD
);
for
(
i
=
0
;
i
<
p_list
->
i_count
;
i
++
)
{
p_access
->
b_die
=
1
;
vlc_object_release
(
p_access
);
p_list
->
p_values
[
i
].
p_object
->
b_die
=
VLC_TRUE
;
}
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
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_DIE
,
NULL
);
}
/*****************************************************************************
...
...
@@ -381,106 +269,192 @@ void input_DestroyThread( input_thread_t *p_input )
/* Join the thread */
vlc_thread_join
(
p_input
);
/* Destroy Mutex locks */
vlc_mutex_destroy
(
&
p_input
->
stream
.
control
.
control_lock
);
vlc_cond_destroy
(
&
p_input
->
stream
.
stream_wait
);
vlc_mutex_destroy
(
&
p_input
->
stream
.
stream_lock
);
/* Delete input lock (only after thread joined) */
vlc_mutex_destroy
(
&
p_input
->
lock_control
);
/* 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.
*****************************************************************************/
static
int
Run
Thread
(
input_thread_t
*
p_input
)
static
int
Run
(
input_thread_t
*
p_input
)
{
vlc_value_t
val
;
mtime_t
i_update_next
=
-
1
;
int64_t
i_intf_update
=
0
;
/* Signal
right now, otherwise we'll get stuck in a peek
*/
/* Signal
that the thread is launched
*/
vlc_thread_ready
(
p_input
);
if
(
Init
Thread
(
p_input
)
)
if
(
Init
(
p_input
)
)
{
/* 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 */
p_input
->
b_dead
=
1
;
p_input
->
b_dead
=
VLC_TRUE
;
return
0
;
}
/* initialization is complete */
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
);
/* Main loop */
while
(
!
p_input
->
b_die
&&
!
p_input
->
b_error
&&
!
p_input
->
b_eof
)
{
unsigned
int
i
,
i_count
;
p_input
->
c_loops
++
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
vlc_bool_t
b_force_update
=
VLC_FALSE
;
int
i_ret
;
int
i_type
;
vlc_value_t
val
;
if
(
p_input
->
stream
.
p_new_program
)
/* Do the read */
if
(
p_input
->
i_state
!=
PAUSE_S
)
{
if
(
p_input
->
pf_set_program
!=
NULL
)
{
/* Reinitialize buffer manager. */
input_AccessReinit
(
p_input
);
p_input
->
pf_set_program
(
p_input
,
p_input
->
stream
.
p_new_program
);
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
i_ret
=
0
;
/* EOF */
/* Escape all decoders for the stream discontinuity they
* will encounter. */
input_EscapeDiscontinuity
(
p_input
);
if
(
i_ret
>
0
)
{
/* 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
=
p_input
->
stream
.
pp_programs
[
i
];
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
);
}
/* Reinitialize synchro. */
p_pgrm
->
i_synchro_state
=
SYNCHRO_REINIT
;
/* Seek to title 0 position 0(start) */
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
;
}
}
if
(
p_input
->
stream
.
p_new_area
)
else
{
if
(
p_input
->
stream
.
b_seekable
&&
p_input
->
pf_set_area
!=
NULL
)
{
input_AccessReinit
(
p_input
);
/* Small wait */
msleep
(
10
*
1000
);
}
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
* will encounter. */
input_EscapeDiscontinuity
(
p_input
);
if
(
b_force_update
||
i_intf_update
<
mdate
()
)
{
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
=
p_input
->
stream
.
pp_programs
[
i
];
/* TODO */
#if 0
char psz_buffer[MSTRTIME_MAX_SIZE];
/* Reinitialize synchro. */
p_pgrm
->
i_synchro_state
=
SYNCHRO_REINIT
;
vlc_mutex_lock( &p_input->p_item->lock );
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_size > 0 )
...
...
@@ -532,66 +506,10 @@ static int RunThread( input_thread_t *p_input )
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. */
i_count = p_input->pf_demux( p_input );
if
(
i_count
==
0
)
{
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
;
}
XXXXX
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 )
EndThread( p_input );
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
;
// float f_fps;
double
f_fps
;
mtime_t
i_length
;
/* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
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
;
char
*
psz_dup
=
strdup
(
p_input
->
input
.
p_item
->
psz_uri
);
char
*
psz_access
=
NULL
;
char
*
psz_demux
=
NULL
;
char
*
psz_path
=
NULL
;
char
*
psz
;
vlc_value_t
val
;
/* Skip the plug-in names */
while
(
*
psz_parser
&&
*
psz_parser
!=
':'
)
{
psz_parser
++
;
}
/* Open access/stream/demux */
psz
=
strchr
(
psz_dup
,
':'
);
#if defined( WIN32 ) || defined( UNDER_CE )
if
(
psz_parser
-
p_input
->
psz_dupsource
==
1
)
{
msg_Warn
(
p_input
,
"drive letter %c: found in source string"
,
p_input
->
psz_dupsource
[
0
]
)
;
psz_parser
=
""
;
}
#endif
if
(
!*
psz_parser
)
if
(
psz
-
psz_dup
==
1
)
{
p_input
->
psz_access
=
p_input
->
psz_demux
=
""
;
p_input
->
psz_name
=
p_input
->
psz_source
;
free
(
p_input
->
psz_dupsource
);
p_input
->
psz_dupsource
=
NULL
;
msg_Warn
(
p_input
,
"drive letter %c: found in source string"
,
psz_dup
[
0
]
);
}
else
#endif
if
(
psz
)
{
*
psz_parser
++
=
'\0'
;
/* let's skip '//' */
if
(
psz_parser
[
0
]
==
'/'
&&
psz_parser
[
1
]
==
'/'
)
{
psz_parser
+=
2
;
}
*
psz
++
=
'\0'
;
if
(
psz
[
0
]
==
'/'
&&
psz
[
1
]
==
'/'
)
psz
+=
2
;
p
_input
->
psz_name
=
psz_parser
;
p
sz_path
=
psz
;
/* Come back to parse the access and demux plug-ins */
psz_parser
=
p_input
->
psz_dupsource
;
if
(
!*
psz_parser
)
{
/* No access */
p_input
->
psz_access
=
""
;
}
else
if
(
*
psz_parser
==
'/'
)
{
/* No access */
p_input
->
psz_access
=
""
;
psz_parser
++
;
}
else
psz
=
strchr
(
psz_dup
,
'/'
);
if
(
psz
)
{
p_input
->
psz_access
=
psz_parser
;
while
(
*
psz_parser
&&
*
psz_parser
!=
'/'
)
{
psz_parser
++
;
}
if
(
*
psz_parser
==
'/'
)
{
*
psz_parser
++
=
'\0'
;
}
*
psz
++
=
'\0'
;
psz_demux
=
psz
;
}
if
(
!*
psz_parser
)
{
/* No demux */
p_input
->
psz_demux
=
""
;
}
else
{
p_input
->
psz_demux
=
psz_parser
;
}
psz_access
=
psz_dup
;
}
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
)
else
{
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
{
free
(
p_input
->
psz_dupsource
);
}
return
VLC_EGENERIC
;
psz_path
=
psz_dup
;
}
/* Initialize optional stream output. (before demuxer)*/
var_Get
(
p_input
,
"sout"
,
&
val
);
if
(
val
.
psz_string
!=
NULL
)
if
(
psz_access
==
NULL
)
psz_access
=
""
;
if
(
psz_demux
==
NULL
)
psz_demux
=
""
;
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
=
sout_NewInstance
(
p_input
,
val
.
psz_string
))
==
NULL
)
p_input
->
p_sout
=
sout_NewInstance
(
p_input
,
psz
);
if
(
p_input
->
p_sout
==
NULL
)
{
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
;
}
free
(
val
.
psz_string
);
}
free
(
psz
);
/* Create es out */
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_MODE
,
ES_OUT_MODE_NONE
);
/* Find and open appropriate access module */
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
p_input
->
psz_access
,
VLC_TRUE
);
/* Maybe we had an encoded url */
if
(
!
p_input
->
p_access
&&
strchr
(
p_input
->
psz_name
,
'%'
)
)
/* Try access_demux if no demux given */
if
(
*
psz_access
&&
*
psz_demux
==
'\0'
)
{
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
);
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
p_input
->
psz_access
,
VLC_TRUE
);
if
(
p_input
->
input
.
p_demux
)
{
/* 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
* are forbidden in filenames on Win32. */
* are forbidden in filenames on Win32. */
/* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
if
(
p_input
->
p_access
==
NULL
&&
(
*
p_input
->
psz_demux
||
*
p_input
->
psz_access
)
)
{
p_input
->
psz_access
=
p_input
->
psz_demux
=
""
;
p_input
->
psz_name
=
p_input
->
psz_source
;
free
(
p_input
->
psz_dupsource
);
p_input
->
psz_dupsource
=
NULL
;
/* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
if
(
p_input
->
input
.
p_access
==
NULL
&&
*
psz_access
==
'\0'
&&
(
*
psz_demux
||
*
psz_path
)
)
{
free
(
psz_dup
);
psz_dup
=
strdup
(
p_input
->
input
.
p_item
->
psz_uri
);
psz_access
=
""
;
psz_demux
=
""
;
psz_path
=
psz_dup
;
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
p_input
->
psz_access
,
VLC_TRUE
);
}
p_input
->
input
.
p_access
=
access2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
);
}
#endif
if
(
p_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
)
if
(
p_input
->
input
.
p_access
==
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
);
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
/* Get infos from access */
access2_Control
(
p_input
->
input
.
p_access
,
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. */
if
(
p_input
->
i_mtu
)
{
p_input
->
i_bufsize
=
p_input
->
i_mtu
;
/* Open a demuxer */
if
(
*
psz_demux
==
'\0'
&&
*
p_input
->
input
.
p_access
->
psz_demux
)
{
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
* cache more data. */
var_Create
(
p_input
,
"audio-desync"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_input
,
"audio-desync"
,
&
val
);
if
(
val
.
i_int
<
0
)
p_input
->
i_pts_delay
-=
(
val
.
i_int
*
1000
);
if
(
p_input
->
p_current_data
==
NULL
&&
p_input
->
pf_read
!=
NULL
)
{
while
(
!
input_FillBuffer
(
p_input
)
)
{
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
;
}
}
}
/* Init 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
->
sub
=
NULL
;
/* Create the stream_t facilities */
p_input
->
s
=
input_StreamNew
(
p_input
);
if
(
p_input
->
s
==
NULL
)
{
/* should never occur yet */
/* TODO: check meta data from users */
msg_Err
(
p_input
,
"cannot create stream_t"
);
/* TODO: get meta data from demuxer */
module_Unneed
(
p_input
,
p_input
->
p_access
);
if
(
p_input
->
stream
.
p_sout
!=
NULL
)
/* Init length */
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
);
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
else
{
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
)
{
msg_Err
(
p_input
,
"no suitable demux module for `%s/%s://%s'"
,
p_input
->
psz_access
,
p_input
->
psz_demux
,
p_input
->
psz_name
);
/* TODO: do subtitle loading */
input_StreamDelete
(
p_input
->
s
);
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
);
/* Set up es_out */
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_ACTIVE
,
VLC_TRUE
);
val
.
b_bool
=
VLC_FALSE
;
if
(
p_input
->
p_sout
)
{
var_Get
(
p_input
,
"sout-all"
,
&
val
);
}
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_MODE
,
val
.
b_bool
?
ES_OUT_MODE_ALL
:
ES_OUT_MODE_AUTO
);
/* 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
);
return
VLC_EGENERIC
;
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"
);
}
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 */
p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
p_input->p_sys->i_sub = 0;
p_input->p_sys->sub = NULL;
p_input
->
p_sys
->
i_stop_time
=
0
;
/* Get meta information from user */
var_Create( p_input, "meta-title", 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 )
vlc_value_t 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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
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 );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
}
/* Get meta informations from demuxer */
...
...
@@ -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 */
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 )
es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
p_sub_toselect->p_es, VLC_TRUE );
}
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
;
#endif
}
/*****************************************************************************
* Error
Thread
: RunThread() error loop
* Error: RunThread() error 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
)
{
...
...
@@ -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
;
#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
vlc_value_t
val
;
msg_Dbg
(
p_input
,
"closing `%s'"
,
p_input
->
input
.
p_item
->
psz_uri
);
/* DumpStream: printf some info for debugging purpose */
#define S p_input->stream
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
);
#undef S
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_pgrm_number
;
i
++
)
{
#define P p_input->stream.pp_programs[i]
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
}
}
/* We are at the end */
p_input
->
i_state
=
END_S
;
val
.
i_int
=
END_S
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* Clean control variables */
input_ControlVarClean
(
p_input
);
/* Free demultiplexer's data */
if
(
p_input
->
p_demux
)
module_Unneed
(
p_input
,
p_input
->
p_demux
);
/* Unload all modules */
if
(
p_input
->
input
.
p_demux
)
demux2_Delete
(
p_input
->
input
.
p_demux
);
/* Free all ES and destroy all decoder threads */
input_EndStream
(
p_input
);
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
);
/* Close optional stream output instance */
if
(
p_input
->
stream
.
p_sout
)
if
(
p_input
->
p_sout
)
{
vlc_object_t
*
p_pl
=
vlc_object_find
(
p_input
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
...
...
@@ -1252,20 +1198,20 @@ static void EndThread( input_thread_t * p_input )
{
/* attach sout to the playlist */
msg_Warn
(
p_input
,
"keeping sout"
);
vlc_object_detach
(
p_input
->
stream
.
p_sout
);
vlc_object_attach
(
p_input
->
stream
.
p_sout
,
p_pl
);
vlc_object_detach
(
p_input
->
p_sout
);
vlc_object_attach
(
p_input
->
p_sout
,
p_pl
);
}
else
{
msg_Warn
(
p_input
,
"destroying sout"
);
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
sout_DeleteInstance
(
p_input
->
p_sout
);
}
if
(
p_pl
)
{
vlc_object_release
(
p_pl
);
}
}
/* TODO subs */
#if 0
/* Destroy subtitles demuxers */
if( p_input->p_sys )
{
...
...
@@ -1278,30 +1224,471 @@ static void EndThread( input_thread_t * p_input )
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 */
if
(
p_input
->
s
)
input_StreamDelete
(
p_input
->
s
);
/* Tell we're dead */
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 */
if
(
p_input
->
p_access
)
module_Unneed
(
p_input
,
p_input
->
p_access
)
;
*
pi_type
=
p_input
->
control
[
0
].
i_type
;
*
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 */
msg_Dbg
(
p_input
,
"freeing info structures..."
);
for
(
i
=
0
;
i
<
p_input
->
i_control
;
i
++
)
{
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
)
;
if
(
p_input
->
psz_dupsource
!=
NULL
)
free
(
p_input
->
psz_dupsource
);
return
VLC_SUCCESS
;
}
/* Tell we're dead */
p_input
->
b_dead
=
1
;
static
void
ControlReduce
(
input_thread_t
*
p_input
)
{
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
*****************************************************************************/
...
...
@@ -1438,273 +1825,4 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
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 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "
ninput
.h"
#include "
input_internal
.h"
/****************************************************************************
* 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,
/* TODO:
* - tune the 2 methods
* - compute cost for seek
* - improve stream mode seeking with closest segments
* - ...
*/
/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
#define MAX_LINE 1024
char
*
stream_ReadLine
(
stream_t
*
s
)
/* Two methods:
* - 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
;
char
*
p_line
;
int
i_data
;
int
i
=
0
;
i_data
=
stream_Peek
(
s
,
&
p_data
,
MAX_LINE
);
int64_t
i_date
;
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
++
;
}
if
(
i_data
<=
0
)
int64_t
i_start
;
/* Offset of block for p_first */
int
i_offset
;
/* Offset for data in p_current */
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
;
}
else
int
i_offset
;
/* Buffer ofset in the current track */
int
i_tk
;
/* Current track */
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
);
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'
;
vlc_bool_t
b_fastseek
;
/* From access */
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
* when we would have a access wrapper, and stream filter
* (like caching, progessive, gunzip, ... )
*/
/* Method 2 */
static
int
AStreamReadStream
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
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* */
typedef
struct
{
input_thread_t
*
p_input
;
}
input_stream_sys_t
;
/* Common */
static
int
AStreamControl
(
stream_t
*
,
int
i_query
,
va_list
);
/* 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
)
);
input_stream_sys_t
*
p_sys
;
if
(
s
)
stream_t
*
s
=
vlc_object_create
(
p_access
,
VLC_OBJECT_STREAM
);
stream_sys_t
*
p_sys
;
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
;
s
->
pf_read
=
IStreamRead
;
s
->
pf_peek
=
IStreamPeek
;
s
->
pf_control
=
IStreamControl
;
int
i
;
s
->
pf_read
=
AStreamReadStream
;
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
)
);
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
p_sys
->
p_input
=
p_input
;
if
(
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_end
<=
0
)
{
msg_Err
(
s
,
"cannot pre fill buffer"
);
goto
error
;
}
}
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
);
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
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
vlc_bool_t
*
p_b
;
int64_t
*
p
_i64
,
i
64
;
int
*
p
_int
;
vlc_bool_t
*
p_b
ool
;
int64_t
*
p
i_64
,
i_
64
;
int
i
_int
;
switch
(
i_query
)
{
case
STREAM_GET_SIZE
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
*
p_i64
=
p_input
->
stream
.
p_selected_area
->
i_size
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
p_access
->
info
.
i_size
;
break
;
case
STREAM_CAN_SEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
*
p_b
=
p_input
->
stream
.
b_seekable
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
p_bool
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
p_bool
);
break
;
case
STREAM_CAN_FASTSEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
*
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
;
p_bool
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
access2_Control
(
p_access
,
ACCESS_CAN_FASTSEEK
,
p_bool
);
break
;
case
STREAM_GET_POSITION
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
*
p_i64
=
p_input
->
stream
.
p_selected_area
->
i_tell
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
p_sys
->
i_pos
;
break
;
case
STREAM_SET_POSITION
:
{
int64_t
i_skip
;
i64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
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
;
}
i_64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
if
(
p_sys
->
b_block
)
return
AStreamSeekBlock
(
s
,
i_64
);
else
return
AStreamSeekStream
(
s
,
i_64
);
case
STREAM_GET_MTU
:
p_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
p_int
=
p_input
->
i_mtu
;
return
VLC_SUCCESS
;
return
VLC_EGENERIC
;
case
STREAM_CONTROL_ACCESS
:
{
int
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_int
=
(
int
)
va_arg
(
args
,
int
);
if
(
i_int
!=
ACCESS_SET_PRIVATE_ID_STATE
)
{
msg_Err
(
s
,
"Hey, what are you thinking ?"
"DON'T USE STREAM_CONTROL_ACCESS !!!"
);
return
VLC_EGENERIC
;
}
if
(
p_input
->
pf_access_control
)
{
return
p_input
->
pf_access_control
(
p_input
,
i_int
,
args
);
}
return
VLC_EGENERIC
;
}
return
access2_Control
(
p_access
,
i_int
,
args
);
default:
msg_Err
(
s
,
"invalid stream_vaControl query=0x%x"
,
i_query
);
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
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
uint8_t
*
p
=
(
uint8_t
*
)
p_data
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
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
;
if
(
stream_Control
(
s
,
STREAM_SET_POSITION
,
i_pos
)
)
/* Fetch a block */
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 */
i_count
=
input_FillBuffer
(
p_input
);
memcpy
(
p_data
,
&
p_sys
->
block
.
p_current
->
p_buffer
[
p_sys
->
block
.
i_offset
],
i_copy
);
p_data
+=
i_copy
;
}
i_data
+=
i_copy
;
if
(
i_count
<
0
)
return
-
1
;
else
if
(
i_count
==
0
)
p_sys
->
block
.
i_offset
+=
i_copy
;
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
;
}
}
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
;
}
/****************************************************************************
* IStreamPeek:
****************************************************************************/
static
int
IStreamPeek
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_peek
)
static
int
AStreamPeekBlock
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_read
)
{
input_stream_sys_t
*
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
return
input_Peek
(
p_sys
->
p_input
,
pp_peek
,
i_peek
);
stream_sys_t
*
p_sys
=
s
->
p_sys
;
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
;
}
/****************************************************************************
* stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
****************************************************************************/
typedef
struct
static
int
AStreamSeekBlock
(
stream_t
*
s
,
int64_t
i_pos
)
{
/* Data buffer */
vlc_mutex_t
lock
;
int
i_buffer
;
int
i_buffer_size
;
uint8_t
*
p_buffer
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
int64_t
i_offset
=
i_pos
-
p_sys
->
block
.
i_start
;
vlc_bool_t
b_seek
;
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 */
char
*
psz_name
;
es_out_t
*
out
;
demux_t
*
p_demux
;
}
d_stream_sys_t
;
while
(
i_current
+
b
->
i_buffer
<
i_offset
)
{
i_current
+=
b
->
i_buffer
;
b
=
b
->
p_next
;
}
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
*
);
p_sys
->
block
.
p_current
=
b
;
p_sys
->
block
.
i_offset
=
i_offset
-
i_current
;
p_sys
->
i_pos
=
i_pos
;
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
;
return
VLC_SUCCESS
;
}
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
)
);
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
;
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_aseek
);
access2_Control
(
p_access
,
ACCESS_CAN_FASTSEEK
,
&
b_aseekfast
);
if
(
!
b_aseek
)
{
b_seek
=
VLC_FALSE
;
msg_Warn
(
s
,
"%lld bytes need to be skipped (access non seekable)"
,
i_offset
-
p_sys
->
block
.
i_size
);
}
else
{
int64_t
i_skip
=
i_offset
-
p_sys
->
block
.
i_size
;
/* Avg bytes per packets */
int
i_avg
=
p_sys
->
stat
.
i_bytes
/
p_sys
->
stat
.
i_read_count
;
/* TODO compute a seek cost instead of fixed threshold */
int
i_th
=
b_aseekfast
?
1
:
5
;
if
(
i_skip
<=
i_th
*
i_avg
&&
i_skip
<
STREAM_CACHE_SIZE
)
b_seek
=
VLC_FALSE
;
else
b_seek
=
VLC_TRUE
;
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
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
/* Release data */
block_ChainRelease
(
p_sys
->
block
.
p_first
);
/* 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
);
/* Realloc if needed */
if
(
p_sys
->
i_buffer
+
p_block
->
i_buffer
>
p_sys
->
i_buffer_size
)
/* Read enought data */
while
(
p_sys
->
block
.
i_start
+
p_sys
->
block
.
i_size
<
i_pos
)
{
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
);
msg_Err
(
s
,
"stream_DemuxSend: buffer size > 5000000"
);
block_Release
(
p_block
);
return
;
p_sys
->
i_pos
+=
p_sys
->
block
.
p_current
->
i_buffer
;
p_sys
->
block
.
p_current
=
p_sys
->
block
.
p_current
->
p_next
;
}
/* 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
;
p_sys
->
block
.
i_offset
=
i_pos
-
p_sys
->
i_pos
;
p_sys
->
i_pos
=
i_pos
;
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
);
if
(
p_sys
->
p_demux
)
block_Release
(
b
);
}
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
);
free
(
p_sys
->
psz_name
);
free
(
p_sys
->
p_buffer
);
free
(
p_sys
);
vlc_object_destroy
(
s
);
i_stop
=
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
;
/* 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
;
int
i_copy
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
]
;
//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
);
}
uint8_t
*
p_data
=
(
uint8_t
*
)
p_read
;
int
i_data
=
0
;
//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
);
if
(
i_copy
>
0
)
/*msg_Dbg( s, "AStreamReadStream: %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 );*/
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
;
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
;
int
i_copy
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
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 );
for
(
;;
)
if
(
tk
->
i_start
>=
tk
->
i_end
)
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
);
//msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
if
(
p_sys
->
i_buffer
>=
i_peek
||
s
->
b_die
)
{
if
(
AStreamRefillStream
(
s
)
)
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
;
int64_t
*
p_i64
;
vlc_bool_t
*
p_b
;
int
*
p_int
;
switch
(
i_query
)
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
vlc_bool_t
b_aseek
;
vlc_bool_t
b_afastseek
;
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
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
p_i64
=
0
;
return
VLC_SUCCESS
;
//msg_Dbg( s, "AStreamSeekStream: current track" );
p_sys
->
i_pos
=
i_pos
;
p_sys
->
stream
.
i_offset
=
i_pos
-
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_start
;
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
;
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_aseek
);
if
(
!
b_aseek
)
{
/* We can't do nothing */
return
VLC_EGENERIC
;
}
case
STREAM_CAN_FASTSEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
*
p_b
=
VLC_FALSE
;
return
VLC_SUCCESS
;
/* Date the current track */
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_date
=
mdate
();
case
STREAM_GET_POSITION
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
p_i64
=
p_sys
->
i_pos
;
return
VLC_SUCCESS
;
/* Try to reuse already read data */
for
(
i
=
0
;
i
<
STREAM_CACHE_TRACK
;
i
++
)
{
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
i
]
;
case
STREAM_SET_POSITION
:
return
VLC_EGENERIC
;
if
(
i_pos
>=
tk
->
i_start
&&
i_pos
<=
tk
->
i_end
)
{
/*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
;
}
}
default:
msg_Err
(
s
,
"invalid DStreamControl query=0x%x"
,
i_query
);
return
VLC_EGENERIC
;
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_afastseek
);
/* FIXME compute seek cost (instead of static 'stupid' value) */
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
;
demux_t
*
p_demux
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
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
);
p_sys
->
p_demux
=
p_demux
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
int64_t
i_first
=
0
;
int64_t
i_start
;
/* Main loop */
while
(
!
s
->
b_die
&&
!
p_demux
->
b_die
)
msg_Dbg
(
s
,
"pre buffering"
);
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
;
}
/* */
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 @@
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "ninput.h"
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#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