Commit d0bf23fa authored by Christophe Massiot's avatar Christophe Massiot

Input III (Episode 1).

- Major rewrite of the buffer core functions
- Modularity of access plugins (file, udp, http)
- Modularity of network stack (ipv4, soon ipv6)
- Autodetection of the type of stream

And a new killing feature : HTTP streams are now seekable.

Please note that dvd, dvdread and vcd plug-ins are broken and thus disabled.
parent eba980c2
......@@ -15,6 +15,7 @@ endif
#
PLUGINS_DIR := ac3_adec \
ac3_spdif \
access \
alsa \
arts \
beos \
......@@ -57,6 +58,9 @@ PLUGINS_DIR := ac3_adec \
PLUGINS_TARGETS := ac3_adec/ac3_adec \
ac3_spdif/ac3_spdif \
access/file \
access/udp \
access/http \
alsa/alsa \
arts/arts \
beos/beos \
......@@ -119,6 +123,7 @@ PLUGINS_TARGETS := ac3_adec/ac3_adec \
mpeg_system/mpeg_ts \
mpeg_adec/mpeg_adec \
mpeg_vdec/mpeg_vdec \
network/ipv4 \
qnx/qnx \
qt/qt \
sdl/sdl \
......@@ -136,7 +141,7 @@ PLUGINS_TARGETS := ac3_adec/ac3_adec \
# C Objects
#
INTERFACE := main interface intf_msg intf_playlist intf_eject
INPUT := input input_ext-dec input_ext-intf input_dec input_programs input_clock mpeg_system
INPUT := input input_ext-plugins input_ext-dec input_ext-intf input_dec input_programs input_clock mpeg_system
VIDEO_OUTPUT := video_output video_text vout_pictures vout_subpictures
AUDIO_OUTPUT := audio_output aout_ext-dec aout_pcm aout_spdif
MISC := mtime modules configuration netutils iso_lang
......
......@@ -5399,7 +5399,7 @@ case x"${target_cpu}" in
;;
esac
BUILTINS="${BUILTINS} mpeg_es mpeg_ps mpeg_ts memcpy idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
BUILTINS="${BUILTINS} mpeg_es mpeg_ps mpeg_ts file udp http ipv4 memcpy idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
PLUGINS="${PLUGINS} lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
MMX_MODULES="memcpymmx idctmmx motionmmx chroma_i420_rgb_mmx chroma_i420_yuy2_mmx chroma_i422_yuy2_mmx chroma_i420_ymga_mmx"
......@@ -6387,7 +6387,7 @@ if test "${with_dvdcss+set}" = set; then
case "x${withval}" in
xlocal-static|xyes)
# local libdvdcss, statically linked
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -6398,7 +6398,7 @@ if test "${with_dvdcss+set}" = set; then
;;
xlocal-shared)
# local libdvdcss, dynamically linked
PLUGINS="${PLUGINS} dvd"
#PLUGINS="${PLUGINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -6408,7 +6408,7 @@ if test "${with_dvdcss+set}" = set; then
;;
xno)
# don't use libdvdcss at all, build a DVD module that can dlopen() it
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -6417,7 +6417,7 @@ if test "${with_dvdcss+set}" = set; then
;;
*)
# existing libdvdcss
PLUGINS="${PLUGINS} dvd"
#PLUGINS="${PLUGINS} dvd"
if test "x$withval" != "xyes"
then
LIB_DVD="${LIB_DVD} -L"$withval"/lib"
......@@ -6430,14 +6430,14 @@ else
# if libdvdcss is in the archive, or to use the dummy replacement otherwise.
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
NEED_LIBDVDCSS=1
STATIC_LIBDVDCSS=1
CFLAGS_DVD="${CFLAGS_DVD} -I../../extras/libdvdcss"
LIB_DVD="${LIB_DVD} lib/libdvdcss.a ${LIB_LIBDVDCSS}"
else
# XXX: no check for libdl is done, don't try this at home !
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -6467,11 +6467,11 @@ if test "${with_dvdread+set}" = set; then
x)
if test x${STATIC_LIBDVDREAD} = x1
then
BUILTINS="${BUILTINS} dvdread"
#BUILTINS="${BUILTINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} ${CFLAGS_DVD} -I../../extras/libdvdread"
LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a ${LIB_DVD}"
else
PLUGINS="${PLUGINS} dvdread"
#PLUGINS="${PLUGINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread ${CFLAGS_DVD}"
LIB_DVDREAD="${LIB_DVDREAD} -Llib -ldvdread ${LIB_DVD}"
fi
......@@ -6489,7 +6489,7 @@ if test "${with_dvdread+set}" = set; then
then
{ echo "configure: error: Can't link shared dvdread with static dvdcss" 1>&2; exit 1; }
else
PLUGINS="${PLUGINS} dvdread"
#PLUGINS="${PLUGINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} ${CFLAGS_DVD}"
LIB_DVDREAD="${LIB_DVDREAD} -ldvdread ${LIB_DVD}"
fi
......@@ -6521,7 +6521,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "cdrom_msf0" >/dev/null 2>&1; then
rm -rf conftest*
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
fi
rm -f conftest*
......@@ -6530,12 +6530,13 @@ fi
if test x$enable_vcd != xno -a "${SYS}" = "bsdi"
then
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
true #delete me
fi
if test x$enable_vcd != xno -a "${SYS}" = "darwin"
then
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
LIB_VCD="${LIB_VCD} -framework IOKit"
fi
......@@ -6605,17 +6606,17 @@ if test "${with_mad+set}" = set; then
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:6609: checking for $ac_hdr" >&5
echo "configure:6610: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 6614 "configure"
#line 6615 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:6619: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:6620: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -6645,7 +6646,7 @@ fi
done
echo $ac_n "checking for mad_bit_init in -lmad""... $ac_c" 1>&6
echo "configure:6649: checking for mad_bit_init in -lmad" >&5
echo "configure:6650: checking for mad_bit_init in -lmad" >&5
ac_lib_var=`echo mad'_'mad_bit_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -6653,7 +6654,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lmad $LIBS"
cat > conftest.$ac_ext <<EOF
#line 6657 "configure"
#line 6658 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
......@@ -6664,7 +6665,7 @@ int main() {
mad_bit_init()
; return 0; }
EOF
if { (eval echo configure:6668: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:6669: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
......@@ -6721,17 +6722,17 @@ then
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:6725: checking for $ac_hdr" >&5
echo "configure:6726: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 6730 "configure"
#line 6731 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:6735: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:6736: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -6754,7 +6755,7 @@ EOF
PLUGINS="${PLUGINS} dsp"
echo $ac_n "checking for main in -lossaudio""... $ac_c" 1>&6
echo "configure:6758: checking for main in -lossaudio" >&5
echo "configure:6759: checking for main in -lossaudio" >&5
ac_lib_var=`echo ossaudio'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -6762,14 +6763,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lossaudio $LIBS"
cat > conftest.$ac_ext <<EOF
#line 6766 "configure"
#line 6767 "configure"
#include "confdefs.h"
int main() {
main()
; return 0; }
EOF
if { (eval echo configure:6773: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:6774: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
......@@ -6805,7 +6806,7 @@ if test "${enable_esd+set}" = set; then
# Extract the first word of "esd-config", so it can be a program name with args.
set dummy esd-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:6809: checking for $ac_word" >&5
echo "configure:6810: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_ESD_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -6856,7 +6857,7 @@ if test "${enable_arts+set}" = set; then
# Extract the first word of "artsc-config", so it can be a program name with args.
set dummy artsc-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:6860: checking for $ac_word" >&5
echo "configure:6861: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_ARTS_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -6914,17 +6915,17 @@ else
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:6918: checking for $ac_hdr" >&5
echo "configure:6919: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 6923 "configure"
#line 6924 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:6928: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:6929: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -6969,17 +6970,17 @@ fi
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:6973: checking for $ac_hdr" >&5
echo "configure:6974: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 6978 "configure"
#line 6979 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:6983: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:6984: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7022,17 +7023,17 @@ if test "x$enableval" != "xno" -a x$SYS != xmingw32
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7026: checking for $ac_hdr" >&5
echo "configure:7027: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7031 "configure"
#line 7032 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7036: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7037: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7120,7 +7121,7 @@ fi
# Extract the first word of "sdl12-config", so it can be a program name with args.
set dummy sdl12-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7124: checking for $ac_word" >&5
echo "configure:7125: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL12_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7160,7 +7161,7 @@ fi
# Extract the first word of "sdl11-config", so it can be a program name with args.
set dummy sdl11-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7164: checking for $ac_word" >&5
echo "configure:7165: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL11_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7201,7 +7202,7 @@ fi
# Extract the first word of "sdl-config", so it can be a program name with args.
set dummy sdl-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7205: checking for $ac_word" >&5
echo "configure:7206: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_SDL_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7247,17 +7248,17 @@ fi
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7251: checking for $ac_hdr" >&5
echo "configure:7252: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7256 "configure"
#line 7257 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7261: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7262: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7327,17 +7328,17 @@ fi
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7331: checking for $ac_hdr" >&5
echo "configure:7332: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7336 "configure"
#line 7337 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7341: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7342: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7366,7 +7367,7 @@ done
else
echo $ac_n "checking for directX headers in ${withval}""... $ac_c" 1>&6
echo "configure:7370: checking for directX headers in ${withval}" >&5
echo "configure:7371: checking for directX headers in ${withval}" >&5
if test -f ${withval}/ddraw.h
then
PLUGINS="${PLUGINS} directx"
......@@ -7475,7 +7476,7 @@ if test "${enable_gnome+set}" = set; then
# Extract the first word of "gnome-config", so it can be a program name with args.
set dummy gnome-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7479: checking for $ac_word" >&5
echo "configure:7480: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GNOME_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7520,17 +7521,17 @@ fi
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7524: checking for $ac_hdr" >&5
echo "configure:7525: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7529 "configure"
#line 7530 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7534: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7535: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7590,7 +7591,7 @@ fi
# Extract the first word of "gtk12-config", so it can be a program name with args.
set dummy gtk12-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7594: checking for $ac_word" >&5
echo "configure:7595: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GTK12_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7629,7 +7630,7 @@ fi
# Extract the first word of "gtk-config", so it can be a program name with args.
set dummy gtk-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:7633: checking for $ac_word" >&5
echo "configure:7634: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -7679,17 +7680,17 @@ fi
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7683: checking for $ac_hdr" >&5
echo "configure:7684: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7688 "configure"
#line 7689 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7693: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7694: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7747,17 +7748,17 @@ if test x$enable_x11 != xno &&
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7751: checking for $ac_hdr" >&5
echo "configure:7752: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7756 "configure"
#line 7757 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7761: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7762: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7810,17 +7811,17 @@ if test x$enable_xvideo != xno &&
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:7814: checking for $ac_hdr" >&5
echo "configure:7815: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7819 "configure"
#line 7820 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7824: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7825: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7844,7 +7845,7 @@ EOF
saved_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -L$x_libraries -lX11 -lXext"
echo $ac_n "checking for XvSetPortAttribute in -lXv_pic""... $ac_c" 1>&6
echo "configure:7848: checking for XvSetPortAttribute in -lXv_pic" >&5
echo "configure:7849: checking for XvSetPortAttribute in -lXv_pic" >&5
ac_lib_var=`echo Xv_pic'_'XvSetPortAttribute | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -7852,7 +7853,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lXv_pic $LIBS"
cat > conftest.$ac_ext <<EOF
#line 7856 "configure"
#line 7857 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
......@@ -7863,7 +7864,7 @@ int main() {
XvSetPortAttribute()
; return 0; }
EOF
if { (eval echo configure:7867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:7868: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
......@@ -7910,17 +7911,17 @@ if test x$enable_lirc = xyes
then
ac_safe=`echo "lirc/lirc_client.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for lirc/lirc_client.h""... $ac_c" 1>&6
echo "configure:7914: checking for lirc/lirc_client.h" >&5
echo "configure:7915: checking for lirc/lirc_client.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 7919 "configure"
#line 7920 "configure"
#include "confdefs.h"
#include <lirc/lirc_client.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:7924: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:7925: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -7937,7 +7938,7 @@ fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
echo $ac_n "checking for lirc_init in -llirc_client""... $ac_c" 1>&6
echo "configure:7941: checking for lirc_init in -llirc_client" >&5
echo "configure:7942: checking for lirc_init in -llirc_client" >&5
ac_lib_var=`echo lirc_client'_'lirc_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -7945,7 +7946,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-llirc_client $LIBS"
cat > conftest.$ac_ext <<EOF
#line 7949 "configure"
#line 7950 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
......@@ -7956,7 +7957,7 @@ int main() {
lirc_init()
; return 0; }
EOF
if { (eval echo configure:7960: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:7961: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
......@@ -7996,17 +7997,17 @@ if test "${enable_alsa+set}" = set; then
then
ac_safe=`echo "alsa/asoundlib.h" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for alsa/asoundlib.h""... $ac_c" 1>&6
echo "configure:8000: checking for alsa/asoundlib.h" >&5
echo "configure:8001: checking for alsa/asoundlib.h" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 8005 "configure"
#line 8006 "configure"
#include "confdefs.h"
#include <alsa/asoundlib.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:8010: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:8011: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -8023,7 +8024,7 @@ fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
echo $ac_n "checking for main in -lasound""... $ac_c" 1>&6
echo "configure:8027: checking for main in -lasound" >&5
echo "configure:8028: checking for main in -lasound" >&5
ac_lib_var=`echo asound'_'main | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -8031,14 +8032,14 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lasound $LIBS"
cat > conftest.$ac_ext <<EOF
#line 8035 "configure"
#line 8036 "configure"
#include "confdefs.h"
int main() {
main()
; return 0; }
EOF
if { (eval echo configure:8042: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:8043: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
......
......@@ -443,7 +443,7 @@ esac
dnl
dnl default modules
dnl
BUILTINS="${BUILTINS} mpeg_es mpeg_ps mpeg_ts memcpy idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
BUILTINS="${BUILTINS} mpeg_es mpeg_ps mpeg_ts file udp http ipv4 memcpy idct idctclassic motion imdct downmix chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga mpeg_adec ac3_adec mpeg_vdec"
PLUGINS="${PLUGINS} lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort fx_scope"
dnl
......@@ -788,7 +788,7 @@ AC_ARG_WITH(dvdcss,
[ case "x${withval}" in
xlocal-static|xyes)
# local libdvdcss, statically linked
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -799,7 +799,7 @@ AC_ARG_WITH(dvdcss,
;;
xlocal-shared)
# local libdvdcss, dynamically linked
PLUGINS="${PLUGINS} dvd"
#PLUGINS="${PLUGINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -809,7 +809,7 @@ AC_ARG_WITH(dvdcss,
;;
xno)
# don't use libdvdcss at all, build a DVD module that can dlopen() it
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -818,7 +818,7 @@ AC_ARG_WITH(dvdcss,
;;
*)
# existing libdvdcss
PLUGINS="${PLUGINS} dvd"
#PLUGINS="${PLUGINS} dvd"
if test "x$withval" != "xyes"
then
LIB_DVD="${LIB_DVD} -L"$withval"/lib"
......@@ -830,14 +830,14 @@ AC_ARG_WITH(dvdcss,
# if libdvdcss is in the archive, or to use the dummy replacement otherwise.
[ if test x${CAN_BUILD_LIBDVDCSS} = x1
then
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
NEED_LIBDVDCSS=1
STATIC_LIBDVDCSS=1
CFLAGS_DVD="${CFLAGS_DVD} -I../../extras/libdvdcss"
LIB_DVD="${LIB_DVD} lib/libdvdcss.a ${LIB_LIBDVDCSS}"
else
# XXX: no check for libdl is done, don't try this at home !
BUILTINS="${BUILTINS} dvd"
#BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -868,11 +868,11 @@ AC_ARG_WITH(dvdread,
x)
if test x${STATIC_LIBDVDREAD} = x1
then
BUILTINS="${BUILTINS} dvdread"
#BUILTINS="${BUILTINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} ${CFLAGS_DVD} -I../../extras/libdvdread"
LIB_DVDREAD="${LIB_DVDREAD} lib/libdvdread.a ${LIB_DVD}"
else
PLUGINS="${PLUGINS} dvdread"
#PLUGINS="${PLUGINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} -I../../extras/libdvdread ${CFLAGS_DVD}"
LIB_DVDREAD="${LIB_DVDREAD} -Llib -ldvdread ${LIB_DVD}"
fi
......@@ -890,7 +890,7 @@ AC_ARG_WITH(dvdread,
then
AC_MSG_ERROR([Can't link shared dvdread with static dvdcss])
else
PLUGINS="${PLUGINS} dvdread"
#PLUGINS="${PLUGINS} dvdread"
CFLAGS_DVDREAD="${CFLAGS_DVDREAD} ${CFLAGS_DVD}"
LIB_DVDREAD="${LIB_DVDREAD} -ldvdread ${LIB_DVD}"
fi
......@@ -911,18 +911,19 @@ AC_ARG_ENABLE(vcd,
if test x$enable_vcd != xno
then
AC_EGREP_HEADER(cdrom_msf0,linux/cdrom.h,[
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
])
fi
if test x$enable_vcd != xno -a "${SYS}" = "bsdi"
then
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
true #delete me
fi
if test x$enable_vcd != xno -a "${SYS}" = "darwin"
then
BUILTINS="${BUILTINS} vcd"
#BUILTINS="${BUILTINS} vcd"
LIB_VCD="${LIB_VCD} -framework IOKit"
fi
......
......@@ -3,7 +3,7 @@
* Collection of useful common types and macros definitions
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: common.h,v 1.79 2002/02/27 03:47:56 sam Exp $
* $Id: common.h,v 1.80 2002/03/01 00:33:17 massiot Exp $
*
* Authors: Samuel Hocevar <sam@via.ecp.fr>
* Vincent Seguin <seguin@via.ecp.fr>
......@@ -171,6 +171,8 @@ struct pgrm_descriptor_s;
struct pes_packet_s;
struct input_area_s;
struct bit_stream_s;
struct input_buffers_s;
struct network_socket_s;
struct intf_subscription_s;
/*****************************************************************************
......@@ -537,10 +539,31 @@ typedef struct module_symbols_s
struct data_packet_s *,
struct es_descriptor_s *,
boolean_t, boolean_t );
int ( * input_ClockManageControl ) ( struct input_thread_s *,
struct pgrm_descriptor_s *,
mtime_t );
void ( * input_FDSeek ) ( struct input_thread_s *, off_t );
void ( * input_FDClose ) ( struct input_thread_s * );
ssize_t ( * input_FDRead ) ( struct input_thread_s *, byte_t *,
size_t );
ssize_t ( * input_FDNetworkRead ) ( struct input_thread_s *, byte_t *,
size_t );
void * ( * input_BuffersInit )( void );
void ( * input_BuffersEnd )( struct input_buffers_s * );
struct data_buffer_s * ( * input_NewBuffer )( struct input_buffers_s *, size_t );
void ( * input_ReleaseBuffer )( struct input_buffers_s *, struct data_buffer_s * );
struct data_packet_s * ( * input_ShareBuffer )( struct input_buffers_s *,
struct data_buffer_s * );
struct data_packet_s * ( * input_NewPacket )( struct input_buffers_s *, size_t );
void ( * input_DeletePacket )( struct input_buffers_s *, struct data_packet_s * );
struct pes_packet_s * ( * input_NewPES )( struct input_buffers_s * );
void ( * input_DeletePES )( struct input_buffers_s *, struct pes_packet_s * );
ssize_t ( * input_FillBuffer )( struct input_thread_s * );
ssize_t ( * input_Peek )( struct input_thread_s *, byte_t **, size_t );
ssize_t ( * input_SplitBuffer )( struct input_thread_s *, struct data_packet_s **, size_t );
int ( * input_AccessInit )( struct input_thread_s * );
void ( * input_AccessReinit )( struct input_thread_s * );
void ( * input_AccessEnd )( struct input_thread_s * );
struct aout_fifo_s * ( * aout_CreateFifo ) ( int, int, int, int, void * );
void ( * aout_DestroyFifo ) ( struct aout_fifo_s * );
......
......@@ -2,7 +2,7 @@
* input_ext-dec.h: structures exported to the VideoLAN decoders
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input_ext-dec.h,v 1.52 2002/01/21 23:57:46 massiot Exp $
* $Id: input_ext-dec.h,v 1.53 2002/03/01 00:33:17 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Kaempf <maxx@via.ecp.fr>
......@@ -40,25 +40,21 @@
*****************************************************************************
* Describe a data packet.
*****************************************************************************/
#define DATA_PACKET \
/* start of the PS or TS packet */ \
byte_t * p_demux_start; \
/* start of the PES payload in this packet */ \
byte_t * p_payload_start; \
byte_t * p_payload_end; /* guess ? :-) */ \
/* is the packet messed up ? */ \
boolean_t b_discard_payload;
typedef struct data_packet_s
{
/* Used to chain the packets that carry data for a same PES or PSI */
struct data_packet_s * p_next;
DATA_PACKET
/* start of the PS or TS packet */
byte_t * p_demux_start;
/* start of the PES payload in this packet */
byte_t * p_payload_start;
byte_t * p_payload_end; /* guess ? :-) */
/* is the packet messed up ? */
boolean_t b_discard_payload;
/* Please note that at least one buffer allocator (in particular, the
* Next Generation Buffer Allocator) extends this structure with
* private data after DATA_PACKET. */
/* pointer to the real data */
struct data_buffer_s * p_buffer;
} data_packet_t;
/*****************************************************************************
......@@ -113,10 +109,8 @@ typedef struct decoder_fifo_s
/* Communication interface between input and decoders */
boolean_t b_die; /* the decoder should return now */
boolean_t b_error; /* the decoder is in an error loop */
void * p_packets_mgt; /* packets management services
* data (netlist...) */
void (* pf_delete_pes)( void *, pes_packet_t * );
/* function to use when releasing a PES */
struct input_buffers_s *p_packets_mgt; /* packets management services
* data */
} decoder_fifo_t;
/*****************************************************************************
......
......@@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.60 2002/02/24 21:36:20 jobi Exp $
* $Id: input_ext-intf.h,v 1.61 2002/03/01 00:33:17 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -261,49 +261,45 @@ typedef struct input_thread_s
vlc_thread_t thread_id; /* id for thread functions */
int i_status; /* status flag */
/* Input module */
struct module_s * p_input_module;
/* Init/End */
int (* pf_probe)( struct input_thread_s * );
void (* pf_init)( struct input_thread_s * );
void (* pf_open)( struct input_thread_s * );
/* Access module */
struct module_s * p_access_module;
int (* pf_open)( struct input_thread_s * );
void (* pf_close)( struct input_thread_s * );
void (* pf_end)( struct input_thread_s * );
/* Read & Demultiplex */
int (* pf_read)( struct input_thread_s *,
struct data_packet_s ** );
void (* pf_demux)( struct input_thread_s *,
struct data_packet_s * );
/* Packet management facilities */
struct data_packet_s *(*pf_new_packet)( void *, size_t );
struct pes_packet_s *(* pf_new_pes)( void * );
void (* pf_delete_packet)( void *,
struct data_packet_s * );
void (* pf_delete_pes)( void *, struct pes_packet_s * );
/* Stream control capabilities */
ssize_t (* pf_read) ( struct input_thread_s *,
byte_t *, size_t );
int (* pf_set_program)( struct input_thread_s *,
struct pgrm_descriptor_s * );
int (* pf_set_area)( struct input_thread_s *,
struct input_area_s * );
void (* pf_seek)( struct input_thread_s *, off_t );
void * p_access_data;
size_t i_mtu;
/* Demux module */
struct module_s * p_demux_module;
int (* pf_init)( struct input_thread_s * );
void (* pf_end)( struct input_thread_s * );
int (* pf_demux)( struct input_thread_s * );
int (* pf_rewind)( struct input_thread_s * );
/* NULL if we don't support going *
* backwards (it's gonna be fun) */
void (* pf_seek)( struct input_thread_s *, off_t );
void * p_demux_data; /* data of the demux */
char * p_source;
int i_handle; /* socket or file descriptor */
FILE * p_stream; /* if applicable */
void * p_handle; /* if i_handle isn't suitable */
void * p_method_data; /* data of the packet manager */
void * p_plugin_data; /* data of the plugin */
/* Buffer manager */
struct input_buffers_s *p_method_data; /* data of the packet manager */
struct data_buffer_s * p_data_buffer;
byte_t * p_current_data;
byte_t * p_last_data;
size_t i_bufsize;
/* General stream description */
stream_descriptor_t stream; /* PAT tables */
stream_descriptor_t stream;
/* Playlist item */
char * psz_source;
char * psz_access;
char * psz_demux;
char * psz_name;
count_t c_loops;
} input_thread_t;
......
......@@ -2,8 +2,8 @@
* input_ext-plugins.h: structures of the input not exported to other modules,
* but exported to plug-ins
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input_ext-plugins.h,v 1.17 2002/02/15 13:32:52 sam Exp $
* Copyright (C) 1999-2002 VideoLAN
* $Id: input_ext-plugins.h,v 1.18 2002/03/01 00:33:17 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -31,6 +31,8 @@
* of data loss (this should be < 188). */
#define PADDING_PACKET_NUMBER 10 /* Number of padding packets top insert to
* escape a decoder. */
#define INPUT_DEFAULT_BUFSIZE 65536 /* Default buffer size to use when none
* is natural. */
#define NO_SEEK -1
/*****************************************************************************
......@@ -72,6 +74,7 @@ int input_UnselectES( struct input_thread_s *, struct es_descriptor_s * );
* Prototypes from input_dec.c
*****************************************************************************/
#ifndef PLUGIN
//decoder_capabilities_s * input_ProbeDecoder( void );
vlc_thread_t input_RunDecoder( struct input_thread_s *,
struct es_descriptor_s * );
void input_EndDecoder( struct input_thread_s *, struct es_descriptor_s * );
......@@ -98,6 +101,44 @@ mtime_t input_ClockGetTS( struct input_thread_s *,
# define input_ClockManageControl p_symbols->input_ClockManageControl
#endif
/*****************************************************************************
* Prototypes from input_ext-plugins.h (buffers management)
*****************************************************************************/
#ifndef PLUGIN
void * input_BuffersInit( void );
void input_BuffersEnd( struct input_buffers_s * );
struct data_buffer_s * input_NewBuffer( struct input_buffers_s *, size_t );
void input_ReleaseBuffer( struct input_buffers_s *, struct data_buffer_s * );
struct data_packet_s * input_ShareBuffer( struct input_buffers_s *,
struct data_buffer_s * );
struct data_packet_s * input_NewPacket( struct input_buffers_s *, size_t );
void input_DeletePacket( struct input_buffers_s *, struct data_packet_s * );
struct pes_packet_s * input_NewPES( struct input_buffers_s * );
void input_DeletePES( struct input_buffers_s *, struct pes_packet_s * );
ssize_t input_FillBuffer( struct input_thread_s * );
ssize_t input_Peek( struct input_thread_s *, byte_t **, size_t );
ssize_t input_SplitBuffer( struct input_thread_s *, data_packet_t **, size_t );
int input_AccessInit( struct input_thread_s * );
void input_AccessReinit( struct input_thread_s * );
void input_AccessEnd( struct input_thread_s * );
#else
# define input_BuffersInit p_symbols->input_BuffersInit
# define input_BuffersEnd p_symbols->input_BuffersEnd
# define input_NewBuffer p_symbols->input_NewBuffer
# define input_ReleaseBuffer p_symbols->input_ReleaseBuffer
# define input_ShareBuffer p_symbols->input_ShareBuffer
# define input_NewPacket p_symbols->input_NewPacket
# define input_DeletePacket p_symbols->input_DeletePacket
# define input_NewPES p_symbols->input_NewPES
# define input_DeletePES p_symbols->input_DeletePES
# define input_FillBuffer p_symbols->input_FillBuffer
# define input_Peek p_symbols->input_Peek
# define input_SplitBuffer p_symbols->input_SplitBuffer
# define input_AccessInit p_symbols->input_AccessInit
# define input_AccessReinit p_symbols->input_AccessReinit
# define input_AccessEnd p_symbols->input_AccessEnd
#endif
/*****************************************************************************
* Create a NULL packet for padding in case of a data loss
*****************************************************************************/
......@@ -107,8 +148,7 @@ static __inline__ void input_NullPacket( input_thread_t * p_input,
data_packet_t * p_pad_data;
pes_packet_t * p_pes;
if( (p_pad_data = p_input->pf_new_packet(
p_input->p_method_data,
if( (p_pad_data = input_NewPacket( p_input->p_method_data,
PADDING_PACKET_SIZE )) == NULL )
{
intf_ErrMsg("Out of memory");
......@@ -129,7 +169,7 @@ static __inline__ void input_NullPacket( input_thread_t * p_input,
}
else
{
if( (p_pes = p_input->pf_new_pes( p_input->p_method_data )) == NULL )
if( (p_pes = input_NewPES( p_input->p_method_data )) == NULL )
{
intf_ErrMsg("Out of memory");
p_input->b_error = 1;
......@@ -145,683 +185,6 @@ static __inline__ void input_NullPacket( input_thread_t * p_input,
}
/*
* Optional Next Generation buffer manager
*
* Either buffers can only be used in one data packet (PS case), or buffers
* contain several data packets (DVD case). In the first case, buffers are
* embedded into data packets, otherwise they are allocated separately and
* shared with a refcount. --Meuuh
*/
/* Number of buffers for the calculation of the mean */
#define INPUT_BRESENHAM_NB 50
/* Flags */
#define BUFFERS_NOFLAGS 0
#define BUFFERS_UNIQUE_SIZE 1 /* Only with NB_LIFO == 1 */
/*****************************************************************************
* _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;
#define BUFFERS_LIFO( TYPE, NAME ) \
struct \
{ \
TYPE * p_stack; /* First item in the LIFO */ \
unsigned int i_depth; /* Number of items in the LIFO */ \
unsigned int i_average_size; /* Average size of the items (Bresenham) */\
} NAME;
#define DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO ) \
typedef struct _input_buffers_s \
{ \
vlc_mutex_t lock; \
PACKETS_LIFO( pes_packet_t, pes ) \
BUFFERS_LIFO( _data_packet_t, data[NB_LIFO] ) \
size_t i_allocated; \
} _input_buffers_t;
#define DECLARE_BUFFERS_SHARED( FLAGS, NB_LIFO ) \
typedef struct _input_buffers_s \
{ \
vlc_mutex_t lock; \
PACKETS_LIFO( pes_packet_t, pes ) \
PACKETS_LIFO( _data_packet_t, data ) \
BUFFERS_LIFO( _data_buffer_t, buffers[NB_LIFO] ) \
size_t i_allocated; \
} _input_buffers_t;
/* Data buffer, used in case the buffer can be shared between several data
* packets */
typedef struct _data_buffer_s
{
struct _data_buffer_s * p_next;
/* number of data packets this buffer is referenced from - when it falls
* down to 0, the buffer is freed */
int i_refcount;
struct /* for compatibility with _data_packet_t */
{
/* size of the current buffer (starting right thereafter) */
unsigned int i_size;
} _private;
} _data_buffer_t;
/* We overload the data_packet_t type to add private members */
typedef struct _data_packet_s
{
struct _data_packet_s * p_next;
DATA_PACKET
union
{
struct _data_buffer_s * p_buffer; /* in case of shared buffers */
/* size of the embedded buffer (starting right thereafter) */
unsigned int i_size;
} _private;
} _data_packet_t;
/*****************************************************************************
* input_BuffersInit: initialize the cache structures, return a pointer to it
*****************************************************************************/
#define DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO ) \
static void * input_BuffersInit( void ) \
{ \
_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_buffers->lock ); \
\
return (void *)p_buffers; \
}
/*****************************************************************************
* input_BuffersEnd: free all cached structures
*****************************************************************************/
#define BUFFERS_END_STAT_BUFFERS_LOOP( STRUCT ) \
for( i = 0; i < NB_LIFO; i++ ) \
{ \
if( FLAGS & BUFFERS_UNIQUE_SIZE ) \
{ \
intf_StatMsg( \
"input buffers stats: " #STRUCT "[%d]: %d packets", \
i, p_buffers->STRUCT[i].i_depth ); \
} \
else \
{ \
intf_StatMsg( \
"input buffers stats: " #STRUCT "[%d]: %d bytes, %d packets", \
i, p_buffers->STRUCT[i].i_average_size, \
p_buffers->STRUCT[i].i_depth ); \
} \
}
#define BUFFERS_END_STAT( FLAGS, NB_LIFO ) \
BUFFERS_END_STAT_BUFFERS_LOOP( data );
#define BUFFERS_END_STAT_SHARED( FLAGS, NB_LIFO ) \
intf_StatMsg( "input buffers stats: data: %d packets", \
p_buffers->data.i_depth ); \
BUFFERS_END_STAT_BUFFERS_LOOP( buffers );
#define BUFFERS_END_BUFFERS_LOOP \
while( p_buf != NULL ) \
{ \
p_next = p_buf->p_next; \
p_buffers->i_allocated -= p_buf->_private.i_size; \
free( p_buf ); \
p_buf = p_next; \
}
#define BUFFERS_END_PACKETS_LOOP \
while( p_packet != NULL ) \
{ \
p_next = p_packet->p_next; \
free( p_packet ); \
p_packet = p_next; \
}
#define BUFFERS_END_LOOP( FLAGS, NB_LIFO ) \
for( i = 0; i < NB_LIFO; i++ ) \
{ \
_data_packet_t * p_next; \
_data_packet_t * p_buf = p_buffers->data[i].p_stack; \
BUFFERS_END_BUFFERS_LOOP; \
} \
#define BUFFERS_END_LOOP_SHARED( FLAGS, NB_LIFO ) \
{ \
/* Free data packets */ \
_data_packet_t * p_next; \
_data_packet_t * p_packet = p_buffers->data.p_stack; \
BUFFERS_END_PACKETS_LOOP; \
} \
\
for( i = 0; i < NB_LIFO; i++ ) \
{ \
_data_buffer_t * p_next; \
_data_buffer_t * p_buf = p_buffers->buffers[i].p_stack; \
BUFFERS_END_BUFFERS_LOOP; \
} \
#define BUFFERS_END( FLAGS, NB_LIFO, STAT_LOOP, LOOP ) \
static void input_BuffersEnd( void * _p_buffers ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
\
if( _p_buffers != NULL ) \
{ \
int i; \
\
if( p_main->b_stats ) \
{ \
int i; \
intf_StatMsg( "input buffers stats: pes: %d packets", \
p_buffers->pes.i_depth ); \
STAT_LOOP( FLAGS, NB_LIFO ); \
} \
\
{ \
/* Free PES */ \
pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack; \
BUFFERS_END_PACKETS_LOOP; \
} \
\
LOOP( FLAGS, NB_LIFO ); \
\
if( p_buffers->i_allocated ) \
{ \
intf_ErrMsg( "input buffers error: %d bytes have not been" \
" freed, expect memory leak", \
p_buffers->i_allocated ); \
} \
\
vlc_mutex_destroy( &p_buffers->lock ); \
free( _p_buffers ); \
} \
}
#define DECLARE_BUFFERS_END( FLAGS, NB_LIFO ) \
BUFFERS_END( FLAGS, NB_LIFO, BUFFERS_END_STAT, BUFFERS_END_LOOP );
#define DECLARE_BUFFERS_END_SHARED( FLAGS, NB_LIFO ) \
BUFFERS_END( FLAGS, NB_LIFO, BUFFERS_END_STAT_SHARED, \
BUFFERS_END_LOOP_SHARED );
/*****************************************************************************
* input_NewPacket: return a pointer to a data packet of the appropriate size
*****************************************************************************/
#define BUFFERS_NEWPACKET_EXTRA_DECLARATION( FLAGS, NB_LIFO ) \
_data_packet_t ** pp_data = &p_buf;
#define BUFFERS_NEWPACKET_EXTRA_DECLARATION_SHARED( FLAGS, NB_LIFO ) \
_data_packet_t * p_data; \
_data_packet_t ** pp_data = &p_data;
#define BUFFERS_NEWPACKET_EXTRA( FLAGS, NB_LIFO )
#define BUFFERS_NEWPACKET_EXTRA_SHARED( FLAGS, NB_LIFO ) \
/* Find a data packet */ \
if( p_buffers->data.p_stack != NULL ) \
{ \
p_data = p_buffers->data.p_stack; \
p_buffers->data.p_stack = p_data->p_next; \
p_buffers->data.i_depth--; \
} \
else \
{ \
p_data = malloc( sizeof( _data_packet_t ) ); \
if( p_data == NULL ) \
{ \
intf_ErrMsg( "Out of memory" ); \
vlc_mutex_unlock( &p_buffers->lock ); \
return( NULL ); \
} \
} \
\
if( i_size == 0 ) \
{ \
/* Warning : in that case, the data packet is left partly \
* uninitialized ; theorically only input_ShareBuffer may call \
* this. */ \
p_data->p_next = NULL; \
p_data->b_discard_payload = 0; \
return( (data_packet_t *)p_data ); \
}
#define BUFFERS_NEWPACKET_END( FLAGS, NB_LIFO, TYPE ) \
(*pp_data)->p_demux_start = (byte_t *)*pp_data + sizeof( TYPE );
#define BUFFERS_NEWPACKET_END_SHARED( FLAGS, NB_LIFO, TYPE ) \
(*pp_data)->_private.p_buffer = p_buf; \
(*pp_data)->p_demux_start = (byte_t *)(*pp_data)->_private.p_buffer \
+ sizeof( TYPE ); \
/* Initialize refcount */ \
p_buf->i_refcount = 1;
#define BUFFERS_NEWPACKET( FLAGS, NB_LIFO, TYPE, NAME, EXTRA_DECLARATION, \
EXTRA, END ) \
/* This one doesn't take p_buffers->lock. */ \
static __inline__ data_packet_t * _input_NewPacket( void * _p_buffers, \
size_t i_size ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
int i_select; \
TYPE * p_buf; \
EXTRA_DECLARATION( FLAGS, NB_LIFO ); \
\
/* Safety check */ \
if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION ) \
{ \
intf_ErrMsg( "INPUT_MAX_ALLOCATION reached (%d)", \
p_buffers->i_allocated ); \
return NULL; \
} \
\
EXTRA( FLAGS, NB_LIFO ); \
\
for( i_select = 0; i_select < NB_LIFO - 1; i_select++ ) \
{ \
if( i_size <= (2 * p_buffers->NAME[i_select].i_average_size \
+ p_buffers->NAME[i_select + 1].i_average_size) / 3 ) \
{ \
break; \
} \
} \
\
if( p_buffers->NAME[i_select].p_stack != NULL ) \
{ \
/* Take the packet from the cache */ \
p_buf = p_buffers->NAME[i_select].p_stack; \
p_buffers->NAME[i_select].p_stack = p_buf->p_next; \
p_buffers->NAME[i_select].i_depth--; \
\
/* Reallocate the packet if it is too small or too large */ \
if( !(FLAGS & BUFFERS_UNIQUE_SIZE) && \
(p_buf->_private.i_size < i_size \
|| p_buf->_private.i_size > 3 * i_size) ) \
{ \
p_buffers->i_allocated -= p_buf->_private.i_size; \
p_buf = realloc( p_buf, sizeof( TYPE ) + i_size ); \
if( p_buf == NULL ) \
{ \
intf_ErrMsg( "Out of memory" ); \
return NULL; \
} \
p_buf->_private.i_size = i_size; \
p_buffers->i_allocated += i_size; \
} \
} \
else \
{ \
/* Allocate a new packet */ \
p_buf = malloc( sizeof( TYPE ) + i_size ); \
if( p_buf == NULL ) \
{ \
intf_ErrMsg( "Out of memory" ); \
return NULL; \
} \
p_buf->_private.i_size = i_size; \
p_buffers->i_allocated += i_size; \
} \
\
/* Initialize data */ \
END( FLAGS, NB_LIFO, TYPE ); \
(*pp_data)->p_next = NULL; \
(*pp_data)->b_discard_payload = 0; \
(*pp_data)->p_payload_start = (*pp_data)->p_demux_start; \
(*pp_data)->p_payload_end = (*pp_data)->p_payload_start + i_size; \
\
return( (data_packet_t *)*pp_data ); \
} \
\
static data_packet_t * input_NewPacket( void * _p_buffers, size_t i_size ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
data_packet_t * p_data; \
\
/* Safety check */ \
if( !(FLAGS & BUFFERS_UNIQUE_SIZE) && i_size > INPUT_MAX_PACKET_SIZE ) \
{ \
intf_ErrMsg( "Packet too big (%d)", i_size ); \
return NULL; \
} \
\
vlc_mutex_lock( &p_buffers->lock ); \
p_data = _input_NewPacket( _p_buffers, i_size ); \
vlc_mutex_unlock( &p_buffers->lock ); \
return( p_data ); \
}
#define DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO ) \
BUFFERS_NEWPACKET( FLAGS, NB_LIFO, _data_packet_t, data, \
BUFFERS_NEWPACKET_EXTRA_DECLARATION, BUFFERS_NEWPACKET_EXTRA, \
BUFFERS_NEWPACKET_END )
#define DECLARE_BUFFERS_NEWPACKET_SHARED( FLAGS, NB_LIFO ) \
BUFFERS_NEWPACKET( FLAGS, NB_LIFO, _data_buffer_t, buffers, \
BUFFERS_NEWPACKET_EXTRA_DECLARATION_SHARED, \
BUFFERS_NEWPACKET_EXTRA_SHARED, BUFFERS_NEWPACKET_END_SHARED )
/*****************************************************************************
* input_DeletePacket: put a packet back into the cache
*****************************************************************************/
#define BUFFERS_DELETEPACKET_EXTRA( FLAGS, NB_LIFO, DATA_CACHE_SIZE ) \
_data_packet_t * p_buf = p_data;
#define BUFFERS_DELETEPACKET_EXTRA_SHARED( FLAGS, NB_LIFO, DATA_CACHE_SIZE )\
_data_buffer_t * p_buf = (_data_buffer_t *)p_data->_private.p_buffer; \
\
/* Get rid of the data packet */ \
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 ); \
} \
\
/* Decrement refcount */ \
p_buf->i_refcount--; \
if( p_buf->i_refcount > 0 ) \
{ \
return; \
}
#define BUFFERS_DELETEPACKETSTACK_EXTRA( FLAGS, NB_LIFO, DATA_CACHE_SIZE ) \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
_data_packet_t * p_first = (_data_packet_t *)_p_first; \
_data_packet_t ** pp_last = (_data_packet_t **)_pp_last; \
\
/* Small hopeless optimization */ \
if( (FLAGS & BUFFERS_UNIQUE_SIZE) \
&& p_buffers->data[0].i_depth < DATA_CACHE_SIZE ) \
{ \
p_buffers->data[0].i_depth += i_nb; \
*pp_last = p_buffers->data[0].p_stack; \
p_buffers->data[0].p_stack = p_first; \
} \
else /* No semicolon after this or you will die */
#define BUFFERS_DELETEPACKETSTACK_EXTRA_SHARED( FLAGS, NB_LIFO, \
DATA_CACHE_SIZE )
#define BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, DATA_CACHE_SIZE, TYPE, \
NAME, EXTRA, EXTRA_STACK ) \
/* This one doesn't take p_buffers->lock. */ \
static __inline__ void _input_DeletePacket( void * _p_buffers, \
data_packet_t * _p_data ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
_data_packet_t * p_data = (_data_packet_t *)_p_data; \
int i_select; \
\
while( p_data != NULL ) \
{ \
_data_packet_t * p_next = p_data->p_next; \
\
EXTRA( FLAGS, NB_LIFO, DATA_CACHE_SIZE ); \
\
for( i_select = 0; i_select < NB_LIFO - 1; i_select++ ) \
{ \
if( p_buf->_private.i_size <= \
(2 * p_buffers->NAME[i_select].i_average_size \
+ p_buffers->NAME[i_select + 1].i_average_size) / 3 ) \
{ \
break; \
} \
} \
\
if( p_buffers->NAME[i_select].i_depth < DATA_CACHE_SIZE ) \
{ \
/* Cache not full : store the packet in it */ \
p_buf->p_next = p_buffers->NAME[i_select].p_stack; \
p_buffers->NAME[i_select].p_stack = p_buf; \
p_buffers->NAME[i_select].i_depth++; \
\
if( !(FLAGS & BUFFERS_UNIQUE_SIZE) ) \
{ \
/* Update Bresenham mean (very approximative) */ \
p_buffers->NAME[i_select].i_average_size = \
( p_buf->_private.i_size \
+ p_buffers->NAME[i_select].i_average_size \
* (INPUT_BRESENHAM_NB - 1) ) \
/ INPUT_BRESENHAM_NB; \
} \
} \
else \
{ \
p_buffers->i_allocated -= p_buf->_private.i_size; \
free( p_buf ); \
} \
\
p_data = p_next; \
} \
} \
\
static void input_DeletePacket( void * _p_buffers, data_packet_t * p_data ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
\
vlc_mutex_lock( &p_buffers->lock ); \
_input_DeletePacket( _p_buffers, p_data ); \
vlc_mutex_unlock( &p_buffers->lock ); \
} \
\
/* Delete a chained list of i_nb data packets. -- needed by DeletePES */ \
static __inline__ void _input_DeletePacketStack( void * _p_buffers, \
data_packet_t * _p_first, \
data_packet_t ** _pp_last, \
unsigned int i_nb ) \
{ \
/* Do not add code before, EXTRA_STACK makes its own declarations. */ \
EXTRA_STACK( FLAGS, NB_LIFO, DATA_CACHE_SIZE ) \
/* No semicolon - PLEASE */ \
{ \
_input_DeletePacket( _p_buffers, _p_first ); \
} \
}
#define DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, DATA_CACHE_SIZE ) \
BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, DATA_CACHE_SIZE, _data_packet_t, \
data, BUFFERS_DELETEPACKET_EXTRA, \
BUFFERS_DELETEPACKETSTACK_EXTRA )
#define DECLARE_BUFFERS_DELETEPACKET_SHARED( FLAGS, NB_LIFO, \
DATA_CACHE_SIZE ) \
BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, DATA_CACHE_SIZE, _data_buffer_t, \
buffers, BUFFERS_DELETEPACKET_EXTRA_SHARED, \
BUFFERS_DELETEPACKETSTACK_EXTRA_SHARED )
/*****************************************************************************
* input_DeletePacketStack: optimize deleting of a stack of packets when
* knowing much information
*****************************************************************************/
/* AFAIK, this isn't used by anyone - it is here for completion.
* _input_DeletePacketStack is declared in DeletePacket because it is needed
* by DeletePES. */
#define DECLARE_BUFFERS_DELETEPACKETSTACK( FLAGS, NB_LIFO ) \
static void input_DeletePacketStack( void * _p_buffers, \
data_packet_t * p_first, \
data_packet_t ** pp_last, \
unsigned int i_nb ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
\
vlc_mutex_lock( &p_buffers->lock ); \
_input_DeletePacketStack( _p_buffers, p_first, pp_last, i_nb ); \
vlc_mutex_unlock( &p_buffers->lock ); \
}
/*****************************************************************************
* input_NewPES: return a pointer to a new PES packet
*****************************************************************************/
#define DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO ) \
static pes_packet_t * input_NewPES( void * _p_buffers ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
pes_packet_t * p_pes; \
\
vlc_mutex_lock( &p_buffers->lock ); \
\
if( p_buffers->pes.p_stack != NULL ) \
{ \
p_pes = p_buffers->pes.p_stack; \
p_buffers->pes.p_stack = p_pes->p_next; \
p_buffers->pes.i_depth--; \
} \
else \
{ \
p_pes = malloc( sizeof( pes_packet_t ) ); \
if( p_pes == NULL ) \
{ \
intf_ErrMsg( "Out of memory" ); \
vlc_mutex_unlock( &p_buffers->lock ); \
return( NULL ); \
} \
} \
\
vlc_mutex_unlock( &p_buffers->lock ); \
\
/* Initialize data */ \
p_pes->p_next = NULL; \
p_pes->b_data_alignment = p_pes->b_discontinuity = \
p_pes->i_pts = p_pes->i_dts = 0; \
p_pes->i_pes_size = 0; \
p_pes->p_first = p_pes->p_last = NULL; \
p_pes->i_nb_data = 0; \
\
return( p_pes ); \
}
/*****************************************************************************
* input_DeletePES: put a pes and all data packets back into the cache
*****************************************************************************/
#define DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, PES_CACHE_SIZE ) \
static void input_DeletePES( void * _p_buffers, pes_packet_t * p_pes ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
\
vlc_mutex_lock( &p_buffers->lock ); \
\
while( p_pes != NULL ) \
{ \
pes_packet_t * p_next = p_pes->p_next; \
\
/* Delete all data packets */ \
if( p_pes->p_first != NULL ) \
{ \
_input_DeletePacketStack( _p_buffers, p_pes->p_first, \
&p_pes->p_last->p_next, \
p_pes->i_nb_data ); \
} \
\
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; \
} \
\
vlc_mutex_unlock( &p_buffers->lock ); \
}
/*****************************************************************************
* input_BuffersToIO: return an IO vector (only with BUFFERS_UNIQUE_SIZE)
*****************************************************************************/
#define DECLARE_BUFFERS_TOIO( FLAGS, BUFFER_SIZE ) \
static data_packet_t * input_BuffersToIO( void * _p_buffers, \
struct iovec * p_iovec, int i_nb )\
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
data_packet_t * p_data = NULL; \
int i; \
\
vlc_mutex_lock( &p_buffers->lock ); \
\
for( i = i_nb - 1; i >= 0; i-- ) \
{ \
data_packet_t * p_next = _input_NewPacket( _p_buffers, \
BUFFER_SIZE /* UNIQUE_SIZE */ ); \
if( p_next == NULL ) \
{ \
_input_DeletePacket( _p_buffers, p_data ); \
return( NULL ); \
} \
\
p_iovec[i].iov_base = p_next->p_demux_start; \
p_iovec[i].iov_len = BUFFER_SIZE; \
p_next->p_next = p_data; \
p_data = p_next; \
} \
\
vlc_mutex_unlock( &p_buffers->lock ); \
\
return( p_data ); \
}
/*****************************************************************************
* input_ShareBuffer: return a new data_packet to the same buffer
*****************************************************************************/
#define DECLARE_BUFFERS_SHAREBUFFER( FLAGS ) \
static data_packet_t * input_ShareBuffer( void * _p_buffers, \
data_packet_t * _p_shared_data ) \
{ \
_input_buffers_t * p_buffers = (_input_buffers_t *)_p_buffers; \
_data_packet_t * p_shared_data = (_data_packet_t *)_p_shared_data; \
_data_packet_t * p_data; \
_data_buffer_t * p_buf = p_shared_data->_private.p_buffer; \
\
vlc_mutex_lock( &p_buffers->lock ); \
\
/* Get new data_packet_t, without a buffer through a special backdoor \
* in _input_NewPacket. */ \
p_data = (_data_packet_t *)_input_NewPacket( _p_buffers, 0 ); \
\
/* Finish initialization of p_data */ \
p_data->_private.p_buffer = p_shared_data->_private.p_buffer; \
p_data->p_demux_start = p_data->p_payload_start \
= (byte_t *)p_shared_data->_private.p_buffer \
+ sizeof( _data_buffer_t ); \
p_data->p_payload_end = p_data->p_demux_start + p_buf->_private.i_size; \
\
/* Update refcount */ \
p_buf->i_refcount++; \
\
vlc_mutex_unlock( &p_buffers->lock ); \
\
return( (data_packet_t *)p_data ); \
}
/*
* Optional MPEG demultiplexing
*/
......@@ -938,3 +301,32 @@ void input_DemuxPSI ( struct input_thread_s *, struct data_packet_s *,
# define input_DemuxPSI p_symbols->input_DemuxPSI
#endif
/*
* Optional standard file descriptor operations (input_ext-plugins.h)
*/
/*****************************************************************************
* input_socket_t: private access plug-in data
*****************************************************************************/
typedef struct input_socket_s
{
/* Unbuffered file descriptor */
int i_handle;
} input_socket_t;
/*****************************************************************************
* Prototypes
*****************************************************************************/
#ifndef PLUGIN
void input_FDClose( struct input_thread_s * );
ssize_t input_FDRead( input_thread_t *, byte_t *, size_t );
int input_FDNetworkRead( input_thread_t *, byte_t *, size_t );
void input_FDSeek( struct input_thread_s *, off_t );
#else
# define input_FDClose p_symbols->input_FDClose
# define input_FDRead p_symbols->input_FDRead
# define input_FDNetworkRead p_symbols->input_FDNetworkRead
# define input_FDSeek p_symbols->input_FDSeek
#endif
......@@ -2,7 +2,7 @@
* modules.h : Module management functions.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: modules.h,v 1.43 2002/02/24 22:06:50 sam Exp $
* $Id: modules.h,v 1.44 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -52,10 +52,10 @@ static __inline__ char *GetCapabilityName( unsigned int i_capa )
#define MODULE_CAPABILITY_INTF 1 /* Interface */
"access",
#define MODULE_CAPABILITY_ACCESS 2 /* Input */
"input",
#define MODULE_CAPABILITY_INPUT 3 /* Input */
"decaps",
#define MODULE_CAPABILITY_DECAPS 4 /* Decaps */
"demux",
#define MODULE_CAPABILITY_DEMUX 3 /* Input */
"network",
#define MODULE_CAPABILITY_NETWORK 4 /* Network */
"decoder",
#define MODULE_CAPABILITY_DECODER 5 /* Audio or video decoder */
"motion",
......@@ -174,38 +174,33 @@ typedef struct function_list_s
void ( * pf_run ) ( struct intf_thread_s * );
} intf;
/* Input plugin */
/* Access plugin */
struct
{
int ( * pf_probe )( struct input_thread_s * );
void ( * pf_init ) ( struct input_thread_s * );
void ( * pf_open ) ( struct input_thread_s * );
int ( * pf_open ) ( struct input_thread_s * );
void ( * pf_close )( struct input_thread_s * );
void ( * pf_end ) ( struct input_thread_s * );
void ( * pf_init_bit_stream ) ( struct bit_stream_s *,
struct decoder_fifo_s *,
void (* pf_bitstream_callback)( struct bit_stream_s *,
boolean_t ),
void * );
int ( * pf_read ) ( struct input_thread_s *,
struct data_packet_s ** );
void ( * pf_demux )( struct input_thread_s *,
struct data_packet_s * );
struct data_packet_s * ( * pf_new_packet ) ( void *, size_t );
struct pes_packet_s * ( * pf_new_pes ) ( void * );
void ( * pf_delete_packet ) ( void *, struct data_packet_s * );
void ( * pf_delete_pes ) ( void *, struct pes_packet_s * );
ssize_t ( * pf_read ) ( struct input_thread_s *, byte_t *, size_t );
void ( * pf_seek ) ( struct input_thread_s *, off_t );
int ( * pf_set_program ) ( struct input_thread_s *,
struct pgrm_descriptor_s * );
struct pgrm_descriptor_s * );
int ( * pf_set_area ) ( struct input_thread_s *,
struct input_area_s * );
} access;
/* Demux plugin */
struct
{
int ( * pf_init ) ( struct input_thread_s * );
void ( * pf_end ) ( struct input_thread_s * );
int ( * pf_demux )( struct input_thread_s * );
int ( * pf_rewind ) ( struct input_thread_s * );
void ( * pf_seek ) ( struct input_thread_s *, off_t );
} input;
} demux;
/* Network plugin */
struct
{
int ( * pf_open )( struct network_socket_s * );
} network;
/* Audio output plugin */
struct
......@@ -312,8 +307,8 @@ typedef struct module_functions_s
/* XXX: The order here has to be the same as above for the #defines */
function_list_t intf;
function_list_t access;
function_list_t input;
function_list_t decaps;
function_list_t demux;
function_list_t network;
function_list_t dec;
function_list_t motion;
function_list_t idct;
......
/*****************************************************************************
* input_es.h: thread structure of the ES plugin
* network.h: interface to communicate with network plug-ins
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: input_es.h,v 1.3 2001/12/27 03:47:09 massiot Exp $
* Copyright (C) 2002 VideoLAN
* $Id: network.h,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -21,6 +21,26 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#define ES_PACKET_SIZE 2048
#define ES_READ_ONCE 50
#define MAX_PACKETS_IN_FIFO 50
/*****************************************************************************
* network_socket_t: structure passed to a network plug-in to define the
* kind of socket we want
*****************************************************************************/
typedef struct network_socket_s
{
unsigned int i_type;
char * psz_bind_addr;
int i_bind_port;
char * psz_server_addr;
int i_server_port;
/* Return values */
int i_handle;
size_t i_mtu;
} network_socket_t;
/* Socket types */
#define NETWORK_UDP 1
#define NETWORK_TCP 2
......@@ -3,7 +3,7 @@
* This header provides a portable threads implementation.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: threads.h,v 1.36 2002/02/27 03:47:56 sam Exp $
* $Id: threads.h,v 1.37 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
......@@ -37,6 +37,10 @@
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */
# include <pthread.h>
# ifdef DEBUG
/* Needed for pthread_cond_timedwait */
# include <errno.h>
# endif
/* This is not prototyped under Linux, though it exists. */
int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
......@@ -716,15 +720,21 @@ static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
timeout.tv_nsec = now.tv_usec * 1000;
if( (i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout )) )
i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout );
if( i_result == ETIMEDOUT )
{
intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)",
pthread_self(), psz_file, i_line, strerror(i_result) );
continue;
}
else
if( i_result )
{
return i_result;
intf_ErrMsg( "thread %d error: cond_wait failed at %s:%d (%s)",
pthread_self(), psz_file, i_line, strerror(i_result) );
}
return( i_result );
}
#endif
......
......@@ -4,7 +4,7 @@
* includes all common video types and constants.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: video.h,v 1.43 2002/02/19 00:50:19 sam Exp $
* $Id: video.h,v 1.44 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -84,11 +84,6 @@ typedef struct picture_s
boolean_t b_repeat_first_field; /* RFF bit */
boolean_t b_top_field_first; /* which field is first */
/* Macroblock counter - the decoder uses it to verify if it has
* decoded all the macroblocks of the picture */
int i_deccount;
vlc_mutex_t lock_deccount;
/* Private data - the video output plugin might want to put stuff here to
* keep track of the picture */
struct picture_sys_s *p_sys;
......
.dep
*.lo
*.o.*
*.lo.*
file_SOURCES = file.c
udp_SOURCES = udp.c
http_SOURCES = http.c
/*****************************************************************************
* file.c: file input (file: access plug-in)
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: file.c,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * );
static int FileOpen ( struct input_thread_s * );
static int FileSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "Standard filesystem file reading" )
ADD_CAPABILITY( ACCESS, 50 )
ADD_SHORTCUT( "file" )
ADD_SHORTCUT( "stream" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
input_getfunctions( &p_module->p_functions->access );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.access
input.pf_open = FileOpen;
input.pf_read = input_FDRead;
input.pf_close = input_FDClose;
input.pf_set_program = FileSetProgram;
input.pf_set_area = NULL;
input.pf_seek = input_FDSeek;
#undef input
}
/*****************************************************************************
* FileOpen: open the file
*****************************************************************************/
static int FileOpen( input_thread_t * p_input )
{
char * psz_name = p_input->psz_name;
int i_stat;
struct stat stat_info;
input_socket_t * p_access_data;
boolean_t b_stdin;
p_input->i_mtu = 0;
b_stdin = ( strlen( p_input->psz_name ) == 1 )
&& *p_input->psz_name == '-';
if( !b_stdin && (i_stat = stat( psz_name, &stat_info )) == (-1) )
{
intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
psz_name, strerror(errno));
return( -1 );
}
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_input->psz_access != NULL
&& !strncmp( p_input->psz_access, "stream", 7 ) )
{
/* stream:%s */
p_input->stream.b_pace_control = 0;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
}
else
{
/* file:%s or %s */
p_input->stream.b_pace_control = 1;
if( b_stdin )
{
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
}
else if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
|| S_ISBLK(stat_info.st_mode) )
{
p_input->stream.b_seekable = 1;
p_input->stream.p_selected_area->i_size = stat_info.st_size;
}
else if( S_ISFIFO(stat_info.st_mode)
#if !defined( SYS_BEOS ) && !defined( WIN32 )
|| S_ISSOCK(stat_info.st_mode)
#endif
)
{
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
}
else
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_ErrMsg( "input error: unknown file type for `%s'",
psz_name );
return( -1 );
}
}
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.i_method = INPUT_METHOD_FILE;
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_WarnMsg( 2, "input: opening file `%s'", psz_name );
p_access_data = malloc( sizeof(input_socket_t) );
p_input->p_access_data = (void *)p_access_data;
if( p_access_data == NULL )
{
intf_ErrMsg( "input error: Out of memory" );
return( -1 );
}
if( b_stdin )
{
p_access_data->i_handle = 0;
}
else if( (p_access_data->i_handle = open( psz_name,
/*O_NONBLOCK | O_LARGEFILE*/ 0 )) == (-1) )
{
intf_ErrMsg( "input error: cannot open file %s (%s)", psz_name,
strerror(errno) );
free( p_access_data );
return( -1 );
}
return( 0 );
}
/*****************************************************************************
* FileSetProgram: Do nothing
*****************************************************************************/
static int FileSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
return( 0 );
}
/*****************************************************************************
* http.c: HTTP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: http.c,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "network.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * );
static int HTTPOpen ( struct input_thread_s * );
static int HTTPSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
static void HTTPSeek ( struct input_thread_s *, off_t );
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "HTTP access plug-in" )
ADD_CAPABILITY( ACCESS, 0 )
ADD_SHORTCUT( "http" )
ADD_SHORTCUT( "http4" )
ADD_SHORTCUT( "http6" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
input_getfunctions( &p_module->p_functions->access );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.access
input.pf_open = HTTPOpen;
input.pf_read = input_FDNetworkRead;
input.pf_close = input_FDClose;
input.pf_set_program = HTTPSetProgram;
input.pf_set_area = NULL;
input.pf_seek = HTTPSeek;
#undef input
}
/*****************************************************************************
* _input_socket_t: private access plug-in data, modified to add private
* fields
*****************************************************************************/
typedef struct _input_socket_s
{
input_socket_t _socket;
char * psz_network;
network_socket_t socket_desc;
char psz_buffer[256];
} _input_socket_t;
/*****************************************************************************
* HTTPConnect: connect to the server and seek to i_tell
*****************************************************************************/
static int HTTPConnect( input_thread_t * p_input, off_t i_tell )
{
_input_socket_t * p_access_data = p_input->p_access_data;
struct module_s * p_network;
char psz_buffer[256];
byte_t * psz_parser;
/* Find an appropriate network module */
p_network = module_Need( MODULE_CAPABILITY_NETWORK,
p_access_data->psz_network,
&p_access_data->socket_desc );
if( p_network == NULL )
{
free( p_access_data );
return( -1 );
}
module_Unneed( p_network );
p_access_data->_socket.i_handle = p_access_data->socket_desc.i_handle;
# define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n"
# define HTTP_END "\r\n"
snprintf( psz_buffer, sizeof(psz_buffer),
"%s"
"Range: bytes=%lld-\r\n"
HTTP_USERAGENT HTTP_END,
p_access_data->psz_buffer, i_tell );
psz_buffer[sizeof(psz_buffer) - 1] = '\0';
/* Send GET ... */
if( write( p_access_data->_socket.i_handle, psz_buffer,
strlen( psz_buffer ) ) == (-1) )
{
intf_ErrMsg( "http error: cannot send request (%s)", strerror(errno) );
input_FDClose( p_input );
return( -1 );
}
/* Prepare the input thread for reading. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
/* FIXME: we shouldn't have to do that ! */
p_input->pf_read = input_FDRead;
while( !input_FillBuffer( p_input ) )
{
if( p_input->b_die || p_input->b_error )
{
input_FDClose( p_input );
return( -1 );
}
}
/* Parse HTTP header. */
#define MAX_LINE 1024
for( ; ; )
{
if( input_Peek( p_input, &psz_parser, MAX_LINE ) <= 0 )
{
intf_ErrMsg( "http error: not enough data" );
input_FDClose( p_input );
return( -1 );
}
if( psz_parser[0] == '\r' && psz_parser[1] == '\n' )
{
/* End of header. */
p_input->p_current_data += 2;
break;
}
if( !strncmp( psz_parser, "Content-Length: ",
strlen("Content-Length: ") ) )
{
psz_parser += strlen("Content-Length: ");
/* FIXME : this won't work for 64-bit lengths */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_size = atoi( psz_parser )
+ i_tell;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
while( *psz_parser != '\r' && psz_parser < p_input->p_last_data )
{
psz_parser++;
}
p_input->p_current_data = psz_parser + 2;
}
if( p_input->stream.p_selected_area->i_size )
{
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell = i_tell
+ (p_input->p_last_data - p_input->p_current_data);
p_input->stream.b_seekable = 1;
p_input->stream.b_changed = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
return( 0 );
}
/*****************************************************************************
* HTTPOpen: parse URL and open the remote file at the beginning
*****************************************************************************/
static int HTTPOpen( input_thread_t * p_input )
{
_input_socket_t * p_access_data;
char * psz_parser = p_input->psz_name;
char * psz_server_addr = NULL;
char * psz_server_port = NULL;
char * psz_path = NULL;
char * psz_proxy;
int i_server_port = 0;
p_access_data = p_input->p_access_data = malloc( sizeof(_input_socket_t) );
if( p_access_data == NULL )
{
intf_ErrMsg( "http error: Out of memory" );
return( -1 );
}
p_access_data->psz_network = NULL;
if( p_input->psz_access != NULL )
{
/* Find out which shortcut was used */
if( !strncmp( p_input->psz_access, "http6", 5 ) )
{
p_access_data->psz_network = "ipv6";
}
else if( !strncmp( p_input->psz_access, "http4", 5 ) )
{
p_access_data->psz_network = "ipv4";
}
}
/* Parse psz_name syntax :
* //<hostname>[:<port>][/<path>] */
while( *psz_parser == '/' )
{
psz_parser++;
}
psz_server_addr = psz_parser;
while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
{
psz_parser++;
}
if ( *psz_parser == ':' )
{
*psz_parser = '\0';
psz_parser++;
psz_server_port = psz_parser;
while( *psz_parser && *psz_parser != '/' )
{
psz_parser++;
}
}
if( *psz_parser == '/' )
{
*psz_parser = '\0';
psz_parser++;
psz_path = psz_parser;
}
/* Convert port format */
if( psz_server_port != NULL )
{
i_server_port = strtol( psz_server_port, &psz_parser, 10 );
if( *psz_parser )
{
intf_ErrMsg( "input error: cannot parse server port near %s",
psz_parser );
free( p_input->p_access_data );
return( -1 );
}
}
if( i_server_port == 0 )
{
i_server_port = 80;
}
if( psz_server_addr == NULL )
{
intf_ErrMsg( "input error: no server given" );
free( p_input->p_access_data );
return( -1 );
}
/* Check proxy */
if( (psz_proxy = getenv( "http_proxy" )) != NULL )
{
/* http://myproxy.mydomain:myport/ */
int i_proxy_port = 0;
/* Skip the protocol name */
while( *psz_proxy && *psz_proxy != ':' )
{
psz_proxy++;
}
/* Skip the "://" part */
while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
{
psz_proxy++;
}
/* Found a proxy name */
if( *psz_proxy )
{
char *psz_port = psz_proxy;
/* Skip the hostname part */
while( *psz_port && *psz_port != ':' && *psz_port != '/' )
{
psz_port++;
}
/* Found a port name */
if( *psz_port )
{
char * psz_junk;
/* Replace ':' with '\0' */
*psz_port = '\0';
psz_port++;
psz_junk = psz_port;
while( *psz_junk && *psz_junk != '/' )
{
psz_junk++;
}
if( *psz_junk )
{
*psz_junk = '\0';
}
if( *psz_port != '\0' )
{
i_proxy_port = atoi( psz_port );
}
}
}
else
{
intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
free( p_input->p_access_data );
return( -1 );
}
p_access_data->socket_desc.i_type = NETWORK_TCP;
p_access_data->socket_desc.psz_server_addr = psz_proxy;
p_access_data->socket_desc.i_server_port = i_proxy_port;
snprintf( p_access_data->psz_buffer, sizeof(p_access_data->psz_buffer),
"GET http://%s:%d/%s HTTP/1.1\r\n",
psz_server_addr, i_server_port, psz_path );
}
else
{
/* No proxy, direct connection. */
p_access_data->socket_desc.i_type = NETWORK_TCP;
p_access_data->socket_desc.psz_server_addr = psz_server_addr;
p_access_data->socket_desc.i_server_port = i_server_port;
snprintf( p_access_data->psz_buffer, sizeof(p_access_data->psz_buffer),
"GET /%s HTTP/1.1\r\nHost: %s\r\n",
psz_path, psz_server_addr );
}
p_access_data->psz_buffer[sizeof(p_access_data->psz_buffer) - 1] = '\0';
intf_WarnMsg( 2, "input: opening server=%s port=%d path=%s",
psz_server_addr, i_server_port, psz_path );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.p_selected_area->i_size = 0;
p_input->stream.i_method = INPUT_METHOD_NETWORK;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->i_mtu = 0;
return( HTTPConnect( p_input, 0 ) );
}
/*****************************************************************************
* HTTPSetProgram: do nothing
*****************************************************************************/
static int HTTPSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
return( 0 );
}
/*****************************************************************************
* HTTPSeek: close and re-open a connection at the right place
*****************************************************************************/
static void HTTPSeek( input_thread_t * p_input, off_t i_pos )
{
_input_socket_t * p_access_data = p_input->p_access_data;
close( p_access_data->_socket.i_handle );
intf_WarnMsg( 2, "http: seeking to position %lld", i_pos );
HTTPConnect( p_input, i_pos );
}
/*****************************************************************************
* udp.c: raw UDP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: udp.c,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* 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 <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "network.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * );
static int UDPOpen ( struct input_thread_s * );
static int UDPSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "Raw UDP access plug-in" )
ADD_CAPABILITY( ACCESS, 0 )
ADD_SHORTCUT( "udp" )
ADD_SHORTCUT( "udpstream" )
ADD_SHORTCUT( "udp4" )
ADD_SHORTCUT( "udp6" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
input_getfunctions( &p_module->p_functions->access );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.access
input.pf_open = UDPOpen;
input.pf_read = input_FDNetworkRead;
input.pf_close = input_FDClose;
input.pf_set_program = UDPSetProgram;
input.pf_set_area = NULL;
input.pf_seek = NULL;
#undef input
}
/*****************************************************************************
* UDPOpen: open the socket
*****************************************************************************/
static int UDPOpen( input_thread_t * p_input )
{
input_socket_t * p_access_data;
struct module_s * p_network;
char * psz_network = NULL;
char * psz_parser = p_input->psz_name;
char * psz_server_addr = NULL;
char * psz_server_port = NULL;
char * psz_bind_addr = NULL;
char * psz_bind_port = NULL;
int i_bind_port = 0, i_server_port = 0;
network_socket_t socket_desc;
if( p_input->psz_access != NULL )
{
/* Find out which shortcut was used */
if( !strncmp( p_input->psz_access, "udp6", 5 ) )
{
psz_network = "ipv6";
}
else if( !strncmp( p_input->psz_access, "udp4", 5 ) )
{
psz_network = "ipv4";
}
}
/* Parse psz_name syntax :
* [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
if( *psz_parser && *psz_parser != '@' )
{
/* Found server */
psz_server_addr = psz_parser;
while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == ':' )
{
/* Found server port */
*psz_parser = '\0'; /* Terminate server name */
psz_parser++;
psz_server_port = psz_parser;
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
}
}
if( *psz_parser == '@' )
{
/* Found bind address or bind port */
*psz_parser = '\0'; /* Terminate server port or name if necessary */ psz_parser++;
if( *psz_parser && *psz_parser != ':' )
{
/* Found bind address */
psz_bind_addr = psz_parser;
while( *psz_parser && *psz_parser != ':' )
{
psz_parser++;
}
}
if( *psz_parser == ':' )
{
/* Found bind port */
*psz_parser = '\0'; /* Terminate bind address if necessary */
psz_parser++;
psz_bind_port = psz_parser;
}
}
/* Convert ports format */
if( psz_server_port != NULL )
{
i_server_port = strtol( psz_server_port, &psz_parser, 10 );
if( *psz_parser )
{
intf_ErrMsg( "input error: cannot parse server port near %s",
psz_parser );
return( -1 );
}
}
if( psz_bind_port != NULL )
{
i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
if( *psz_parser )
{
intf_ErrMsg( "input error: cannot parse bind port near %s",
psz_parser );
return( -1 );
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 0;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.i_method = INPUT_METHOD_NETWORK;
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_WarnMsg( 2, "input: opening server=%s:%d local=%s:%d",
psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
/* Prepare the network_socket_t structure */
socket_desc.i_type = NETWORK_UDP;
socket_desc.psz_bind_addr = psz_bind_addr;
socket_desc.i_bind_port = i_bind_port;
socket_desc.psz_server_addr = psz_server_addr;
socket_desc.i_server_port = i_server_port;
/* Find an appropriate network module */
p_network = module_Need( MODULE_CAPABILITY_NETWORK, psz_network,
&socket_desc );
if( p_network == NULL )
{
return( -1 );
}
module_Unneed( p_network );
p_access_data = p_input->p_access_data = malloc( sizeof(input_socket_t) );
if( p_access_data == NULL )
{
intf_ErrMsg( "input error: Out of memory" );
return( -1 );
}
p_access_data->i_handle = socket_desc.i_handle;
p_input->i_mtu = socket_desc.i_mtu;
return( 0 );
}
/*****************************************************************************
* UDPSetProgram: Do nothing
*****************************************************************************/
static int UDPSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
return( 0 );
}
......@@ -2,7 +2,7 @@
* dummy.c : dummy plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
* $Id: dummy.c,v 1.16 2002/02/27 03:47:56 sam Exp $
* $Id: dummy.c,v 1.17 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -32,7 +32,8 @@
/*****************************************************************************
* Capabilities defined in the other files.
*****************************************************************************/
void _M( input_getfunctions ) ( function_list_t * p_function_list );
void _M( access_getfunctions ) ( function_list_t * p_function_list );
void _M( demux_getfunctions ) ( function_list_t * p_function_list );
void _M( aout_getfunctions ) ( function_list_t * p_function_list );
void _M( vout_getfunctions ) ( function_list_t * p_function_list );
void _M( intf_getfunctions ) ( function_list_t * p_function_list );
......@@ -48,17 +49,19 @@ MODULE_INIT_START
SET_DESCRIPTION( "dummy functions module" )
/* Capability score set to 0 because we don't want to be spawned
* unless explicitly requested to */
ADD_CAPABILITY( AOUT, 1 )
ADD_CAPABILITY( VOUT, 1 )
ADD_CAPABILITY( INTF, 1 )
/* This one is ok. */
ADD_CAPABILITY( INPUT, 100 )
ADD_CAPABILITY( AOUT, 0 )
ADD_CAPABILITY( VOUT, 0 )
ADD_CAPABILITY( INTF, 0 )
ADD_CAPABILITY( ACCESS, 0 )
ADD_CAPABILITY( DEMUX, 0 )
ADD_SHORTCUT( "dummy" )
ADD_SHORTCUT( "vlc" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( input_getfunctions )( &p_module->p_functions->input );
_M( access_getfunctions )( &p_module->p_functions->access );
_M( demux_getfunctions )( &p_module->p_functions->demux );
_M( aout_getfunctions )( &p_module->p_functions->aout );
_M( vout_getfunctions )( &p_module->p_functions->vout );
_M( intf_getfunctions )( &p_module->p_functions->intf );
......
/*****************************************************************************
* input_dummy.c: dummy input plugin, to manage "vlc:***" special options
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: input_dummy.c,v 1.15 2002/02/15 13:32:53 sam Exp $
* Copyright (C) 2001, 2002 VideoLAN
* $Id: input_dummy.c,v 1.16 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -31,10 +31,6 @@
#include <videolan/vlc.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "interface.h"
#include "intf_playlist.h"
......@@ -46,25 +42,23 @@
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int DummyProbe ( struct input_thread_s * );
static void DummyInit ( struct input_thread_s * );
static void DummyOpen ( struct input_thread_s * );
static int DummyInit ( struct input_thread_s * );
static int DummyOpen ( struct input_thread_s * );
static void DummyClose ( struct input_thread_s * );
static void DummyEnd ( struct input_thread_s * );
static int DummyRead ( struct input_thread_s *, data_packet_t ** );
static int DummyDemux ( struct input_thread_s * );
/*****************************************************************************
* dummy_data_t: private input data
* access_sys_t: private input data
*****************************************************************************/
typedef struct dummy_data_s
struct demux_sys_s
{
/* The real command */
int i_command;
/* Used for the pause command */
mtime_t expiration;
} dummy_data_t;
};
#define COMMAND_NOP 0
#define COMMAND_QUIT 1
......@@ -75,48 +69,37 @@ typedef struct dummy_data_s
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list )
void _M( access_getfunctions )( function_list_t * p_function_list )
{
#define input p_function_list->functions.input
input.pf_probe = DummyProbe;
input.pf_init = DummyInit;
#define input p_function_list->functions.access
input.pf_open = DummyOpen;
input.pf_read = NULL;
input.pf_close = DummyClose;
input.pf_end = DummyEnd;
input.pf_set_program = NULL;
input.pf_set_area = NULL;
input.pf_read = DummyRead;
input.pf_demux = NULL;
input.pf_new_packet = NULL;
input.pf_new_pes = NULL;
input.pf_delete_packet = NULL;
input.pf_delete_pes = NULL;
input.pf_rewind = NULL;
input.pf_seek = NULL;
#undef input
}
/*****************************************************************************
* DummyProbe: verifies that the input is a vlc command
*****************************************************************************/
static int DummyProbe( input_thread_t *p_input )
void _M( demux_getfunctions )( function_list_t * p_function_list )
{
char *psz_name = p_input->p_source;
if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "vlc:", 4 ) )
{
/* If the user specified "vlc:" then it's probably a special command */
return 0;
}
return -1;
#define input p_function_list->functions.demux
input.pf_init = DummyInit;
input.pf_end = DummyEnd;
input.pf_demux = DummyDemux;
input.pf_rewind = NULL;
#undef input
}
/*****************************************************************************
* DummyOpen: open the target, ie. do nothing
*****************************************************************************/
static void DummyOpen( input_thread_t * p_input )
static int DummyOpen( input_thread_t * p_input )
{
p_input->stream.i_method = INPUT_METHOD_NONE;
/* Force dummy demux plug-in */
p_input->psz_demux = "vlc";
return( 0 );
}
/*****************************************************************************
......@@ -124,41 +107,28 @@ static void DummyOpen( input_thread_t * p_input )
*****************************************************************************/
static void DummyClose( input_thread_t * p_input )
{
;
}
/*****************************************************************************
* DummyOpen: initialize the target, ie. parse the command
* DummyInit: initialize the target, ie. parse the command
*****************************************************************************/
static void DummyInit( struct input_thread_s *p_input )
static int DummyInit( struct input_thread_s *p_input )
{
dummy_data_t* p_method;
char *psz_name = p_input->p_source;
int i_len = strlen( psz_name );
char * psz_name = p_input->psz_name;
int i_len = strlen( psz_name );
struct demux_sys_s * p_method;
int i_arg;
p_input->stream.b_seekable = 0;
if( ( i_len <= 4 ) || strncasecmp( psz_name, "vlc:", 4 ) )
{
/* If the command doesn't start with "vlc:" then it's not for us */
p_input->b_error = 1;
return;
}
/* We don't need the "vlc:" stuff any more */
psz_name += 4;
i_len -= 4;
p_method = malloc( sizeof( dummy_data_t ) );
p_method = malloc( sizeof( struct demux_sys_s ) );
if( p_method == NULL )
{
intf_ErrMsg( "input: out of memory" );
p_input->b_error = 1;
return;
return( -1 );
}
p_input->p_plugin_data = (void *)p_method;
p_input->p_demux_data = p_method;
p_input->stream.p_demux_data = NULL;
/* Check for a "vlc:nop" command */
......@@ -166,7 +136,7 @@ static void DummyInit( struct input_thread_s *p_input )
{
intf_WarnMsg( 2, "input: command `nop'" );
p_method->i_command = COMMAND_NOP;
return;
return( 0 );
}
/* Check for a "vlc:quit" command */
......@@ -174,7 +144,7 @@ static void DummyInit( struct input_thread_s *p_input )
{
intf_WarnMsg( 2, "input: command `quit'" );
p_method->i_command = COMMAND_QUIT;
return;
return( 0 );
}
/* Check for a "vlc:loop" command */
......@@ -182,7 +152,7 @@ static void DummyInit( struct input_thread_s *p_input )
{
intf_WarnMsg( 2, "input: command `loop'" );
p_method->i_command = COMMAND_LOOP;
return;
return( 0 );
}
/* Check for a "vlc:pause:***" command */
......@@ -192,14 +162,14 @@ static void DummyInit( struct input_thread_s *p_input )
intf_WarnMsg( 2, "input: command `pause %i'", i_arg );
p_method->i_command = COMMAND_PAUSE;
p_method->expiration = mdate() + (mtime_t)i_arg * (mtime_t)1000000;
return;
return( 0 );
}
intf_ErrMsg( "input error: unknown command `%s'", psz_name );
free( p_input->p_plugin_data );
free( p_input->p_demux_data );
p_input->b_error = 1;
return;
return( -1 );
}
/*****************************************************************************
......@@ -207,21 +177,20 @@ static void DummyInit( struct input_thread_s *p_input )
*****************************************************************************/
static void DummyEnd( struct input_thread_s *p_input )
{
free( p_input->p_plugin_data );
free( p_input->p_demux_data );
}
/*****************************************************************************
* DummyRead: do what the command says
* DummyDemux: do what the command says
*****************************************************************************/
static int DummyRead( struct input_thread_s *p_input, data_packet_t **pp_data )
static int DummyDemux( struct input_thread_s *p_input )
{
dummy_data_t* p_method = (dummy_data_t *)p_input->p_plugin_data;
struct demux_sys_s * p_method = p_input->p_demux_data;
switch( p_method->i_command )
{
case COMMAND_QUIT:
p_main->p_intf->b_die = 1;
p_input->b_eof = 1;
p_input->b_die = 1;
break;
case COMMAND_LOOP:
......@@ -246,8 +215,6 @@ static int DummyRead( struct input_thread_s *p_input, data_packet_t **pp_data )
break;
}
*pp_data = NULL;
return 0;
return 1;
}
......@@ -2,7 +2,7 @@
* dvd.c : DVD input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: dvd.c,v 1.20 2002/02/26 01:17:13 stef Exp $
* $Id: dvd.c,v 1.21 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -37,7 +37,8 @@
/*****************************************************************************
* Capabilities defined in the other files.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list );
void _M( access_getfunctions )( function_list_t * p_function_list );
void _M( demux_getfunctions )( function_list_t * p_function_list );
/*****************************************************************************
* Local prototypes.
......@@ -57,16 +58,17 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
#ifdef GOD_DAMN_DMCA
SET_DESCRIPTION( "DVD input module, uses libdvdcss if present" )
ADD_CAPABILITY( INPUT, 90 )
#else
SET_DESCRIPTION( "DVD input module, linked with libdvdcss" )
ADD_CAPABILITY( INPUT, 100 )
#endif
ADD_CAPABILITY( ACCESS, 0 )
ADD_CAPABILITY( DEMUX, 0 )
ADD_SHORTCUT( "dvd" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( input_getfunctions )( &p_module->p_functions->input );
_M( access_getfunctions )( &p_module->p_functions->access );
_M( demux_getfunctions )( &p_module->p_functions->demux );
#ifdef GOD_DAMN_DMCA
ProbeLibDVDCSS();
#endif
......
......@@ -2,7 +2,7 @@
* gtk_display.c: Gtk+ tools for main interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: gtk_display.c,v 1.15 2002/02/24 21:36:20 jobi Exp $
* $Id: gtk_display.c,v 1.16 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Stphane Borel <stef@via.ecp.fr>
......@@ -131,7 +131,7 @@ gint GtkModeManage( intf_thread_t * p_intf )
p_intf->p_sys->p_window ),
"label_status" );
gtk_label_set_text( GTK_LABEL( p_label ),
p_input_bank->pp_input[0]->p_source );
p_input_bank->pp_input[0]->psz_source );
break;
case INPUT_METHOD_DISC:
//intf_WarnMsg( 2, "intf info: disc method" );
......@@ -144,7 +144,7 @@ gint GtkModeManage( intf_thread_t * p_intf )
p_intf->p_sys->p_window ),
"network_address_label" );
gtk_label_set_text( GTK_LABEL( p_label ),
p_input_bank->pp_input[0]->p_source );
p_input_bank->pp_input[0]->psz_source );
p_channel = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT(
p_intf->p_sys->p_window ), "network_channel_box" ) );
if( config_GetIntVariable( INPUT_NETWORK_CHANNEL_VAR ) )
......@@ -164,7 +164,7 @@ gint GtkModeManage( intf_thread_t * p_intf )
p_intf->p_sys->p_window ),
"label_status" );
gtk_label_set_text( GTK_LABEL( p_label ),
p_input_bank->pp_input[0]->p_source );
p_input_bank->pp_input[0]->psz_source );
break;
}
......
mpeg_es_SOURCES = mpeg_es.c input_es.c
mpeg_ps_SOURCES = mpeg_ps.c input_ps.c
mpeg_ts_SOURCES = mpeg_ts.c input_ts.c
mpeg_es_SOURCES = mpeg_es.c
mpeg_ps_SOURCES = mpeg_ps.c
mpeg_ts_SOURCES = mpeg_ts.c
/*****************************************************************************
* input_es.c: Elementary Stream demux and packet management
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: input_es.c,v 1.13 2002/02/15 13:32:53 sam Exp $
*
* Author: 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 <errno.h>
#include <videolan/vlc.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#if defined( WIN32 )
# include <io.h> /* read() */
#else
# include <sys/uio.h> /* struct iovec */
#endif
#if defined( WIN32 )
# include "input_iovec.h"
#endif
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "input_es.h"
#include "debug.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int ESProbe ( struct input_thread_s * );
static int ESRead ( struct input_thread_s *, data_packet_t ** );
static void ESInit ( struct input_thread_s * );
static void ESEnd ( struct input_thread_s * );
static void ESSeek ( struct input_thread_s *, off_t );
static int ESSetProgram ( struct input_thread_s *, pgrm_descriptor_t * );
static void ESDemux ( struct input_thread_s *,
struct data_packet_s * );
/*****************************************************************************
* Declare a buffer manager
*****************************************************************************/
#define FLAGS BUFFERS_UNIQUE_SIZE
#define NB_LIFO 1
DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 150 );
DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 150 );
DECLARE_BUFFERS_TOIO( FLAGS, ES_PACKET_SIZE );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list )
{
#define input p_function_list->functions.input
input.pf_probe = ESProbe;
input.pf_init = ESInit;
input.pf_open = NULL;
input.pf_close = NULL;
input.pf_end = ESEnd;
input.pf_set_area = NULL;
input.pf_set_program = ESSetProgram;
input.pf_read = ESRead;
input.pf_demux = ESDemux;
input.pf_new_packet = input_NewPacket;
input.pf_new_pes = input_NewPES;
input.pf_delete_packet = input_DeletePacket;
input.pf_delete_pes = input_DeletePES;
input.pf_rewind = NULL;
input.pf_seek = ESSeek;
#undef input
}
/*
* Data reading functions
*/
/*****************************************************************************
* ESProbe: verifies that the stream is a ES stream
*****************************************************************************/
static int ESProbe( input_thread_t *p_input )
{
return 0;
}
/*****************************************************************************
* ESInit: initializes ES structures
*****************************************************************************/
static void ESInit( input_thread_t * p_input )
{
es_descriptor_t * p_es;
p_input->p_method_data = NULL;
if( (p_input->p_method_data = input_BuffersInit()) == NULL )
{
p_input->b_error = 1;
return;
}
/* FIXME : detect if InitStream failed */
input_InitStream( p_input, 0 );
input_AddProgram( p_input, 0, 0 );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
vlc_mutex_lock( &p_input->stream.stream_lock );
p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xE0, 0 );
p_es->i_stream_id = 0xE0;
p_es->i_type = MPEG1_VIDEO_ES;
p_es->i_cat = VIDEO_ES;
input_SelectES( p_input, p_es );
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
* ESEnd: frees unused data
*****************************************************************************/
static void ESEnd( input_thread_t * p_input )
{
input_BuffersEnd( p_input->p_method_data );
}
/*****************************************************************************
* ESRead: reads data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* packets.
*****************************************************************************/
static int ESRead( input_thread_t * p_input,
data_packet_t ** pp_data )
{
int i_read;
struct iovec p_iovec[ES_READ_ONCE];
data_packet_t * p_data;
/* Get iovecs */
*pp_data = p_data = input_BuffersToIO( p_input->p_method_data, p_iovec,
ES_READ_ONCE );
if ( p_data == NULL )
{
return( -1 );
}
i_read = readv( p_input->i_handle, p_iovec, ES_READ_ONCE );
if( i_read == -1 )
{
intf_ErrMsg( "input error: ES readv error" );
p_input->pf_delete_packet( p_input->p_method_data, p_data );
return( -1 );
}
p_input->stream.p_selected_area->i_tell += i_read;
i_read /= ES_PACKET_SIZE;
if( i_read != ES_READ_ONCE )
{
/* We got fewer packets than wanted. Give remaining packets
* back to the buffer allocator. */
int i_loop;
for( i_loop = 0; i_loop < i_read; i_loop++ )
{
pp_data = &(*pp_data)->p_next;
}
p_input->pf_delete_packet( p_input->p_method_data, *pp_data );
*pp_data = NULL;
}
return( i_read );
}
/*****************************************************************************
* ESSeek: changes the stream position indicator
*****************************************************************************/
static void ESSeek( input_thread_t * p_input, off_t i_position )
{
lseek( p_input->i_handle, i_position, SEEK_SET );
p_input->stream.p_selected_area->i_tell = i_position;
}
/*****************************************************************************
* ESSetProgram: Does nothing
*****************************************************************************/
static int ESSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
{
return( 0 );
}
/*****************************************************************************
* ESDemux: fakes a demultiplexer
*****************************************************************************/
static void ESDemux( input_thread_t * p_input, data_packet_t * p_data )
{
pes_packet_t * p_pes = p_input->pf_new_pes( p_input->p_method_data );
decoder_fifo_t * p_fifo =
p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo;
if( p_pes == NULL )
{
intf_ErrMsg("Out of memory");
p_input->b_error = 1;
return;
}
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->p_first = p_pes->p_last = p_data;
p_pes->i_nb_data = 1;
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
{
/* Wait for the decoder. */
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
| (input_ClockManageControl( p_input,
p_input->stream.p_selected_program,
(mtime_t)0 ) == PAUSE_S) )
{
intf_WarnMsg( 2, "synchro reinit" );
p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY;
p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
}
input_DecodePES( p_fifo, p_pes );
}
/*****************************************************************************
* input_ps.c: PS demux and packet management
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_ps.c,v 1.13 2002/02/24 20:51:10 gbazin Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Cyril Deguet <asmax@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 <stdio.h>
#include <string.h>
#include <errno.h>
#include <videolan/vlc.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include <fcntl.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "input_ps.h"
#include "debug.h"
/*****************************************************************************
* fseeko: fseeko replacement for BSDI.
*****************************************************************************/
#ifdef __bsdi__
int __sfseek __P(( FILE *, fpos_t, int ));
fpos_t __sftell __P(( FILE * ));
static __inline__ off_t fseeko( FILE *p_file, off_t i_offset, int i_pos )
{
return __sfseek( p_file, i_offset, i_pos );
}
#endif
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int PSProbe ( struct input_thread_s * );
static int PSRead ( struct input_thread_s *, data_packet_t ** );
static void PSInit ( struct input_thread_s * );
static void PSEnd ( struct input_thread_s * );
static int PSSetProgram ( struct input_thread_s * , pgrm_descriptor_t * );
static void PSSeek ( struct input_thread_s *, off_t );
/*****************************************************************************
* Declare a buffer manager
*****************************************************************************/
#define FLAGS BUFFERS_NOFLAGS
#define NB_LIFO 2
DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 300 );
DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 300 );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list )
{
#define input p_function_list->functions.input
input.pf_probe = PSProbe;
input.pf_init = PSInit;
input.pf_open = NULL;
input.pf_close = NULL;
input.pf_end = PSEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_set_area = NULL;
input.pf_set_program = PSSetProgram;
input.pf_read = PSRead;
input.pf_demux = input_DemuxPS;
input.pf_new_packet = input_NewPacket;
input.pf_new_pes = input_NewPES;
input.pf_delete_packet = input_DeletePacket;
input.pf_delete_pes = input_DeletePES;
input.pf_rewind = NULL;
input.pf_seek = PSSeek;
#undef input
}
/*
* Data reading functions
*/
/*****************************************************************************
* PSProbe: verifies that the stream is a PS stream
*****************************************************************************/
static int PSProbe( input_thread_t *p_input )
{
char * psz_name = p_input->p_source;
if( ( strlen(psz_name) > 5 ) && (!strncasecmp( psz_name, "file:", 5 )
|| !strncasecmp( psz_name, "http:", 5 )) )
{
/* If the user specified "file:" or "http:" then it's probably a
* PS file */
return 0;
}
/* Oh, we load it anyway */
return 0;
}
/*****************************************************************************
* PSInit: initializes PS structures
*****************************************************************************/
static void PSInit( input_thread_t * p_input )
{
if( (p_input->p_method_data = input_BuffersInit()) == NULL )
{
p_input->b_error = 1;
return;
}
if( p_input->p_stream == NULL )
{
/* Re-open the socket as a buffered FILE stream */
p_input->p_stream = fdopen( p_input->i_handle, "r" );
if( p_input->p_stream == NULL )
{
intf_ErrMsg( "Cannot open file (%s)", strerror(errno) );
input_BuffersEnd( p_input->p_method_data );
p_input->b_error = 1;
return;
}
}
/* FIXME : detect if InitStream failed */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program =
p_input->stream.pp_programs[0] ;
p_input->stream.p_new_program =
p_input->stream.pp_programs[0] ;
if( p_input->stream.b_seekable )
{
stream_ps_data_t * p_demux_data =
(stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
rewind( p_input->p_stream );
/* Pre-parse the stream to gather stream_descriptor_t. */
p_input->stream.pp_programs[0]->b_is_ok = 0;
p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
while( !p_input->b_die && !p_input->b_error
&& !p_demux_data->b_has_PSM )
{
int i_result;
data_packet_t * p_data;
data_packet_t * p_saved_data;
i_result = PSRead( p_input, &p_data );
p_saved_data = p_data;
while( p_data != NULL )
{
input_ParsePS( p_input, p_data );
p_data = p_data->p_next;
}
p_input->pf_delete_packet( p_input->p_method_data, p_saved_data );
if( i_result == 0 )
{
/* EOF */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
break;
}
else if( i_result == -1 )
{
p_input->b_error = 1;
break;
}
/* File too big. */
if( p_input->stream.p_selected_area->i_tell >
INPUT_PREPARSE_LENGTH )
{
break;
}
}
rewind( p_input->p_stream );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell = 0;
if( p_demux_data->b_has_PSM )
{
/* (The PSM decoder will care about spawning the decoders) */
p_input->stream.pp_programs[0]->b_is_ok = 1;
}
#ifdef AUTO_SPAWN
else
{
/* (We have to do it ourselves) */
int i_es;
/* FIXME: we should do multiple passes in case an audio type
* is not present */
for( i_es = 0;
i_es < p_input->stream.pp_programs[0]->i_es_number;
i_es++ )
{
#define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
switch( p_es->i_type )
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
input_SelectES( p_input, p_es );
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== (p_es->i_id & 0x1F) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !(p_es->i_id & 0x1F) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_MPEG:
input_SelectES( p_input, p_es );
}
break;
case AC3_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== ((p_es->i_id & 0xF00) >> 8) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !((p_es->i_id & 0xF00) >> 8) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_AC3:
input_SelectES( p_input, p_es );
}
break;
case DVD_SPU_ES:
if( config_GetIntVariable( INPUT_SUBTITLE_VAR )
== ((p_es->i_id & 0x1F00) >> 8) )
{
input_SelectES( p_input, p_es );
}
break;
case LPCM_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== ((p_es->i_id & 0x1F00) >> 8) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !((p_es->i_id & 0x1F00) >> 8) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_LPCM:
input_SelectES( p_input, p_es );
}
break;
}
}
}
#endif
if( p_main->b_stats )
{
input_DumpStream( p_input );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
else
{
/* The programs will be added when we read them. */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_FILE;
p_input->stream.pp_programs[0]->b_is_ok = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
}
/*****************************************************************************
* PSEnd: frees unused data
*****************************************************************************/
static void PSEnd( input_thread_t * p_input )
{
input_BuffersEnd( p_input->p_method_data );
}
/*****************************************************************************
* SafeRead: reads a chunk of stream and correctly detects errors
*****************************************************************************/
static __inline__ int SafeRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
int i_error;
while( fread( p_buffer, i_len, 1, p_input->p_stream ) != 1 )
{
if( feof( p_input->p_stream ) )
{
return( 0 );
}
if( (i_error = ferror( p_input->p_stream )) )
{
intf_ErrMsg( "Read failed (%s)", strerror(i_error) );
return( -1 );
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_len;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( i_len );
}
/*****************************************************************************
* PSRead: reads data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* packets.
*****************************************************************************/
static int PSRead( input_thread_t * p_input,
data_packet_t ** pp_data )
{
byte_t p_header[6];
data_packet_t * p_data;
size_t i_packet_size;
int i_packet, i_error;
*pp_data = NULL;
for( i_packet = 0; i_packet < PS_READ_ONCE; i_packet++ )
{
/* Read what we believe to be a packet header. */
if( (i_error = SafeRead( p_input, p_header, 4 )) <= 0 )
{
return( i_error );
}
if( (U32_AT(p_header) & 0xFFFFFF00) != 0x100L )
{
/* This is not the startcode of a packet. Read the stream
* until we find one. */
u32 i_startcode = U32_AT(p_header);
int i_dummy;
if( i_startcode )
{
/* It is common for MPEG-1 streams to pad with zeros
* (although it is forbidden by the recommendation), so
* don't bother everybody in this case. */
intf_WarnMsg( 3, "Garbage at input (%.8x)", i_startcode );
}
while( (i_startcode & 0xFFFFFF00) != 0x100L )
{
i_startcode <<= 8;
if( (i_dummy = getc( p_input->p_stream )) != EOF )
{
i_startcode |= i_dummy;
}
else
{
return( 0 );
}
}
/* Packet found. */
*(u32 *)p_header = U32_AT(&i_startcode);
}
/* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
if( U32_AT(p_header) != 0x1B9 )
{
/* The packet is at least 6 bytes long. */
if( (i_error = SafeRead( p_input, p_header + 4, 2 )) <= 0 )
{
return( i_error );
}
if( U32_AT(p_header) != 0x1BA )
{
/* That's the case for all packets, except pack header. */
i_packet_size = U16_AT(&p_header[4]);
}
else
{
/* Pack header. */
if( (p_header[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
i_packet_size = 8;
}
else if( (p_header[4] & 0xF0) == 0x20 )
{
/* MPEG-1 */
i_packet_size = 6;
}
else
{
intf_ErrMsg( "Unable to determine stream type" );
return( -1 );
}
}
}
else
{
/* System End Code */
i_packet_size = -2;
}
/* Fetch a packet of the appropriate size. */
p_data = p_input->pf_new_packet( p_input->p_method_data,
i_packet_size + 6 );
if( p_data == NULL )
{
intf_ErrMsg( "Out of memory" );
return( -1 );
}
if( U32_AT(p_header) != 0x1B9 )
{
/* Copy the header we already read. */
memcpy( p_data->p_demux_start, p_header, 6 );
/* Read the remaining of the packet. */
if( i_packet_size && (i_error =
SafeRead( p_input, p_data->p_demux_start + 6,
i_packet_size )) <= 0 )
{
p_input->pf_delete_packet( p_input->p_method_data, p_data );
return( i_error );
}
/* In MPEG-2 pack headers we still have to read stuffing bytes. */
if( U32_AT(p_header) == 0x1BA )
{
if( i_packet_size == 8 && (p_data->p_demux_start[13] & 0x7) != 0 )
{
/* MPEG-2 stuffing bytes */
byte_t p_garbage[8];
if( (i_error = SafeRead( p_input, p_garbage,
p_data->p_demux_start[13] & 0x7)) <= 0 )
{
p_input->pf_delete_packet( p_input->p_method_data,
p_data );
return( i_error );
}
}
}
}
else
{
/* Copy the small header. */
memcpy( p_data->p_demux_start, p_header, 4 );
}
/* Give the packet to the other input stages. */
*pp_data = p_data;
pp_data = &p_data->p_next;
}
return( i_packet + 1 );
}
/*****************************************************************************
* PSSetProgram: Does nothing since a PS Stream is mono-program
*****************************************************************************/
static int PSSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program)
{
return( 0 );
}
/*****************************************************************************
* PSSeek: changes the stream position indicator
*****************************************************************************/
static void PSSeek( input_thread_t * p_input, off_t i_position )
{
/* A little bourrin but should work for a while --Meuuh */
#if defined( WIN32 ) || defined( SYS_GNU0_2 )
fseek( p_input->p_stream, (long)i_position, SEEK_SET );
#else
fseeko( p_input->p_stream, i_position, SEEK_SET );
#endif
p_input->stream.p_selected_area->i_tell = i_position;
}
/*****************************************************************************
* input_ps.h: thread structure of the PS plugin
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ps.h,v 1.2 2001/12/27 03:47:09 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Cyril Deguet <asmax@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.
*****************************************************************************/
#define PS_READ_ONCE 50
/*****************************************************************************
* input_ts.c: TS demux and netlist management
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_ts.c,v 1.13 2002/02/15 13:32:53 sam Exp $
*
* Authors: Henri Fallon <henri@videolan.org>
*
* 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 <errno.h>
#include <videolan/vlc.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include <sys/types.h>
#if !defined( _MSC_VER )
# include <sys/time.h>
#endif
#ifdef SYS_NTO
# include <sys/select.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#if defined( WIN32 )
# include <io.h>
# include <winsock2.h>
#else
# include <sys/uio.h> /* struct iovec */
#endif
#if defined( WIN32 )
# include "input_iovec.h"
#endif
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "input_ts.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int TSProbe ( struct input_thread_s * );
static void TSInit ( struct input_thread_s * );
static void TSEnd ( struct input_thread_s * );
static int TSRead ( struct input_thread_s *, data_packet_t ** );
/*****************************************************************************
* Declare a buffer manager
*****************************************************************************/
#define FLAGS BUFFERS_UNIQUE_SIZE
#define NB_LIFO 1
DECLARE_BUFFERS_EMBEDDED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
DECLARE_BUFFERS_END( FLAGS, NB_LIFO );
DECLARE_BUFFERS_NEWPACKET( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPACKET( FLAGS, NB_LIFO, 1000 );
DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 150 );
DECLARE_BUFFERS_TOIO( FLAGS, TS_PACKET_SIZE );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list )
{
#define input p_function_list->functions.input
input.pf_probe = TSProbe;
input.pf_init = TSInit;
input.pf_open = NULL;
input.pf_close = NULL;
input.pf_end = TSEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_set_area = NULL;
input.pf_set_program = input_SetProgram;
input.pf_read = TSRead;
input.pf_demux = input_DemuxTS;
input.pf_new_packet = input_NewPacket;
input.pf_new_pes = input_NewPES;
input.pf_delete_packet = input_DeletePacket;
input.pf_delete_pes = input_DeletePES;
input.pf_rewind = NULL;
input.pf_seek = NULL;
#undef input
}
/*****************************************************************************
* TSProbe: verifies that the stream is a TS stream
*****************************************************************************/
static int TSProbe( input_thread_t * p_input )
{
char * psz_name = p_input->p_source;
if( ( strlen(psz_name) >= 10 && !strncasecmp( psz_name, "udpstream:", 10 ) )
|| ( strlen(psz_name) >= 4 && !strncasecmp( psz_name, "udp:", 4 ) ) )
{
/* If the user specified "udp:" then it's probably a network stream */
return 0;
}
if( ( strlen(psz_name) > 5 ) && !strncasecmp( psz_name, "file:", 5 ) )
{
/* If the user specified "file:" then it's probably a file */
psz_name += 5;
}
if( ( strlen(psz_name) > 3 ) &&
!strncasecmp( psz_name+strlen(psz_name)-3, ".ts", 3) )
{
/* If it is a ".ts" file it's probably a TS file ... */
return 0;
}
return -1;
}
/*****************************************************************************
* TSInit: initializes TS structures
*****************************************************************************/
static void TSInit( input_thread_t * p_input )
{
thread_ts_data_t * p_method;
es_descriptor_t * p_pat_es;
es_ts_data_t * p_demux_data;
stream_ts_data_t * p_stream_data;
/* Initialise structure */
p_method = malloc( sizeof( thread_ts_data_t ) );
if( p_method == NULL )
{
intf_ErrMsg( "TS input : Out of memory" );
p_input->b_error = 1;
return;
}
#if defined( WIN32 )
p_method->i_length = 0;
p_method->i_offset = 0;
#endif
p_input->p_plugin_data = (void *)p_method;
p_input->p_method_data = NULL;
if( (p_input->p_method_data = input_BuffersInit()) == NULL )
{
p_input->b_error = 1;
return;
}
/* Initialize the stream */
input_InitStream( p_input, sizeof( stream_ts_data_t ) );
p_input->stream.p_selected_area->i_tell = 0;
/* Init */
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
/* We'll have to catch the PAT in order to continue
* Then the input will catch the PMT and then the others ES
* The PAT es is indepedent of any program. */
p_pat_es = input_AddES( p_input, NULL,
0x00, sizeof( es_ts_data_t ) );
p_demux_data=(es_ts_data_t *)p_pat_es->p_demux_data;
p_demux_data->b_psi = 1;
p_demux_data->i_psi_type = PSI_IS_PAT;
p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
p_demux_data->p_psi_section->b_is_complete = 1;
}
/*****************************************************************************
* TSEnd: frees unused data
*****************************************************************************/
static void TSEnd( input_thread_t * p_input )
{
es_descriptor_t * p_pat_es;
p_pat_es = input_FindES( p_input, 0x00 );
if( p_pat_es != NULL )
input_DelES( p_input, p_pat_es );
free(p_input->p_plugin_data);
input_BuffersEnd( p_input->p_method_data );
}
/*****************************************************************************
* TSRead: reads data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* packets.
*****************************************************************************/
static int TSRead( input_thread_t * p_input,
data_packet_t ** pp_data )
{
thread_ts_data_t * p_method;
int i_read = 0, i_loop;
int i_data = 1;
struct iovec p_iovec[TS_READ_ONCE];
data_packet_t * p_data;
struct timeval timeout;
/* Init */
p_method = ( thread_ts_data_t * )p_input->p_plugin_data;
/* Initialize file descriptor set */
FD_ZERO( &(p_method->fds) );
FD_SET( p_input->i_handle, &(p_method->fds) );
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
/* Fill if some data is available */
#if defined( WIN32 )
if ( ! p_input->stream.b_pace_control )
#endif
{
i_data = select( p_input->i_handle + 1, &p_method->fds,
NULL, NULL, &timeout );
}
if( i_data == -1 )
{
intf_ErrMsg( "input error: TS select error (%s)", strerror(errno) );
return( -1 );
}
if( i_data )
{
/* Get iovecs */
*pp_data = p_data = input_BuffersToIO( p_input->p_method_data, p_iovec,
TS_READ_ONCE );
if ( p_data == NULL )
{
return( -1 );
}
#if defined( WIN32 )
if( p_input->stream.b_pace_control )
{
i_read = readv( p_input->i_handle, p_iovec, TS_READ_ONCE );
}
else
{
i_read = readv_network( p_input->i_handle, p_iovec,
TS_READ_ONCE, p_method );
}
#else
i_read = readv( p_input->i_handle, p_iovec, TS_READ_ONCE );
/* Shouldn't happen, but it does - at least under Linux */
if( (i_read == -1) && ( (errno == EAGAIN) || (errno = EWOULDBLOCK) ) )
{
/* just ignore that error */
intf_ErrMsg( "input error: 0 bytes read" );
i_read = 0;
}
#endif
/* Error */
if( i_read == -1 )
{
intf_ErrMsg( "input error: TS readv error" );
p_input->pf_delete_packet( p_input->p_method_data, p_data );
return( -1 );
}
p_input->stream.p_selected_area->i_tell += i_read;
i_read /= TS_PACKET_SIZE;
/* Check correct TS header */
for( i_loop = 0; i_loop < i_read; i_loop++ )
{
if( (*pp_data)->p_demux_start[0] != 0x47 )
{
intf_ErrMsg( "input error: bad TS packet (starts with "
"0x%.2x, should be 0x47)",
p_data->p_demux_start[0] );
}
pp_data = &(*pp_data)->p_next;
}
if( i_read != TS_READ_ONCE )
{
/* Delete remaining packets */
p_input->pf_delete_packet( p_input->p_method_data, *pp_data );
}
}
*pp_data = NULL;
return( i_read );
}
/*****************************************************************************
* input_ts.h: structures of the input not exported to other modules
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ts.h,v 1.5 2001/12/30 07:09:55 sam Exp $
*
* Authors: Henri Fallon <henri@via.ecp.fr>
* Boris Dors <babal@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.
*****************************************************************************/
/* UDP packets contain 1500 bytes, that is 7 TS packets */
#define TS_READ_ONCE 7
#ifdef WIN32
# define BUFFER_SIZE (7 * TS_PACKET_SIZE)
#endif
/*****************************************************************************
* thread_ts_data_t: private input data
*****************************************************************************/
typedef struct thread_ts_data_s
{
/* The file descriptor we select() on */
fd_set fds;
#if defined( WIN32 )
char p_buffer[ BUFFER_SIZE ]; /* temporary buffer for readv_network */
int i_length; /* length of the UDP packet */
int i_offset; /* number of bytes already read from the buffer */
#endif
} thread_ts_data_t;
/*****************************************************************************
* network readv() replacement for iovec-impaired C libraries
*****************************************************************************/
#if defined(WIN32)
static __inline__ int read_network( int i_fd, char * p_base,
thread_ts_data_t *p_sys, int i_len )
{
int i_bytes;
if( p_sys->i_offset >= p_sys->i_length )
{
p_sys->i_length = recv( i_fd, p_sys->p_buffer, BUFFER_SIZE, 0 );
if ( p_sys->i_length == SOCKET_ERROR )
{
return -1;
}
p_sys->i_offset = 0;
}
if( i_len <= p_sys->i_length - p_sys->i_offset )
{
i_bytes = i_len;
}
else
{
i_bytes = p_sys->i_length - p_sys->i_offset;
}
FAST_MEMCPY( p_base, p_sys->p_buffer + p_sys->i_offset, i_bytes );
p_sys->i_offset += i_bytes;
return i_bytes;
}
static __inline__ int readv_network( int i_fd, struct iovec *p_iovec,
int i_count, thread_ts_data_t *p_sys )
{
int i_index, i_len, i_total = 0;
u8 *p_base;
for( i_index = i_count; i_index; i_index-- )
{
register signed int i_bytes;
i_len = p_iovec->iov_len;
p_base = p_iovec->iov_base;
/* Loop is unrolled one time to spare the (i_bytes <= 0) test */
if( i_len > 0 )
{
i_bytes = read_network( i_fd, p_base, p_sys, i_len );
if( ( i_total == 0 ) && ( i_bytes < 0 ) )
{
return -1;
}
if( i_bytes <= 0 )
{
return i_total;
}
i_len -= i_bytes; i_total += i_bytes; p_base += i_bytes;
while( i_len > 0 )
{
i_bytes = read_network( i_fd, p_base, p_sys, i_len );
if( i_bytes <= 0 )
{
return i_total;
}
i_len -= i_bytes; i_total += i_bytes; p_base += i_bytes;
}
}
p_iovec++;
}
return i_total;
}
#endif
......@@ -2,7 +2,7 @@
* mpeg_es.c : Elementary Stream input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: mpeg_es.c,v 1.3 2002/02/15 13:32:53 sam Exp $
* $Id: mpeg_es.c,v 1.4 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -26,13 +26,30 @@
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <errno.h>
#include <videolan/vlc.h>
#include <sys/types.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*****************************************************************************
* Constants
*****************************************************************************/
#define ES_PACKET_SIZE 65536
#define MAX_PACKETS_IN_FIFO 3
/*****************************************************************************
* Capabilities defined in the other files.
* Local prototypes
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list );
static void input_getfunctions( function_list_t * p_function_list );
static int ESDemux ( struct input_thread_s * );
static int ESInit ( struct input_thread_s * );
static void ESEnd ( struct input_thread_s * );
/*****************************************************************************
* Build configuration tree.
......@@ -41,15 +58,165 @@ MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "ISO 13818-1 MPEG Elementary Stream input" )
ADD_CAPABILITY( INPUT, 5 )
SET_DESCRIPTION( "ISO 13818-2 MPEG Elementary Stream input" )
ADD_CAPABILITY( DEMUX, 150 )
ADD_SHORTCUT( "es" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( input_getfunctions )( &p_module->p_functions->input );
input_getfunctions( &p_module->p_functions->demux );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.demux
input.pf_init = ESInit;
input.pf_end = ESEnd;
input.pf_demux = ESDemux;
input.pf_rewind = NULL;
#undef input
}
/*
* Data reading functions
*/
/*****************************************************************************
* ESInit: initializes ES structures
*****************************************************************************/
static int ESInit( input_thread_t * p_input )
{
es_descriptor_t * p_es;
byte_t * p_peek;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
/* Improve speed. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
}
/* Have a peep at the show. */
if( input_Peek( p_input, &p_peek, 4 ) < 4 )
{
/* Stream shorter than 4 bytes... */
intf_ErrMsg( "input error: cannot peek() (mpeg_es)" );
return( -1 );
}
if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
{
if( p_input->psz_demux && strncmp( p_input->psz_demux, "es", 3 ) )
{
/* User forced */
intf_ErrMsg( "input error: this doesn't seem like an MPEG stream, continuing" );
}
else
{
intf_WarnMsg( 2, "input: ES plug-in discarded (no startcode)" );
return( -1 );
}
}
else if( *(p_peek + 3) > 0xb9 )
{
if( p_input->psz_demux && strncmp( p_input->psz_demux, "es", 3 ) )
{
/* User forced */
intf_ErrMsg( "input error: this seems to be a system stream (PS plug-in ?), but continuing" );
}
else
{
intf_WarnMsg( 2, "input: ES plug-in discarded (system startcode)" );
return( -1 );
}
}
if( input_InitStream( p_input, 0 ) == -1 )
{
return( -1 );
}
input_AddProgram( p_input, 0, 0 );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
vlc_mutex_lock( &p_input->stream.stream_lock );
p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xE0, 0 );
p_es->i_stream_id = 0xE0;
p_es->i_type = MPEG1_VIDEO_ES;
p_es->i_cat = VIDEO_ES;
input_SelectES( p_input, p_es );
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( 0 );
}
/*****************************************************************************
* ESEnd: frees unused data
*****************************************************************************/
static void ESEnd( input_thread_t * p_input )
{
}
/*****************************************************************************
* ESDemux: reads and demuxes data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, 1 otherwise
*****************************************************************************/
static int ESDemux( input_thread_t * p_input )
{
ssize_t i_read;
decoder_fifo_t * p_fifo =
p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo;
pes_packet_t * p_pes;
data_packet_t * p_data;
i_read = input_SplitBuffer( p_input, &p_data, ES_PACKET_SIZE );
if ( i_read <= 0 )
{
return( i_read );
}
p_pes = input_NewPES( p_input->p_method_data );
if( p_pes == NULL )
{
intf_ErrMsg("Out of memory");
input_DeletePacket( p_input->p_method_data, p_data );
return( -1 );
}
p_pes->i_rate = p_input->stream.control.i_rate;
p_pes->p_first = p_pes->p_last = p_data;
p_pes->i_nb_data = 1;
vlc_mutex_lock( &p_fifo->data_lock );
if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
{
/* Wait for the decoder. */
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
vlc_mutex_unlock( &p_fifo->data_lock );
if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
| (input_ClockManageControl( p_input,
p_input->stream.p_selected_program,
(mtime_t)0 ) == PAUSE_S) )
{
intf_WarnMsg( 2, "synchro reinit" );
p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY;
p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
}
input_DecodePES( p_fifo, p_pes );
return( 1 );
}
......@@ -2,7 +2,7 @@
* mpeg_ps.c : Program Stream input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: mpeg_ps.c,v 1.3 2002/02/15 13:32:53 sam Exp $
* $Id: mpeg_ps.c,v 1.4 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -26,13 +26,29 @@
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <errno.h>
#include <videolan/vlc.h>
#include <sys/types.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*****************************************************************************
* Capabilities defined in the other files.
* Constants
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list );
#define PS_READ_ONCE 50
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list );
static int PSDemux ( struct input_thread_s * );
static int PSInit ( struct input_thread_s * );
static void PSEnd ( struct input_thread_s * );
/*****************************************************************************
* Build configuration tree.
......@@ -42,14 +58,371 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "ISO 13818-1 MPEG Program Stream input" )
ADD_CAPABILITY( INPUT, 10 )
ADD_CAPABILITY( DEMUX, 100 )
ADD_SHORTCUT( "ps" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( input_getfunctions )( &p_module->p_functions->input );
input_getfunctions( &p_module->p_functions->demux );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.demux
input.pf_init = PSInit;
input.pf_end = PSEnd;
input.pf_demux = PSDemux;
input.pf_rewind = NULL;
#undef input
}
/*
* Data reading functions
*/
/*****************************************************************************
* PSRead: reads one PS packet
*****************************************************************************/
#define PEEK( SIZE ) \
i_error = input_Peek( p_input, &p_peek, SIZE ); \
if( i_error == -1 ) \
{ \
return( -1 ); \
} \
else if( i_error < SIZE ) \
{ \
/* EOF */ \
return( 0 ); \
}
static __inline__ ssize_t PSRead( input_thread_t * p_input,
data_packet_t ** pp_data )
{
byte_t * p_peek;
size_t i_packet_size;
ssize_t i_error, i_read;
/* Read what we believe to be a packet header. */
PEEK( 4 );
if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
{
if( *p_peek || *(p_peek + 1) || *(p_peek + 2) )
{
/* It is common for MPEG-1 streams to pad with zeros
* (although it is forbidden by the recommendation), so
* don't bother everybody in this case. */
intf_WarnMsg( 3, "input warning: garbage at input (0x%x%x%x%x)",
*p_peek, *(p_peek + 1), *(p_peek + 2), *(p_peek + 3) );
}
/* This is not the startcode of a packet. Read the stream
* until we find one. */
while( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
{
p_input->p_current_data++;
PEEK( 4 );
}
/* Packet found. */
}
/* 0x1B9 == SYSTEM_END_CODE, it is only 4 bytes long. */
if( p_peek[3] != 0xB9 )
{
/* The packet is at least 6 bytes long. */
PEEK( 6 );
if( p_peek[3] != 0xBA )
{
/* That's the case for all packets, except pack header. */
i_packet_size = (p_peek[4] << 8) | p_peek[5];
}
else
{
/* Pack header. */
if( (p_peek[4] & 0xC0) == 0x40 )
{
/* MPEG-2 */
i_packet_size = 8;
}
else if( (p_peek[4] & 0xF0) == 0x20 )
{
/* MPEG-1 */
i_packet_size = 6;
}
else
{
intf_ErrMsg( "Unable to determine stream type" );
return( -1 );
}
}
}
else
{
/* System End Code */
i_packet_size = -2;
}
/* Fetch a packet of the appropriate size. */
i_read = input_SplitBuffer( p_input, pp_data, i_packet_size + 6 );
if( i_read <= 0 )
{
return( i_read );
}
/* In MPEG-2 pack headers we still have to read stuffing bytes. */
if( ((*pp_data)->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
{
size_t i_stuffing = ((*pp_data)->p_demux_start[13] & 0x7);
/* Force refill of the input buffer - though we don't care
* about p_peek. Please note that this is unoptimized. */
PEEK( i_stuffing );
p_input->p_current_data += i_stuffing;
}
return( 1 );
}
/*****************************************************************************
* PSInit: initializes PS structures
*****************************************************************************/
static int PSInit( input_thread_t * p_input )
{
byte_t * p_peek;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
/* Improve speed. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
}
/* Have a peep at the show. */
if( input_Peek( p_input, &p_peek, 4 ) < 4 )
{
/* Stream shorter than 4 bytes... */
intf_ErrMsg( "input error: cannot peek() (mpeg_ps)" );
return( -1 );
}
if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
{
if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
{
/* User forced */
intf_ErrMsg( "input error: this doesn't seem like an MPEG stream, continuing" );
}
else
{
intf_WarnMsg( 2, "input: PS plug-in discarded (no startcode)" );
return( -1 );
}
}
else if( *(p_peek + 3) <= 0xb9 )
{
if( p_input->psz_demux && strncmp( p_input->psz_demux, "ps", 3 ) )
{
/* User forced */
intf_ErrMsg( "input error: this seems to be an elementary stream (ES plug-in ?),");
intf_ErrMsg( "but continuing" );
}
else
{
intf_WarnMsg( 2, "input: PS plug-in discarded (ES startcode)" );
return( -1 );
}
}
if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 )
{
return( -1 );
}
input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program =
p_input->stream.pp_programs[0] ;
p_input->stream.p_new_program =
p_input->stream.pp_programs[0] ;
if( p_input->stream.b_seekable )
{
stream_ps_data_t * p_demux_data =
(stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data;
/* Pre-parse the stream to gather stream_descriptor_t. */
p_input->stream.pp_programs[0]->b_is_ok = 0;
p_demux_data->i_PSM_version = EMPTY_PSM_VERSION;
while( !p_input->b_die && !p_input->b_error
&& !p_demux_data->b_has_PSM )
{
ssize_t i_result;
data_packet_t * p_data;
i_result = PSRead( p_input, &p_data );
if( i_result == 0 )
{
/* EOF */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.pp_programs[0]->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
break;
}
else if( i_result == -1 )
{
p_input->b_error = 1;
break;
}
input_ParsePS( p_input, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
/* File too big. */
if( p_input->stream.p_selected_area->i_tell >
INPUT_PREPARSE_LENGTH )
{
break;
}
}
p_input->pf_seek( p_input, (off_t)0 );
input_AccessReinit( p_input );
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_demux_data->b_has_PSM )
{
/* (The PSM decoder will care about spawning the decoders) */
p_input->stream.pp_programs[0]->b_is_ok = 1;
}
#ifdef AUTO_SPAWN
else
{
/* (We have to do it ourselves) */
int i_es;
/* FIXME: we should do multiple passes in case an audio type
* is not present */
for( i_es = 0;
i_es < p_input->stream.pp_programs[0]->i_es_number;
i_es++ )
{
#define p_es p_input->stream.pp_programs[0]->pp_es[i_es]
switch( p_es->i_type )
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
input_SelectES( p_input, p_es );
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== (p_es->i_id & 0x1F) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !(p_es->i_id & 0x1F) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_MPEG:
input_SelectES( p_input, p_es );
}
break;
case AC3_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== ((p_es->i_id & 0xF00) >> 8) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !((p_es->i_id & 0xF00) >> 8) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_AC3:
input_SelectES( p_input, p_es );
}
break;
case DVD_SPU_ES:
if( config_GetIntVariable( INPUT_SUBTITLE_VAR )
== ((p_es->i_id & 0x1F00) >> 8) )
{
input_SelectES( p_input, p_es );
}
break;
case LPCM_AUDIO_ES:
if( config_GetIntVariable( INPUT_CHANNEL_VAR )
== ((p_es->i_id & 0x1F00) >> 8) ||
( config_GetIntVariable( INPUT_CHANNEL_VAR ) < 0
&& !((p_es->i_id & 0x1F00) >> 8) ) )
switch( config_GetIntVariable( INPUT_AUDIO_VAR ) )
{
case -1:
case REQUESTED_LPCM:
input_SelectES( p_input, p_es );
}
break;
}
}
}
#endif
if( p_main->b_stats )
{
input_DumpStream( p_input );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
else
{
/* The programs will be added when we read them. */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_FILE;
p_input->stream.pp_programs[0]->b_is_ok = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
return( 0 );
}
/*****************************************************************************
* PSEnd: frees unused data
*****************************************************************************/
static void PSEnd( input_thread_t * p_input )
{
}
/*****************************************************************************
* PSDemux: reads and demuxes data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* packets.
*****************************************************************************/
static int PSDemux( input_thread_t * p_input )
{
int i;
for( i = 0; i < PS_READ_ONCE; i++ )
{
data_packet_t * p_data;
ssize_t i_result;
i_result = PSRead( p_input, &p_data );
if( i_result <= 0 )
{
return( i_result );
}
input_DemuxPS( p_input, p_data );
}
return( i );
}
......@@ -2,7 +2,7 @@
* mpeg_ts.c : Transport Stream input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: mpeg_ts.c,v 1.3 2001/12/31 04:53:33 sam Exp $
* $Id: mpeg_ts.c,v 1.4 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Henri Fallon <henri@via.ecp.fr>
*
......@@ -24,15 +24,31 @@
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <videolan/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*****************************************************************************
* Capabilities defined in the other files.
* Constants
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list );
#define TS_READ_ONCE 200
#define TS_PACKET_SIZE 188
#define TS_SYNC_CODE 0x47
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list );
static int TSInit ( struct input_thread_s * );
static void TSEnd ( struct input_thread_s * );
static int TSDemux ( struct input_thread_s * );
/*****************************************************************************
* Build configuration tree.
......@@ -42,14 +58,170 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "ISO 13818-1 MPEG Transport Stream input" )
ADD_CAPABILITY( INPUT, 150 )
ADD_CAPABILITY( DEMUX, 160 )
ADD_SHORTCUT( "ts" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( input_getfunctions )( &p_module->p_functions->input );
input_getfunctions( &p_module->p_functions->demux );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.demux
input.pf_init = TSInit;
input.pf_end = TSEnd;
input.pf_demux = TSDemux;
input.pf_rewind = NULL;
#undef input
}
/*****************************************************************************
* TSInit: initializes TS structures
*****************************************************************************/
static int TSInit( input_thread_t * p_input )
{
es_descriptor_t * p_pat_es;
es_ts_data_t * p_demux_data;
stream_ts_data_t * p_stream_data;
byte_t * p_peek;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
/* Improve speed. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
}
/* Have a peep at the show. */
if( input_Peek( p_input, &p_peek, 1 ) < 1 )
{
intf_ErrMsg( "input error: cannot peek() (mpeg_ts)" );
return( -1 );
}
if( *p_peek != TS_SYNC_CODE )
{
if( p_input->psz_demux && strncmp( p_input->psz_demux, "ts", 3 ) )
{
/* User forced */
intf_ErrMsg( "input error: this doesn't seem like a TS stream, continuing" );
}
else
{
intf_WarnMsg( 2, "input: TS plug-in discarded (no sync)" );
return( -1 );
}
}
/* Adapt the bufsize for our only use. */
if( p_input->i_mtu != 0 )
{
/* Have minimum granularity to avoid bottlenecks at the input level. */
p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE;
}
if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
{
return( -1 );
}
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
/* We'll have to catch the PAT in order to continue
* Then the input will catch the PMT and then the others ES
* The PAT es is indepedent of any program. */
p_pat_es = input_AddES( p_input, NULL,
0x00, sizeof( es_ts_data_t ) );
p_demux_data = (es_ts_data_t *)p_pat_es->p_demux_data;
p_demux_data->b_psi = 1;
p_demux_data->i_psi_type = PSI_IS_PAT;
p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
p_demux_data->p_psi_section->b_is_complete = 1;
return( 0 );
}
/*****************************************************************************
* TSEnd: frees unused data
*****************************************************************************/
static void TSEnd( input_thread_t * p_input )
{
}
/*****************************************************************************
* TSDemux: reads and demuxes data packets
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* packets.
*****************************************************************************/
#define PEEK( SIZE ) \
i_error = input_Peek( p_input, &p_peek, SIZE ); \
if( i_error == -1 ) \
{ \
return( -1 ); \
} \
else if( i_error < SIZE ) \
{ \
/* EOF */ \
return( 0 ); \
}
static int TSDemux( input_thread_t * p_input )
{
int i_read_once = (p_input->i_mtu ?
p_input->i_bufsize / TS_PACKET_SIZE :
TS_READ_ONCE);
int i;
for( i = 0; i < i_read_once; i++ )
{
data_packet_t * p_data;
ssize_t i_read, i_error;
byte_t * p_peek;
PEEK( 1 );
if( *p_peek != TS_SYNC_CODE )
{
intf_WarnMsg( 3, "input warning: garbage at input (%x)", *p_peek );
if( p_input->i_mtu )
{
/* Try to resync on next packet. */
PEEK( TS_PACKET_SIZE );
p_input->p_current_data += TS_PACKET_SIZE;
}
else
{
/* Move forward until we find 0x47 (and hope it's the good
* one... FIXME) */
while( *p_peek != TS_SYNC_CODE )
{
p_input->p_current_data++;
PEEK( 1 );
}
}
}
i_read = input_SplitBuffer( p_input, &p_data, TS_PACKET_SIZE );
if( i_read <= 0 )
{
return( i_read );
}
input_DemuxTS( p_input, p_data );
}
return( i_read_once );
}
.dep
*.lo
*.o.*
*.lo.*
ipv4_SOURCES = ipv4.c
/*****************************************************************************
* ipv4.c: IPv4 network abstraction layer
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: ipv4.c,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* 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 <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
# include <netinet/in.h>
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
# endif
#endif
#include "network.h"
/* Default MTU used for UDP socket. FIXME: we should issue some ioctl()
* call to get that value from the interface driver. */
#define DEFAULT_MTU 1500
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void getfunctions( function_list_t * );
static int NetworkOpen( struct network_socket_s * );
/*****************************************************************************
* Build configuration tree.
*****************************************************************************/
MODULE_CONFIG_START
MODULE_CONFIG_STOP
MODULE_INIT_START
SET_DESCRIPTION( "IPv4 network abstraction layer" )
ADD_CAPABILITY( NETWORK, 50 )
ADD_SHORTCUT( "ipv4" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
getfunctions( &p_module->p_functions->network );
MODULE_ACTIVATE_STOP
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
static void getfunctions( function_list_t * p_function_list )
{
#define f p_function_list->functions.network
f.pf_open = NetworkOpen;
#undef f
}
/*****************************************************************************
* BuildAddr: utility function to build a struct sockaddr_in
*****************************************************************************/
static int BuildAddr( struct sockaddr_in * p_socket,
const char * psz_address, int i_port )
{
/* Reset struct */
memset( p_socket, 0, sizeof( struct sockaddr_in ) );
p_socket->sin_family = AF_INET; /* family */
p_socket->sin_port = htons( i_port );
if( psz_address == NULL )
{
p_socket->sin_addr.s_addr = INADDR_ANY;
}
else
{
struct hostent * p_hostent;
/* Try to convert address directly from in_addr - this will work if
* psz_address is dotted decimal. */
#ifdef HAVE_ARPA_INET_H
if( !inet_aton( psz_address, &p_socket->sin_addr ) )
#else
if( (p_socket->sin_addr.s_addr = inet_addr( psz_address )) == -1 )
#endif
{
/* We have a fqdn, try to find its address */
if ( (p_hostent = gethostbyname( psz_address )) == NULL )
{
intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_address );
return( -1 );
}
/* Copy the first address of the host in the socket address */
memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
p_hostent->h_length );
}
}
return( 0 );
}
/*****************************************************************************
* OpenUDP: open a UDP socket
*****************************************************************************
* psz_bind_addr, i_bind_port : address and port used for the bind()
* system call. If psz_bind_addr == NULL, the socket is bound to
* INADDR_ANY and broadcast reception is enabled. If i_bind_port == 0,
* 1234 is used. If psz_bind_addr is a multicast (class D) address,
* join the multicast group.
* psz_server_addr, i_server_port : address and port used for the connect()
* system call. It can avoid receiving packets from unauthorized IPs.
* Its use leads to great confusion and is currently discouraged.
* This function returns -1 in case of error.
*****************************************************************************/
static int OpenUDP( network_socket_t * p_socket )
{
char * psz_bind_addr = p_socket->psz_bind_addr;
int i_bind_port = p_socket->i_bind_port;
char * psz_server_addr = p_socket->psz_server_addr;
int i_server_port = p_socket->i_server_port;
int i_handle, i_opt, i_opt_size;
struct sockaddr_in sock;
if( i_bind_port == 0 )
{
i_bind_port = config_GetIntVariable( INPUT_PORT_VAR );
}
/* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
* protocol */
if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 )
{
intf_ErrMsg( "ipv4 error: cannot create socket (%s)", strerror(errno) );
return( -1 );
}
/* We may want to reuse an already used socket */
i_opt = 1;
if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_ErrMsg( "ipv4 error: cannot configure socket (SO_REUSEADDR: %s)",
strerror(errno));
close( i_handle );
return( -1 );
}
/* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
* packet loss caused by scheduling problems */
i_opt = 0x80000;
if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_WarnMsg( 1,
"ipv4 warning: cannot configure socket (SO_RCVBUF: %s)",
strerror(errno));
}
/* Check if we really got what we have asked for, because Linux, etc.
* will silently limit the max buffer size to net.core.rmem_max which
* is typically only 65535 bytes */
i_opt = 0;
i_opt_size = sizeof( i_opt );
if( getsockopt( i_handle, SOL_SOCKET, SO_RCVBUF,
(void*) &i_opt, &i_opt_size ) == -1 )
{
intf_WarnMsg( 1, "ipv4 warning: cannot query socket (SO_RCVBUF: %s)",
strerror(errno));
}
else if( i_opt < 0x80000 )
{
intf_WarnMsg( 1, "ipv4 warning: socket buffer size is 0x%x"
" instead of 0x%x", i_opt, 0x80000 );
}
/* Build the local socket */
if ( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 )
{
close( i_handle );
return( -1 );
}
/* Bind it */
if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
{
intf_ErrMsg( "ipv4 error: cannot bind socket (%s)", strerror(errno) );
close( i_handle );
return( -1 );
}
/* Allow broadcast reception if we bound on INADDR_ANY */
if( psz_bind_addr == NULL )
{
i_opt = 1;
if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST,
(void*) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_WarnMsg( 1,
"ipv4 warning: cannot configure socket (SO_BROADCAST: %s)",
strerror(errno));
}
}
/* Join the multicast group if the socket is a multicast address */
#ifndef IN_MULTICAST
# define IN_MULTICAST(a) IN_CLASSD(a)
#endif
if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
{
struct ip_mreq imr;
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char*)&imr, sizeof(struct ip_mreq) ) == -1 )
{
intf_ErrMsg( "ipv4 error: failed to join IP multicast group (%s)",
strerror(errno) );
close( i_handle );
return( -1 );
}
}
if( psz_server_addr != NULL )
{
/* Build socket for remote connection */
if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
{
intf_ErrMsg( "ipv4 error: cannot build remote address" );
close( i_handle );
return( -1 );
}
/* Connect the socket */
if( connect( i_handle, (struct sockaddr *) &sock,
sizeof( sock ) ) == (-1) )
{
intf_ErrMsg( "ipv4 error: cannot connect socket (%s)",
strerror(errno) );
close( i_handle );
return( -1 );
}
}
p_socket->i_handle = i_handle;
p_socket->i_mtu = DEFAULT_MTU;
return( 0 );
}
/*****************************************************************************
* OpenTCP: open a TCP socket
*****************************************************************************
* psz_server_addr, i_server_port : address and port used for the connect()
* system call. If i_server_port == 0, 80 is used.
* Other parameters are ignored.
* This function returns -1 in case of error.
*****************************************************************************/
static int OpenTCP( network_socket_t * p_socket )
{
char * psz_server_addr = p_socket->psz_server_addr;
int i_server_port = p_socket->i_server_port;
int i_handle;
struct sockaddr_in sock;
if( i_server_port == 0 )
{
i_server_port = 80;
}
/* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
* protocol */
if( (i_handle = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
{
intf_ErrMsg( "ipv4 error: cannot create socket (%s)", strerror(errno) );
return( -1 );
}
/* Build remote address */
if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
{
close( i_handle );
return( -1 );
}
/* Connect the socket */
if( connect( i_handle, (struct sockaddr *) &sock,
sizeof( sock ) ) == (-1) )
{
intf_ErrMsg( "ipv4 error: cannot connect socket (%s)",
strerror(errno) );
close( i_handle );
return( -1 );
}
p_socket->i_handle = i_handle;
p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
return( 0 );
}
/*****************************************************************************
* NetworkOpen: wrapper around OpenUDP and OpenTCP
*****************************************************************************/
static int NetworkOpen( network_socket_t * p_socket )
{
if( p_socket->i_type == NETWORK_UDP )
{
return OpenUDP( p_socket );
}
else
{
return OpenTCP( p_socket );
}
}
......@@ -4,9 +4,10 @@
* decoders.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input.c,v 1.179 2002/02/27 04:49:55 sam Exp $
* $Id: input.c,v 1.180 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Alexis Guillard <alexis.guillard@bt.com>
*
* 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,33 +34,9 @@
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#elif defined( SYS_NTO )
/* unsupported */
#else
# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
# include <netinet/in.h>
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
# endif
#endif
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
......@@ -85,15 +62,6 @@ static void CloseThread ( input_thread_t *p_input );
static void DestroyThread ( input_thread_t *p_input );
static void EndThread ( input_thread_t *p_input );
static void FileOpen ( input_thread_t *p_input );
static void StdOpen ( input_thread_t *p_input );
static void FileClose ( input_thread_t *p_input );
#if !defined( SYS_NTO )
static void NetworkOpen ( input_thread_t *p_input );
static void HTTPOpen ( input_thread_t *p_input );
static void NetworkClose ( input_thread_t *p_input );
#endif
/*****************************************************************************
* input_InitBank: initialize the input bank.
*****************************************************************************/
......@@ -156,7 +124,7 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
p_input->b_eof = 0;
/* Set target */
p_input->p_source = p_item->psz_name;
p_input->psz_source = strdup( p_item->psz_name );
/* Set status */
p_input->i_status = THREAD_CREATE;
......@@ -165,7 +133,6 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
p_input->c_loops = 0;
p_input->stream.c_packets_read = 0;
p_input->stream.c_packets_trashed = 0;
p_input->p_stream = NULL;
/* Set locks. */
vlc_mutex_init( &p_input->stream.stream_lock );
......@@ -205,7 +172,7 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
VOUT_GRAYSCALE_VAR );
p_input->stream.control.i_smp = config_GetIntVariable( VDEC_SMP_VAR );
intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source );
intf_WarnMsg( 1, "input: playlist item `%s'", p_input->psz_source );
/* Create thread. */
if( vlc_thread_create( &p_input->thread_id, "input",
......@@ -306,8 +273,7 @@ static int RunThread( input_thread_t *p_input )
while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
{
data_packet_t * p_data;
int i_count, i;
int i, i_count;
p_input->c_loops++;
......@@ -362,8 +328,10 @@ static int RunThread( input_thread_t *p_input )
{
if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
{
p_input->pf_seek( p_input,
p_input->stream.p_selected_area->i_seek );
off_t i_new_pos = p_input->stream.p_selected_area->i_seek;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->pf_seek( p_input, i_new_pos );
vlc_mutex_lock( &p_input->stream.stream_lock );
for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
{
......@@ -376,6 +344,9 @@ static int RunThread( input_thread_t *p_input )
/* Reinitialize synchro. */
p_pgrm->i_synchro_state = SYNCHRO_REINIT;
}
/* Reinitialize buffer manager. */
input_AccessReinit( p_input );
}
p_input->stream.p_selected_area->i_seek = NO_SEEK;
}
......@@ -408,19 +379,8 @@ static int RunThread( input_thread_t *p_input )
vlc_mutex_unlock( &p_input->stream.stream_lock );
i_count = p_input->pf_read( p_input, &p_data );
/* Demultiplex read packets. */
while( p_data != NULL )
{
data_packet_t * p_next = p_data->p_next;
p_data->p_next = NULL;
p_input->stream.c_packets_read++;
p_input->pf_demux( p_input, p_data );
p_data = p_next;
}
/* Read and demultiplex some data. */
i_count = p_input->pf_demux( p_input );
if( i_count == 0 && p_input->stream.b_seekable )
{
......@@ -452,90 +412,139 @@ static int RunThread( input_thread_t *p_input )
*****************************************************************************/
static int InitThread( input_thread_t * p_input )
{
char *psz_name;
/* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
char * psz_parser = p_input->psz_source;
/* Find appropriate module. */
psz_name = config_GetPszVariable( INPUT_METHOD_VAR );
p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT, psz_name,
(void *)p_input );
/* Skip the plug-in names */
while( *psz_parser && *psz_parser != ':' )
{
psz_parser++;
}
if( psz_name ) free( psz_name );
if( p_input->p_input_module == NULL )
if( !*psz_parser )
{
intf_ErrMsg( "input error: no suitable input module for `%s'",
p_input->p_source );
return( -1 );
p_input->psz_access = p_input->psz_demux = NULL;
p_input->psz_name = p_input->psz_source;
}
else
{
*psz_parser++ = '\0';
#define f p_input->p_input_module->p_functions->input.functions.input
p_input->pf_probe = f.pf_probe;
p_input->pf_init = f.pf_init;
p_input->pf_end = f.pf_end;
p_input->pf_read = f.pf_read;
p_input->pf_set_area = f.pf_set_area;
p_input->pf_set_program = f.pf_set_program;
p_input->pf_demux = f.pf_demux;
p_input->pf_new_packet = f.pf_new_packet;
p_input->pf_new_pes = f.pf_new_pes;
p_input->pf_delete_packet = f.pf_delete_packet;
p_input->pf_delete_pes = f.pf_delete_pes;
p_input->pf_rewind = f.pf_rewind;
p_input->pf_seek = f.pf_seek;
p_input->psz_name = psz_parser;
if( f.pf_open != NULL )
{
f.pf_open( p_input );
/* Come back to parse the access and demux plug-ins */
psz_parser = p_input->psz_source;
if( !*psz_parser )
{
/* No access */
p_input->psz_access = NULL;
}
else if( *psz_parser == '/' )
{
/* No access */
p_input->psz_access = NULL;
psz_parser++;
}
else
{
p_input->psz_access = psz_parser;
while( *psz_parser && *psz_parser != '/' )
{
psz_parser++;
}
if( *psz_parser == '/' )
{
*psz_parser++ = '\0';
}
}
if( !*psz_parser )
{
/* No demux */
p_input->psz_demux = NULL;
}
else
{
p_input->psz_demux = psz_parser;
}
}
#if !defined( SYS_NTO )
/* FIXME : this is waaaay too kludgy */
else if( ( strlen( p_input->p_source ) >= 10
&& !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
|| ( strlen( p_input->p_source ) >= 4
&& !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
intf_WarnMsg( 2, "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 )
{
/* Network stream */
NetworkOpen( p_input );
p_input->stream.i_method = INPUT_METHOD_NETWORK;
return( -1 );
}
else if( ( strlen( p_input->p_source ) > 5 )
&& !strncasecmp( p_input->p_source, "http:", 5 ) )
/* Find and open appropriate access plug-in. */
p_input->p_access_module = module_Need( MODULE_CAPABILITY_ACCESS,
p_input->psz_access,
(void *)p_input );
if( p_input->p_access_module == NULL )
{
/* HTTP stream */
HTTPOpen( p_input );
p_input->stream.i_method = INPUT_METHOD_NETWORK;
intf_ErrMsg( "input error: no suitable access plug-in for `%s/%s:%s'",
p_input->psz_access, p_input->psz_demux,
p_input->psz_name );
return( -1 );
}
#endif
else if( ( strlen( p_input->p_source ) == 1 )
&& *p_input->p_source == '-' )
#define f p_input->p_access_module->p_functions->access.functions.access
p_input->pf_open = f.pf_open;
p_input->pf_close = f.pf_close;
p_input->pf_read = f.pf_read;
p_input->pf_set_area = f.pf_set_area;
p_input->pf_set_program = f.pf_set_program;
p_input->pf_seek = f.pf_seek;
#undef f
/* Waiting for stream. */
if( p_input->i_mtu )
{
/* Stdin */
StdOpen( p_input );
p_input->i_bufsize = p_input->i_mtu;
}
else
{
/* File input */
FileOpen( p_input );
p_input->stream.i_method = INPUT_METHOD_FILE;
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
}
#undef f
if( p_input->b_error )
if( p_input->p_current_data == NULL )
{
/* We barfed -- exit nicely */
module_Unneed( p_input->p_input_module );
return( -1 );
while( !input_FillBuffer( p_input ) )
{
if( p_input->b_die || p_input->b_error )
{
module_Unneed( p_input->p_access_module );
return( -1 );
}
}
}
p_input->pf_init( p_input );
/* Find and open appropriate demux plug-in. */
p_input->p_demux_module = module_Need( MODULE_CAPABILITY_DEMUX,
p_input->psz_demux,
(void *)p_input );
if( p_input->b_error )
if( p_input->p_demux_module == NULL )
{
/* We barfed -- exit nicely */
CloseThread( p_input );
module_Unneed( p_input->p_input_module );
intf_ErrMsg( "input error: no suitable demux plug-in for `%s/%s:%s'",
p_input->psz_access, p_input->psz_demux,
p_input->psz_name );
module_Unneed( p_input->p_access_module );
return( -1 );
}
#define f p_input->p_demux_module->p_functions->demux.functions.demux
p_input->pf_init = f.pf_init;
p_input->pf_end = f.pf_end;
p_input->pf_demux = f.pf_demux;
p_input->pf_rewind = f.pf_rewind;
#undef f
return( 0 );
}
......@@ -583,12 +592,10 @@ static void EndThread( input_thread_t * p_input )
/* Free demultiplexer's data */
p_input->pf_end( p_input );
module_Unneed( p_input->p_demux_module );
/* Close the input method */
/* Close the access plug-in */
CloseThread( p_input );
/* Release modules */
module_Unneed( p_input->p_input_module );
}
/*****************************************************************************
......@@ -596,32 +603,12 @@ static void EndThread( input_thread_t * p_input )
*****************************************************************************/
static void CloseThread( input_thread_t * p_input )
{
#define f p_input->p_input_module->p_functions->input.functions.input
p_input->pf_close( p_input );
module_Unneed( p_input->p_access_module );
if( f.pf_close != NULL )
{
f.pf_close( p_input );
}
#if !defined( SYS_NTO )
/* Close stream */
else if( ( strlen( p_input->p_source ) > 10
&& !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
|| ( strlen( p_input->p_source ) > 4
&& !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
{
NetworkClose( p_input );
}
else if( ( strlen( p_input->p_source ) > 5 )
&& !strncasecmp( p_input->p_source, "http:", 5 ) )
{
NetworkClose( p_input );
}
#endif
else
{
FileClose( p_input );
}
#undef f
input_AccessEnd( p_input );
free( p_input->psz_source );
}
/*****************************************************************************
......@@ -633,681 +620,3 @@ static void DestroyThread( input_thread_t * p_input )
p_input->i_status = THREAD_OVER;
}
/*****************************************************************************
* StdOpen : open standard input
*****************************************************************************/
static void StdOpen( input_thread_t * p_input )
{
vlc_mutex_lock( &p_input->stream.stream_lock );
/* Suppose we can control the pace - this won't work in some cases ! */
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
p_input->stream.p_selected_area->i_tell = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_WarnMsg( 2, "input: opening stdin" );
p_input->i_handle = 0;
}
/*****************************************************************************
* FileOpen : open a file descriptor
*****************************************************************************/
static void FileOpen( input_thread_t * p_input )
{
struct stat stat_info;
int i_stat;
char *psz_name = p_input->p_source;
if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
{
int i_size = strlen( psz_name );
if( ( i_size > 8 )
&& !strncasecmp( psz_name, "dvdread:", 8 ) )
{
/* get rid of the 'dvdread:' stuff and try again */
psz_name += 8;
i_stat = stat( psz_name, &stat_info );
}
else if( ( i_size > 4 )
&& !strncasecmp( psz_name, "dvd:", 4 ) )
{
/* get rid of the 'dvd:' stuff and try again */
psz_name += 4;
i_stat = stat( psz_name, &stat_info );
}
else if( ( i_size > 4 )
&& !strncasecmp( psz_name, "vcd:", 4 ) )
{
/* get rid of the 'vcd:' stuff and try again */
psz_name += 4;
i_stat = stat( psz_name, &stat_info );
}
else if( ( i_size > 5 )
&& !strncasecmp( psz_name, "file:", 5 ) )
{
/* get rid of the 'file:' stuff and try again */
psz_name += 5;
i_stat = stat( psz_name, &stat_info );
}
if( i_stat == (-1) )
{
intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
psz_name, strerror(errno));
p_input->b_error = 1;
return;
}
}
vlc_mutex_lock( &p_input->stream.stream_lock );
/* If we are here we can control the pace... */
p_input->stream.b_pace_control = 1;
if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
|| S_ISBLK(stat_info.st_mode) )
{
p_input->stream.b_seekable = 1;
p_input->stream.p_selected_area->i_size = stat_info.st_size;
}
else if( S_ISFIFO(stat_info.st_mode)
#if !defined( SYS_BEOS ) && !defined( WIN32 )
|| S_ISSOCK(stat_info.st_mode)
#endif
)
{
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
}
else
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_ErrMsg( "input error: unknown file type for `%s'",
psz_name );
p_input->b_error = 1;
return;
}
p_input->stream.p_selected_area->i_tell = 0;
vlc_mutex_unlock( &p_input->stream.stream_lock );
intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source );
if( (p_input->i_handle = open( psz_name,
/*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
{
intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
p_input->b_error = 1;
return;
}
}
/*****************************************************************************
* FileClose : close a file descriptor
*****************************************************************************/
static void FileClose( input_thread_t * p_input )
{
intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source );
close( p_input->i_handle );
return;
}
#if !defined( SYS_NTO )
/*****************************************************************************
* NetworkOpen : open a network socket
*****************************************************************************/
static void NetworkOpen( input_thread_t * p_input )
{
char *psz_server = NULL;
char *psz_bind = NULL;
int i_server_port = 0;
int i_bind_port = 0;
int i_opt;
int i_opt_size;
struct sockaddr_in sock;
/* Get the remote server. Syntax is :
* udp[stream]:[/][/][serveraddr[:serverport]][@[bindaddr]:[bindport]] */
if( p_input->p_source != NULL )
{
char * psz_parser = p_input->p_source;
char * psz_server_port = NULL;
char * psz_bind_port = NULL;
/* Skip the protocol name */
while( *psz_parser && *psz_parser != ':' )
{
psz_parser++;
}
/* Skip the "://" part */
while( *psz_parser && (*psz_parser == ':' || *psz_parser == '/') )
{
psz_parser++;
}
if( *psz_parser && *psz_parser != '@' )
{
/* Found server */
psz_server = psz_parser;
while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == ':' )
{
/* Found server port */
*psz_parser = '\0'; /* Terminate server name */
psz_parser++;
psz_server_port = psz_parser;
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
}
}
if( *psz_parser == '@' )
{
/* Found bind address or bind port */
*psz_parser = '\0'; /* Terminate server port or name if necessary */
psz_parser++;
if( *psz_parser && *psz_parser != ':' )
{
/* Found bind address */
psz_bind = psz_parser;
while( *psz_parser && *psz_parser != ':' )
{
psz_parser++;
}
}
if( *psz_parser == ':' )
{
/* Found bind port */
*psz_parser = '\0'; /* Terminate bind address if necessary */
psz_parser++;
psz_bind_port = psz_parser;
}
}
/* Convert ports format */
if( psz_server_port != NULL )
{
i_server_port = strtol( psz_server_port, &psz_parser, 10 );
if( *psz_parser )
{
intf_ErrMsg( "input error: cannot parse server port near %s",
psz_parser );
p_input->b_error = 1;
return;
}
}
if( psz_bind_port != NULL )
{
i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
if( *psz_parser )
{
intf_ErrMsg( "input error: cannot parse bind port near %s",
psz_parser );
p_input->b_error = 1;
return;
}
}
}
else
{
/* This is required or NetworkClose will never be called */
p_input->p_source = "ts: network input";
}
/* Check that we got a valid port */
if( i_bind_port == 0 )
{
i_bind_port = config_GetIntVariable( INPUT_PORT_VAR );
}
intf_WarnMsg( 2, "input: server=%s:%d local=%s:%d",
psz_server, i_server_port, psz_bind, i_bind_port );
/* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
* protocol */
p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
if( p_input->i_handle == -1 )
{
intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );
p_input->b_error = 1;
return;
}
/* We may want to reuse an already used socket */
i_opt = 1;
if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
strerror(errno));
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
* packet loss caused by scheduling problems */
i_opt = 0x80000;
if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_WarnMsg( 1, "input warning: can't configure socket (SO_RCVBUF: %s)",
strerror(errno));
}
/* Check if we really got what we have asked for, because Linux, etc.
* will silently limit the max buffer size to net.core.rmem_max which
* is typically only 65535 bytes */
i_opt = 0;
i_opt_size = sizeof( i_opt );
if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
(void*) &i_opt, &i_opt_size ) == -1 )
{
intf_WarnMsg( 1, "input warning: can't query socket (SO_RCVBUF: %s)",
strerror(errno));
}
else if( i_opt < 0x80000 )
{
intf_WarnMsg( 1, "input warning: socket buffer size is 0x%x"
" instead of 0x%x", i_opt, 0x80000 );
}
/* Build the local socket */
/* As we have a problem with multicast under win32, let's bind on INADDR_ANY */
#ifdef WIN32
if ( network_BuildAddr( &sock, NULL, i_bind_port ) == -1 )
#else
if ( network_BuildAddr( &sock, psz_bind, i_bind_port ) == -1 )
#endif
{
intf_ErrMsg( "input error: can't build local address" );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Bind it */
if( bind( p_input->i_handle, (struct sockaddr *)&sock,
sizeof( sock ) ) < 0 )
{
intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Allow broadcast reception if we bound on INADDR_ANY */
if( psz_bind == NULL )
{
i_opt = 1;
if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_BROADCAST,
(void*) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_WarnMsg( 1, "input warning: can't configure socket (SO_BROADCAST: %s)",
strerror(errno));
}
}
/* Join the multicast group if the socket is a multicast address */
#ifndef IN_MULTICAST
# define IN_MULTICAST(a) IN_CLASSD(a)
#endif
#ifdef WIN32
if( IN_MULTICAST( ntohl( inet_addr (psz_bind) ) ) )
{
struct ip_mreq imr;
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr.s_addr = inet_addr (psz_bind) ;
#else
if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
{
struct ip_mreq imr;
imr.imr_interface.s_addr = INADDR_ANY;
imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
#endif
if( setsockopt( p_input->i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char*)&imr, sizeof(struct ip_mreq) ) == -1 )
{
intf_ErrMsg( "input error: failed to join IP multicast group (%s)",
strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
}
if( psz_server != NULL )
{
/* Build socket for remote connection */
if ( network_BuildAddr( &sock, psz_server, i_server_port ) == -1 )
{
intf_ErrMsg( "input error: can't build remote address" );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Connect the socket */
if( connect( p_input->i_handle, (struct sockaddr *) &sock,
sizeof( sock ) ) == (-1) )
{
intf_ErrMsg( "input error: can't connect socket (%s)",
strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
}
p_input->stream.b_pace_control = 0;
p_input->stream.b_seekable = 0;
intf_WarnMsg( 3, "input: successfully opened network mode" );
return;
}
/*****************************************************************************
* NetworkClose : close a network socket
*****************************************************************************/
static void NetworkClose( input_thread_t * p_input )
{
intf_WarnMsg( 2, "input: closing network target `%s'", p_input->p_source );
close( p_input->i_handle );
}
/*****************************************************************************
* HTTPOpen : make an HTTP request
*****************************************************************************/
static void HTTPOpen( input_thread_t * p_input )
{
char *psz_server = NULL;
char *psz_path = NULL;
char *psz_proxy;
int i_port = 0;
int i_opt;
struct sockaddr_in sock;
char psz_buffer[256];
/* Get the remote server */
if( p_input->p_source != NULL )
{
psz_server = p_input->p_source;
/* Skip the protocol name */
while( *psz_server && *psz_server != ':' )
{
psz_server++;
}
/* Skip the "://" part */
while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
{
psz_server++;
}
/* Found a server name */
if( *psz_server )
{
char *psz_port = psz_server;
/* Skip the hostname part */
while( *psz_port && *psz_port != ':' && *psz_port != '/' )
{
psz_port++;
}
/* Found a port name */
if( *psz_port )
{
if( *psz_port == ':' )
{
/* Replace ':' with '\0' */
*psz_port = '\0';
psz_port++;
}
psz_path = psz_port;
while( *psz_path && *psz_path != '/' )
{
psz_path++;
}
if( *psz_path )
{
*psz_path = '\0';
psz_path++;
}
else
{
psz_path = NULL;
}
if( *psz_port != '\0' )
{
i_port = atoi( psz_port );
}
}
}
else
{
psz_server = NULL;
}
}
/* Check that we got a valid server */
if( psz_server == NULL )
{
intf_ErrMsg( "input error: No server given" );
p_input->b_error = 1;
return;
}
/* Check that we got a valid port */
if( i_port == 0 )
{
i_port = 80; /* FIXME */
}
intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server,
i_port, psz_path );
/* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
* * protocol */
p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 );
if( p_input->i_handle == -1 )
{
intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) ); p_input->b_error = 1;
return;
}
/* We may want to reuse an already used socket */
i_opt = 1;
if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
(void *) &i_opt, sizeof( i_opt ) ) == -1 )
{
intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
strerror(errno));
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Check proxy */
if( (psz_proxy = getenv( "http_proxy" )) != NULL )
{
/* http://myproxy.mydomain:myport/ */
int i_proxy_port = 0;
/* Skip the protocol name */
while( *psz_proxy && *psz_proxy != ':' )
{
psz_proxy++;
}
/* Skip the "://" part */
while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
{
psz_proxy++;
}
/* Found a proxy name */
if( *psz_proxy )
{
char *psz_port = psz_proxy;
/* Skip the hostname part */
while( *psz_port && *psz_port != ':' && *psz_port != '/' )
{
psz_port++;
}
/* Found a port name */
if( *psz_port )
{
char * psz_junk;
/* Replace ':' with '\0' */
*psz_port = '\0';
psz_port++;
psz_junk = psz_port;
while( *psz_junk && *psz_junk != '/' )
{
psz_junk++;
}
if( *psz_junk )
{
*psz_junk = '\0';
}
if( *psz_port != '\0' )
{
i_proxy_port = atoi( psz_port );
}
}
}
else
{
intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Build socket for proxy connection */
if ( network_BuildAddr( &sock, psz_proxy, i_proxy_port ) == -1 )
{
intf_ErrMsg( "input error: can't build remote address" );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
}
else
{
/* No proxy, direct connection */
if ( network_BuildAddr( &sock, psz_server, i_port ) == -1 )
{
intf_ErrMsg( "input error: can't build remote address" );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
}
/* Connect the socket */
if( connect( p_input->i_handle, (struct sockaddr *) &sock,
sizeof( sock ) ) == (-1) )
{
intf_ErrMsg( "input error: can't connect socket (%s)",
strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
p_input->stream.b_seekable = 0;
p_input->stream.b_pace_control = 1; /* TCP/IP... */
# define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n"
# define HTTP_END "\r\n"
/* Prepare GET ... */
if( psz_proxy != NULL )
{
snprintf( psz_buffer, sizeof(psz_buffer),
"GET http://%s:%d/%s HTTP/1.0\r\n"
HTTP_USERAGENT HTTP_END,
psz_server, i_port, psz_path );
}
else
{
snprintf( psz_buffer, sizeof(psz_buffer),
"GET /%s HTTP/1.0\r\nHost: %s\r\n"
HTTP_USERAGENT HTTP_END,
psz_path, psz_server );
}
psz_buffer[sizeof(psz_buffer) - 1] = '\0';
/* Send GET ... */
if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) )
{
intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
/* Read HTTP header - this is gonna be fun with plug-ins which do not
* use p_input->p_stream :-( */
if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL )
{
intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) );
close( p_input->i_handle );
p_input->b_error = 1;
return;
}
while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) )
{
if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL
|| *psz_buffer == '\r' || *psz_buffer == '\0' )
{
break;
}
/* FIXME : check Content-Type one day */
}
intf_WarnMsg( 3, "input: successfully opened HTTP mode" );
}
#endif /* !defined( SYS_NTO ) */
......@@ -2,7 +2,7 @@
* input_dec.c: Functions for the management of decoders
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input_dec.c,v 1.28 2002/02/24 20:51:10 gbazin Exp $
* $Id: input_dec.c,v 1.29 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -254,7 +254,6 @@ static decoder_config_t * CreateDecoderConfig( input_thread_t * p_input,
p_config->p_decoder_fifo->i_depth = 0;
p_config->p_decoder_fifo->b_die = p_config->p_decoder_fifo->b_error = 0;
p_config->p_decoder_fifo->p_packets_mgt = p_input->p_method_data;
p_config->p_decoder_fifo->pf_delete_pes = p_input->pf_delete_pes;
return p_config;
}
......@@ -268,9 +267,8 @@ static void DeleteDecoderConfig( decoder_config_t * p_config )
p_config->i_id, p_config->i_type,
p_config->p_decoder_fifo->i_depth );
/* Free all packets still in the decoder fifo. */
p_config->p_decoder_fifo->pf_delete_pes(
p_config->p_decoder_fifo->p_packets_mgt,
p_config->p_decoder_fifo->p_first );
input_DeletePES( p_config->p_decoder_fifo->p_packets_mgt,
p_config->p_decoder_fifo->p_first );
/* Destroy the lock and cond */
vlc_cond_destroy( &p_config->p_decoder_fifo->data_wait );
......
......@@ -2,7 +2,7 @@
* input_ext-dec.c: services to the decoders
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_ext-dec.c,v 1.29 2002/01/21 23:57:46 massiot Exp $
* $Id: input_ext-dec.c,v 1.30 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
......@@ -96,7 +96,7 @@ void DecoderError( decoder_fifo_t * p_fifo )
while (!p_fifo->b_die)
{
/* Trash all received PES packets */
p_fifo->pf_delete_pes( p_fifo->p_packets_mgt, p_fifo->p_first );
input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
p_fifo->p_first = NULL;
p_fifo->pp_last = &p_fifo->p_first;
......@@ -132,8 +132,7 @@ static __inline__ boolean_t _NextDataPacket( decoder_fifo_t * p_fifo,
/* Free the previous PES packet. */
p_next = p_fifo->p_first->p_next;
p_fifo->p_first->p_next = NULL;
p_fifo->pf_delete_pes( p_fifo->p_packets_mgt,
p_fifo->p_first );
input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first );
p_fifo->p_first = p_next;
p_fifo->i_depth--;
......
/*****************************************************************************
* input_ext-plugins.c: useful functions for access and demux plug-ins
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: input_ext-plugins.c,v 1.1 2002/03/01 00:33:18 massiot Exp $
*
* 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 <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <videolan/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
# include <netdb.h> /* hostent ... */
# include <sys/socket.h>
# include <netinet/in.h>
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
# endif
#endif
#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
*****************************************************************************/
typedef struct data_buffer_s
{
struct data_buffer_s * 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;
} data_buffer_t;
/*****************************************************************************
* 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;
typedef struct input_buffers_s
{
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_buffers_t;
/*****************************************************************************
* input_BuffersInit: initialize the cache structures, return a pointer to it
*****************************************************************************/
void * input_BuffersInit( void )
{
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_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_buffers_t * p_buffers )
{
if( p_buffers != NULL )
{
if( p_main->b_stats )
{
intf_StatMsg( "input buffers stats: pes: %d packets",
p_buffers->pes.i_depth );
intf_StatMsg( "input buffers stats: data: %d packets",
p_buffers->data.i_depth );
intf_StatMsg( "input buffers stats: 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 )
{
intf_ErrMsg( "input buffers error: %d 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 )
{
intf_ErrMsg( "INPUT_MAX_ALLOCATION reached (%d)",
p_buffers->i_allocated );
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 )
{
intf_ErrMsg( "Out of memory" );
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 )
{
intf_ErrMsg( "Out of memory" );
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 )
{
intf_ErrMsg( "Out of memory" );
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 = NewBuffer( p_buffers, i_size );
data_packet_t * p_data;
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 )
{
intf_ErrMsg( "Out of memory" );
return NULL;
}
}
p_pes->p_next = NULL;
p_pes->b_data_alignment = p_pes->b_discontinuity =
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;
ssize_t i_ret;
vlc_mutex_lock( &p_input->p_method_data->lock );
p_buf = NewBuffer( p_input->p_method_data,
i_remains + p_input->i_bufsize );
if( p_buf == NULL )
{
return( -1 );
}
p_buf->i_refcount = 1;
if( p_input->p_data_buffer != NULL )
{
FAST_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 );
}
/* 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_ret = 0;
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 + 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 )
{
if( p_input->p_last_data - p_input->p_current_data < i_size )
{
/* Go to the next buffer */
ssize_t i_ret = input_FillBuffer( p_input );
if( i_size == -1 )
{
return( -1 );
}
else if( i_ret < i_size )
{
i_size = 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 )
{
if( p_input->p_last_data - p_input->p_current_data < i_size )
{
/* Go to the next buffer */
ssize_t i_ret = input_FillBuffer( p_input );
if( i_ret == -1 )
{
return( -1 );
}
else if( i_ret < i_size )
{
i_size = i_ret;
}
}
*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;
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();
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 after 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_method_data );
}
/*
* Optional file descriptor management functions, for use by access plug-ins
* base on file descriptors (file, udp, http...).
*/
/*****************************************************************************
* input_FDClose: close the target
*****************************************************************************/
void input_FDClose( input_thread_t * p_input )
{
input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
intf_WarnMsg( 2, "input: closing `%s/%s:%s'",
p_input->psz_access, p_input->psz_demux, p_input->psz_name );
close( p_access_data->i_handle );
free( p_access_data );
}
/*****************************************************************************
* input_FDRead: standard read on a file descriptor.
*****************************************************************************/
ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
{
input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
if( i_ret > 0 )
{
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_ret;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
if( i_ret < 0 )
{
intf_ErrMsg( "input error: read() failed (%s)", strerror(errno) );
}
return( i_ret );
}
/*****************************************************************************
* NetworkSelect: Checks whether data is available on a file descriptor
*****************************************************************************/
static __inline__ int NetworkSelect( input_thread_t * p_input )
{
input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
struct timeval timeout;
fd_set fds;
int i_ret;
/* Initialize file descriptor set */
FD_ZERO( &fds );
FD_SET( p_access_data->i_handle, &fds );
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
/* Find if some data is available */
i_ret = select( p_access_data->i_handle + 1, &fds,
NULL, NULL, &timeout );
if( i_ret == -1 )
{
intf_ErrMsg( "input error: network select error (%s)", strerror(errno) );
}
return( i_ret );
}
/*****************************************************************************
* input_FDNetworkRead: read on a file descriptor, checking periodically
* p_input->b_die
*****************************************************************************/
ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
if( NetworkSelect( p_input ) > 0 )
{
input_socket_t * p_access_data
= (input_socket_t *)p_input->p_access_data;
ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
if( i_ret > 0 )
{
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += i_ret;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
if( i_ret < 0 )
{
intf_ErrMsg( "input error: recv() failed (%s)", strerror(errno) );
}
return( i_ret );
}
return( 0 );
}
/*****************************************************************************
* input_FDSeek: seek to a specific location in a file
*****************************************************************************/
void input_FDSeek( input_thread_t * p_input, off_t i_pos )
{
input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
lseek( p_access_data->i_handle, i_pos, SEEK_SET );
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell = i_pos;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
......@@ -2,7 +2,7 @@
* mpeg_system.c: TS, PS and PES management
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: mpeg_system.c,v 1.80 2002/02/24 20:51:10 gbazin Exp $
* $Id: mpeg_system.c,v 1.81 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Lespinasse <walken@via.ecp.fr>
......@@ -130,7 +130,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
!= PES_HEADER_SIZE )
{
intf_WarnMsg( 1, "input: PES packet too short to have a header" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -149,7 +149,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
/* packet_start_code_prefix != 0x000001 */
intf_ErrMsg( "input error: data loss, "
"PES packet doesn't start with 0x000001" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
}
else
......@@ -195,7 +195,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1,
"PES packet too short to have a MPEG-2 header" );
p_input->pf_delete_pes( p_input->p_method_data,
input_DeletePES( p_input->p_method_data,
p_pes );
p_pes = NULL;
return;
......@@ -212,7 +212,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1,
"PES packet too short to have a MPEG-2 header" );
p_input->pf_delete_pes( p_input->p_method_data,
input_DeletePES( p_input->p_method_data,
p_pes );
p_pes = NULL;
return;
......@@ -230,7 +230,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1,
"PES packet too short to have a MPEG-2 header" );
p_input->pf_delete_pes( p_input->p_method_data,
input_DeletePES( p_input->p_method_data,
p_pes );
p_pes = NULL;
return;
......@@ -261,7 +261,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1,
"PES packet too short to have a MPEG-1 header" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -269,7 +269,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
if( i_pes_header_size == 23 )
{
intf_ErrMsg( "input error: too much MPEG-1 stuffing" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -285,7 +285,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1, "input: PES packet too short "
"to have a MPEG-1 header" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -305,7 +305,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1, "input: PES packet too short "
"to have a MPEG-1 header" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -323,7 +323,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_WarnMsg( 1, "input: PES packet too short "
"to have a MPEG-1 header" );
p_input->pf_delete_pes( p_input->p_method_data,
input_DeletePES( p_input->p_method_data,
p_pes );
p_pes = NULL;
return;
......@@ -365,7 +365,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
if( (p_data = p_data->p_next) == NULL )
{
intf_ErrMsg( "input error: PES header bigger than payload" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -376,7 +376,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
if( i_payload_size < i_pes_header_size )
{
intf_ErrMsg( "input error: PES header bigger than payload" );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
p_pes = NULL;
return;
}
......@@ -392,7 +392,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es )
{
intf_ErrMsg( "input error: no fifo to receive PES %p "
"(who wrote this damn code ?)", p_pes );
p_input->pf_delete_pes( p_input->p_method_data, p_pes );
input_DeletePES( p_input->p_method_data, p_pes );
}
p_pes = NULL;
}
......@@ -430,7 +430,7 @@ void input_GatherPES( input_thread_t * p_input, data_packet_t * p_data,
if( !b_unit_start && p_pes == NULL )
{
/* Random access... */
p_input->pf_delete_packet( p_input->p_method_data, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
}
else
{
......@@ -441,7 +441,7 @@ void input_GatherPES( input_thread_t * p_input, data_packet_t * p_data,
* packet. This is also here that we can synchronize with the
* stream if we lost packets or if the decoder has just
* started. */
if( (p_pes = p_input->pf_new_pes( p_input->p_method_data ) ) == NULL )
if( (p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
{
intf_ErrMsg( "input error: out of memory" );
p_input->b_error = 1;
......@@ -913,7 +913,7 @@ void input_DemuxPS( input_thread_t * p_input, data_packet_t * p_data )
/* Trash the packet if it has no payload or if it isn't selected */
if( b_trash )
{
p_input->pf_delete_packet( p_input->p_method_data, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
p_input->stream.c_packets_trashed++;
}
}
......@@ -1126,7 +1126,7 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
/* Trash the packet if it has no payload or if it isn't selected */
if( b_trash )
{
p_input->pf_delete_packet( p_input->p_method_data, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
p_input->stream.c_packets_trashed++;
}
else
......@@ -1282,7 +1282,7 @@ void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
#undef p_psi
#undef p
p_input->pf_delete_packet( p_input->p_method_data, p_data );
input_DeletePacket( p_input->p_method_data, p_data );
return ;
}
......
......@@ -2,7 +2,7 @@
* modules.c : Built-in and plugin modules management functions
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: modules.c,v 1.54 2002/02/24 20:51:10 gbazin Exp $
* $Id: modules.c,v 1.55 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
......@@ -385,9 +385,19 @@ module_t * module_Need( int i_capability, char *psz_name, void *p_data )
/* Test the requested capability */
switch( i_capability )
{
case MODULE_CAPABILITY_INPUT:
i_ret = p_first->p_module->p_functions->input.functions.
input.pf_probe( (input_thread_t *)p_data );
case MODULE_CAPABILITY_ACCESS:
i_ret = p_first->p_module->p_functions->access.functions.
access.pf_open( (struct input_thread_s *)p_data );
break;
case MODULE_CAPABILITY_DEMUX:
i_ret = p_first->p_module->p_functions->demux.functions.
demux.pf_init( (struct input_thread_s *)p_data );
break;
case MODULE_CAPABILITY_NETWORK:
i_ret = p_first->p_module->p_functions->network.functions.
network.pf_open( (struct network_socket_s *)p_data );
break;
case MODULE_CAPABILITY_DECODER:
......@@ -397,22 +407,22 @@ module_t * module_Need( int i_capability, char *psz_name, void *p_data )
case MODULE_CAPABILITY_INTF:
i_ret = p_first->p_module->p_functions->intf.functions.
intf.pf_open( (intf_thread_t *)p_data );
intf.pf_open( (struct intf_thread_s *)p_data );
break;
case MODULE_CAPABILITY_AOUT:
i_ret = p_first->p_module->p_functions->aout.functions.
aout.pf_open( (aout_thread_t *)p_data );
aout.pf_open( (struct aout_thread_s *)p_data );
break;
case MODULE_CAPABILITY_VOUT:
i_ret = p_first->p_module->p_functions->vout.functions.
vout.pf_create( (vout_thread_t *)p_data );
vout.pf_create( (struct vout_thread_s *)p_data );
break;
case MODULE_CAPABILITY_CHROMA:
i_ret = p_first->p_module->p_functions->chroma.functions.
chroma.pf_init( (vout_thread_t *)p_data );
chroma.pf_init( (struct vout_thread_s *)p_data );
break;
case MODULE_CAPABILITY_IDCT:
......
......@@ -2,7 +2,7 @@
* modules_plugin.h : Plugin management functions used by the core application.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: modules_plugin.h,v 1.12 2002/02/24 21:36:20 jobi Exp $
* $Id: modules_plugin.h,v 1.13 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -214,6 +214,25 @@ module_error( void )
(p_symbols)->input_DemuxTS = input_DemuxTS; \
(p_symbols)->input_DemuxPSI = input_DemuxPSI; \
(p_symbols)->input_ClockManageControl = input_ClockManageControl; \
(p_symbols)->input_FDSeek = input_FDSeek; \
(p_symbols)->input_FDClose = input_FDClose; \
(p_symbols)->input_FDRead = input_FDRead; \
(p_symbols)->input_FDNetworkRead = input_FDNetworkRead; \
(p_symbols)->input_BuffersInit = input_BuffersInit; \
(p_symbols)->input_BuffersEnd = input_BuffersEnd; \
(p_symbols)->input_NewBuffer = input_NewBuffer; \
(p_symbols)->input_ReleaseBuffer = input_ReleaseBuffer; \
(p_symbols)->input_ShareBuffer = input_ShareBuffer; \
(p_symbols)->input_NewPacket = input_NewPacket; \
(p_symbols)->input_DeletePacket = input_DeletePacket; \
(p_symbols)->input_NewPES = input_NewPES; \
(p_symbols)->input_DeletePES = input_DeletePES; \
(p_symbols)->input_FillBuffer = input_FillBuffer; \
(p_symbols)->input_Peek = input_Peek; \
(p_symbols)->input_SplitBuffer = input_SplitBuffer; \
(p_symbols)->input_AccessInit = input_AccessInit; \
(p_symbols)->input_AccessReinit = input_AccessReinit; \
(p_symbols)->input_AccessEnd = input_AccessEnd; \
(p_symbols)->aout_CreateFifo = aout_CreateFifo; \
(p_symbols)->aout_DestroyFifo = aout_DestroyFifo; \
(p_symbols)->vout_CreateThread = vout_CreateThread; \
......
......@@ -5,7 +5,7 @@
* thread, and destroy a previously oppened video output thread.
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: video_output.c,v 1.162 2002/02/27 18:19:21 sam Exp $
* $Id: video_output.c,v 1.163 2002/03/01 00:33:18 massiot Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
......@@ -125,7 +125,6 @@ vout_thread_t * vout_CreateThread ( int *pi_status,
{
p_vout->p_picture[i_index].i_status = FREE_PICTURE;
p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
vlc_mutex_init( &p_vout->p_picture[i_index].lock_deccount );
}
for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
......@@ -641,7 +640,6 @@ static void EndThread( vout_thread_t *p_vout )
{
free( p_vout->p_picture[i_index].p_data );
}
vlc_mutex_destroy( &p_vout->p_picture[i_index].lock_deccount );
}
/* Destroy all remaining subpictures */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment