* ./modules/*: moved plugins to the new tree. Yet untested builds include

waveout, directx, qnx, beos, win32, macosx, and the AltiVec modules.
  * ALL: removed mention of AC3 in favour of A52.
  * ./configure.in, ./Makefile*: modules can now be built deeper than 1
    directory. As a consequence, the build is even slower (but I'm fixing
    this) and make clean doesn't work anymore.
This commit is contained in:
Sam Hocevar 2002-08-04 17:23:44 +00:00
parent e5a6cfeafb
commit 19ea8feb6d
459 changed files with 115763 additions and 565 deletions

215
Makefile
View File

@ -13,165 +13,6 @@ endif
# Objects and files
###############################################################################
#
# All possible plugin directories, needed for make clean
#
PLUGINS_DIR := a52 \
a52_system \
aa \
ac3_adec \
ac3_spdif \
access \
alsa \
arts \
avi \
beos \
chroma \
cinepak \
directx \
downmix \
dsp \
dummy \
dvd \
dvdread \
dvdplay \
esd \
familiar \
fb \
ffmpeg \
mp4 \
filter \
fx \
ggi \
glide \
gtk \
idct \
imdct \
kde \
lirc \
lpcm_adec \
macosx \
mad \
memcpy \
mga \
motion \
mpeg_system \
mpeg_adec \
mpeg_vdec \
mp4 \
network \
ogg \
qnx \
qt \
satellite \
sdl \
spudec \
text \
vcd \
win32 \
x11 \
xosd
PLUGINS_TARGETS := a52/a52 \
aa/aa \
a52_system/a52_system \
ac3_adec/ac3_adec \
ac3_spdif/ac3_spdif \
access/file \
access/udp \
access/http \
alsa/alsa \
arts/arts \
avi/avi \
beos/beos \
chroma/chroma_i420_rgb \
chroma/chroma_i420_rgb_mmx \
chroma/chroma_i420_yuy2 \
chroma/chroma_i420_yuy2_mmx \
chroma/chroma_i422_yuy2 \
chroma/chroma_i422_yuy2_mmx \
chroma/chroma_i420_ymga \
chroma/chroma_i420_ymga_mmx \
cinepak/cinepak \
directx/directx \
downmix/downmix \
downmix/downmixsse \
downmix/downmix3dn \
dsp/dsp \
dummy/dummy \
dummy/null \
dvd/dvd \
dvdread/dvdread \
dvdplay/dvdplay \
esd/esd \
familiar/familiar \
fb/fb \
ffmpeg/ffmpeg \
mp4/mp4 \
filter/filter_clone \
filter/filter_crop \
filter/filter_deinterlace \
filter/filter_distort \
filter/filter_invert \
filter/filter_transform \
filter/filter_wall \
filter/filter_clone \
fx/fx_scope \
ggi/ggi \
glide/glide \
gtk/gnome \
gtk/gtk \
idct/idct \
idct/idctclassic \
idct/idctmmx \
idct/idctmmxext \
idct/idctaltivec \
imdct/imdct \
imdct/imdct3dn \
imdct/imdctsse \
kde/kde \
lirc/lirc \
lpcm_adec/lpcm_adec \
macosx/macosx \
mad/mad \
memcpy/memcpy \
memcpy/memcpymmx \
memcpy/memcpymmxext \
memcpy/memcpy3dn \
memcpy/memcpyaltivec \
mga/mga \
mga/xmga \
motion/motion \
motion/motionmmx \
motion/motionmmxext \
motion/motion3dnow \
motion/motionaltivec \
mpeg_system/mpeg_audio \
mpeg_system/mpeg_es \
mpeg_system/mpeg_ps \
mpeg_system/mpeg_ts \
mpeg_system/mpeg_ts_dvbpsi \
mpeg_adec/mpeg_adec \
mpeg_vdec/mpeg_vdec \
mp4/mp4 \
network/ipv4 \
network/ipv6 \
ogg/vorbis \
qnx/qnx \
qt/qt \
satellite/satellite \
sdl/sdl \
spudec/spudec \
text/logger \
text/ncurses \
text/rc \
vcd/vcd \
win32/waveout \
win32/intfwin \
x11/x11 \
x11/xvideo \
xosd/xosd
#
# C Objects
#
@ -238,10 +79,10 @@ CPP_DEP := $(CPP_OBJ:%.o=.dep/%.dpp)
# Translate plugin names
#
ifneq (,$(PLUGINS))
PLUGIN_OBJ := $(shell for i in $(PLUGINS) ; do echo " "$(PLUGINS_TARGETS)" " | sed -e 's@.*/\('$$i'\) .*@plugins/\1.so@' -e 's@^ .*@@' ; done)
PLUGIN_OBJ := $(PLUGINS:%=modules/%.so)
endif
ifneq (,$(BUILTINS))
BUILTIN_OBJ := $(shell for i in $(BUILTINS) ; do echo " "$(PLUGINS_TARGETS)" " | sed -e 's@.*/\('$$i'\) .*@plugins/\1.a@' -e 's@^ .*@@' ; done)
BUILTIN_OBJ := $(BUILTINS:%=modules/%.a)
endif
#
@ -295,9 +136,9 @@ po-clean:
plugins-clean:
for dir in $(PLUGINS_DIR) ; do \
( cd plugins/$${dir} \
( cd modules/$${dir} \
&& $(MAKE) -f ../../Makefile.modules clean ) ; done
rm -f plugins/*/*.o plugins/*/*.lo plugins/*/*.moc plugins/*/*.bak
rm -f modules/**/*.o modules/**/*.lo modules/**/*.moc modules/**/*.bak
vlc-clean:
rm -f $(C_OBJ) $(CPP_OBJ)
@ -348,7 +189,7 @@ endif
plugins-install:
mkdir -p $(DESTDIR)$(libdir)/vlc
ifneq (,$(PLUGINS))
$(INSTALL) $(PLUGINS:%=plugins/%.so) $(DESTDIR)$(libdir)/vlc
$(INSTALL) $(PLUGINS:%=modules/%.so) $(DESTDIR)$(libdir)/vlc
endif
plugins-uninstall:
@ -357,7 +198,7 @@ plugins-uninstall:
builtins-install:
mkdir -p $(DESTDIR)$(libdir)/vlc
ifneq (,$(BUILTINS))
$(INSTALL) -m 644 $(BUILTINS:%=plugins/%.a) $(DESTDIR)$(libdir)/vlc
$(INSTALL) -m 644 $(BUILTINS:%=modules/%.a) $(DESTDIR)$(libdir)/vlc
endif
builtins-uninstall:
@ -410,13 +251,13 @@ dist:
find debian -mindepth 1 -maxdepth 1 -type d | \
while read i ; do rm -Rf tmp/vlc/$$i ; done
# Copy .c .h .in .cpp .m and .glade files
find include src plugins -type f -name '*.[bcdhigmrst]*' | while read i ; \
find include src modules -type f -name '*.[bcdhigmrst]*' | while read i ; \
do cp $$i tmp/vlc/$$i ; done
# Grmbl... special case...
for i in API BUGS DESIGN TODO ; \
do cp plugins/mad/$$i tmp/vlc/plugins/mad ; done
do cp modules/mad/$$i tmp/vlc/modules/mad ; done
# Copy plugin Makefiles
find plugins -type f -name Makefile | while read i ; \
find modules -type f -name Makefile | while read i ; \
do cp $$i tmp/vlc/$$i ; done
# Copy extra programs and documentation
cp -a extras/* tmp/vlc/extras
@ -472,12 +313,12 @@ package-win32:
for file in AUTHORS COPYING ChangeLog README FAQ TODO ; \
do cp $$file tmp/$${file}.txt ; \
unix2dos tmp/$${file}.txt ; done
mkdir tmp/plugins
cp $(PLUGINS:%=plugins/%.so) tmp/plugins/
mkdir tmp/modules
cp $(PLUGINS:%=modules/%.so) tmp/modules/
# don't include these two
#rm -f tmp/plugins/gtk.so tmp/plugins/sdl.so
#rm -f tmp/modules/gtk.so tmp/modules/sdl.so
ifneq (,$(PLUGINS))
for i in $(PLUGINS) ; do if test $$i != intfwin ; then $(STRIP) tmp/plugins/$$i.so ; fi ; done
for i in $(PLUGINS) ; do if test $$i != intfwin ; then $(STRIP) tmp/modules/$$i.so ; fi ; done
endif
mkdir tmp/share
for file in default8x16.psf default8x9.psf ; \
@ -504,9 +345,9 @@ package-beos:
cp AUTHORS COPYING ChangeLog README FAQ TODO tmp/vlc/
for file in default8x16.psf default8x9.psf ; \
do cp share/$$file tmp/vlc/share/ ; done
mkdir tmp/vlc/plugins
cp $(PLUGINS:%=plugins/%.so) tmp/vlc/plugins/
strip $(PLUGINS:%=tmp/vlc/plugins/%.so)
mkdir tmp/vlc/modules
cp $(PLUGINS:%=modules/%.so) tmp/vlc/modules/
strip $(PLUGINS:%=tmp/vlc/modules/%.so)
# Create package
mv tmp/vlc tmp/vlc-${VERSION}
(cd tmp ; find vlc-${VERSION} | \
@ -546,10 +387,10 @@ ifneq (,$(findstring darwin,$(SYS)))
cd extras/MacOSX ; pbxbuild | grep -v '^ ' | grep -v '^\t' | grep -v "^$$"
cp -r extras/MacOSX/build/vlc.bundle ./vlc.app
$(INSTALL) -d vlc.app/Contents/MacOS/share
$(INSTALL) -d vlc.app/Contents/MacOS/plugins
$(INSTALL) -d vlc.app/Contents/MacOS/modules
$(INSTALL) vlc vlc.app/Contents/MacOS/
ifneq (,$(PLUGINS))
$(INSTALL) $(PLUGINS:%=plugins/%.so) vlc.app/Contents/MacOS/plugins
$(INSTALL) $(PLUGINS:%=modules/%.so) vlc.app/Contents/MacOS/modules
endif
$(INSTALL) -m 644 share/*.psf vlc.app/Contents/MacOS/share
endif
@ -564,7 +405,7 @@ src/misc/modules_builtin.h: Makefile.opts Makefile Makefile.config
@rm -f $@ && cp $@.in $@
ifneq (,$(BUILTINS))
@for i in $(BUILTINS) ; do \
echo "int vlc_entry__"$$i"( module_t* );" >>$@; \
echo "int vlc_entry__"`basename $$i`"( module_t* );" >>$@; \
done
@echo "" >> $@ ;
endif
@ -573,7 +414,7 @@ endif
@echo " { \\" >> $@ ;
ifneq (,$(BUILTINS))
@for i in $(BUILTINS) ; do \
echo " ALLOCATE_BUILTIN("$$i"); \\" >> $@ ; \
echo " ALLOCATE_BUILTIN("`basename $$i`"); \\" >> $@ ; \
done
endif
@echo " } while( 0 );" >> $@ ;
@ -634,19 +475,11 @@ lib/libvlc.a: Makefile.opts Makefile.dep Makefile $(LIBVLC_OBJ)
#lib/libvlc.so: Makefile.opts Makefile.dep Makefile $(LIBVLC_OBJ)
# $(CC) -shared $(LIBVLC_OBJ) $(LDFLAGS) $(vlc_LDFLAGS) -o $@
#
# Plugins target
#
plugins: Makefile.modules Makefile.opts Makefile.dep Makefile $(PLUGIN_OBJ)
$(PLUGIN_OBJ): $(H_OBJ) FORCE
@cd $(shell echo " "$(PLUGINS_TARGETS)" " | sed -e 's@.* \([^/]*/\)'$(@:plugins/%.so=%)' .*@plugins/\1@' -e 's@^ .*@@') && $(MAKE) -f ../../Makefile.modules $(@:plugins/%=../%)
#
# Built-in modules target
#
builtins: Makefile.modules Makefile.opts Makefile.dep Makefile $(BUILTIN_OBJ)
$(BUILTIN_OBJ): $(H_OBJ) FORCE
@cd $(shell echo " "$(PLUGINS_TARGETS)" " | sed -e 's@.* \([^/]*/\)'$(@:plugins/%.a=%)' .*@plugins/\1@' -e 's@^ .*@@') && $(MAKE) -f ../../Makefile.modules $(@:plugins/%=../%)
plugins: Makefile.modules Makefile.opts Makefile.dep Makefile $(PLUGIN_OBJ)
modules/%.a modules/%.so: $(H_OBJ) FORCE
@cd $(shell echo $@ | sed -e 's@\(.*\)/.*@\1@') && $(MAKE) -f $(shell echo $@ | sed -e 's@[^/]*/@../@g' -e 's@\(.*\)/.*@\1@')/Makefile.modules $(shell echo $@ | sed -e 's@.*/@@') PARENT=$(shell echo $@ | sed -e 's@[^/]*/@../@g' -e 's@\(.*\)/.*@\1@')
#
# Mozilla plugin target

View File

@ -13,7 +13,7 @@ include Makefile
#
# Analyze the target we are asked to build
#
module_name := $(shell echo $(MAKECMDGOALS) | sed 's@.*/\(.*\)\..*@\1@')
module_name := $(shell echo $(MAKECMDGOALS) | sed 's@\..*@@')
suff := $(shell echo $(MAKECMDGOALS) | sed 's@.*\.@@' | tr so/a lo/o)
#
@ -23,6 +23,9 @@ SRC_C := $(filter %.c,$($(module_name)_SOURCES))
SRC_CPP := $(filter %.cpp,$($(module_name)_SOURCES))
SRC_M := $(filter %.m,$($(module_name)_SOURCES))
plugins_CFLAGS += -D__PLUGIN__ -I$(PARENT)/include -I$(PARENT)/extras
builtins_CFLAGS += -D__BUILTIN__ -I$(PARENT)/include -I$(PARENT)/extras
ifeq (lo,$(suff))
extra_CFLAGS := $(plugins_CFLAGS) $($(module_name)_CFLAGS) \
-DMODULE_NAME=$(module_name) -DMODULE_NAME_IS_$(module_name) \
@ -57,17 +60,17 @@ clean:
FORCE:
$(OBJ_ALL): ../../Makefile.modules ../../Makefile.dep ../../Makefile ../../Makefile.opts Makefile
$(OBJ_ALL): $(H_DEP:%=../../include/%)
$(OBJ_ALL): $(PARENT)/Makefile.modules $(PARENT)/Makefile.dep $(PARENT)/Makefile $(PARENT)/Makefile.opts Makefile
$(OBJ_ALL): $(H_DEP:%=$(PARENT)/include/%)
$(C_DEP): %.d: FORCE
@$(MAKE) -s --no-print-directory -f ../../Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
@$(MAKE) -s --no-print-directory -f $(PARENT)/Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
$(CPP_DEP): %.dpp: FORCE
@$(MAKE) -s --no-print-directory -f ../../Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
@$(MAKE) -s --no-print-directory -f $(PARENT)/Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
$(M_DEP): %.dm: FORCE
@$(MAKE) -s --no-print-directory -f ../../Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
@$(MAKE) -s --no-print-directory -f $(PARENT)/Makefile.dep $@ CFLAGS="$(CFLAGS) $(extra_CFLAGS)"
$(SRC_C:%.c=%.$(suff).$(module_name)): %.$(suff).$(module_name): .dep/%.d
$(SRC_C:%.c=%.$(suff).$(module_name)): %.$(suff).$(module_name): %.c
@ -83,10 +86,10 @@ $(SRC_M:%.m=%.$(suff).$(module_name)): %.$(suff).$(module_name): %.m
# foo_CUSTOM lets us override all target rules for foo.so and foo.a
ifeq (,$($(module_name)_CUSTOM))
../$(module_name).so: $(EXTRA_DEP) $(OBJ_ALL)
$(module_name).so: $(EXTRA_DEP) $(OBJ_ALL)
$(CC) $(OBJ_ALL) $(LDFLAGS) $(plugins_LDFLAGS) $($(module_name)_LDFLAGS) -o $@
../$(module_name).a: $(EXTRA_DEP) $(OBJ_ALL)
$(module_name).a: $(EXTRA_DEP) $(OBJ_ALL)
rm -f $@
ar rc $@ $(OBJ_ALL)
$(RANLIB) $@

View File

@ -60,7 +60,7 @@ mozilla_CFLAGS = @mozilla_CFLAGS@
a52_CFLAGS = @a52_CFLAGS@
arts_CFLAGS = @arts_CFLAGS@
chroma_i420_yuy2_mmx_CFLAGS = @chroma_i420_yuy2_mmx_CFLAGS@
i420_yuy2_mmx_CFLAGS = @i420_yuy2_mmx_CFLAGS@
directx_CFLAGS = @directx_CFLAGS@
dvd_CFLAGS = @dvd_CFLAGS@
dvdread_CFLAGS = @dvdread_CFLAGS@
@ -76,7 +76,7 @@ kde_CFLAGS = @kde_CFLAGS@
mad_CFLAGS = @mad_CFLAGS@
memcpyaltivec_CFLAGS = @memcpyaltivec_CFLAGS@
motionaltivec_CFLAGS = @motionaltivec_CFLAGS@
mpeg_ts_dvbpsi_CFLAGS = @mpeg_ts_dvbpsi_CFLAGS@
ts_dvbpsi_CFLAGS = @ts_dvbpsi_CFLAGS@
qt_CFLAGS = @qt_CFLAGS@
sdl_CFLAGS = @sdl_CFLAGS@
x11_CFLAGS = @x11_CFLAGS@
@ -95,7 +95,7 @@ aa_LDFLAGS = @aa_LDFLAGS@
alsa_LDFLAGS = @alsa_LDFLAGS@
arts_LDFLAGS = @arts_LDFLAGS@
beos_LDFLAGS = @beos_LDFLAGS@
chroma_i420_rgb_LDFLAGS = @chroma_i420_rgb_LDFLAGS@
i420_rgb_LDFLAGS = @i420_rgb_LDFLAGS@
directx_LDFLAGS = @directx_LDFLAGS@
dsp_LDFLAGS = @dsp_LDFLAGS@
dvd_LDFLAGS = @dvd_LDFLAGS@
@ -103,7 +103,7 @@ dvdread_LDFLAGS = @dvdread_LDFLAGS@
dvdplay_LDFLAGS = @dvdplay_LDFLAGS@
esd_LDFLAGS = @esd_LDFLAGS@
familiar_LDFLAGS = @familiar_LDFLAGS@
filter_distort_LDFLAGS = @filter_distort_LDFLAGS@
distort_LDFLAGS = @distort_LDFLAGS@
ffmpeg_LDFLAGS = @ffmpeg_LDFLAGS@
mp4_LDFLAGS = @mp4_LDFLAGS@
ggi_LDFLAGS = @ggi_LDFLAGS@
@ -123,7 +123,7 @@ macosx_LDFLAGS = @macosx_LDFLAGS@
mad_LDFLAGS = @mad_LDFLAGS@
memcpyaltivec_LDFLAGS = @memcpyaltivec_LDFLAGS@
motionaltivec_LDFLAGS = @motionaltivec_LDFLAGS@
mpeg_ts_dvbpsi_LDFLAGS = @mpeg_ts_dvbpsi_LDFLAGS@
ts_dvbpsi_LDFLAGS = @ts_dvbpsi_LDFLAGS@
ncurses_LDFLAGS = @ncurses_LDFLAGS@
qnx_LDFLAGS = @qnx_LDFLAGS@
qt_LDFLAGS = @qt_LDFLAGS@
@ -250,16 +250,10 @@ endif
endif
endif
#
# C compiler flags: plugins and builtins compilation
#
plugins_CFLAGS += -D__PLUGIN__ -I../../include -I../../extras
builtins_CFLAGS += -D__BUILTIN__ -I../../include -I../../extras
#
# Linker flags: plugins and builtins linking
#
builtins_LDFLAGS += $(patsubst %,$$%_LDFLAGS,$(BUILTINS))
builtins_LDFLAGS += $(patsubst %,$$%_LDFLAGS,$(shell echo $(BUILTINS) | sed -e 's@\([^ ]*/\)*@@g'))
#
# Debugging and profiling support

499
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -367,7 +367,7 @@ AC_CACHE_CHECK([if \$CC accepts -fomit-frame-pointer],
if test "x${ac_cv_c_omit_frame_pointer}" != "xno"; then
CFLAGS_OPTIM_NODEBUG="${CFLAGS_OPTIM_NODEBUG} -fomit-frame-pointer"
# this plugin does not compile without -fomit-frame-pointer, damn gcc!
chroma_i420_yuy2_mmx_CFLAGS="${chroma_i420_yuy2_mmx_CFLAGS} -fomit-frame-pointer"
i420_yuy2_mmx_CFLAGS="${i420_yuy2_mmx_CFLAGS} -fomit-frame-pointer"
fi
dnl Check for Darwin plugin linking flags
@ -434,16 +434,22 @@ dnl
dnl default modules
dnl
BUILTINS="${BUILTINS}"
PLUGINS="${PLUGINS} dummy null rc logger mpeg_es mpeg_audio mpeg_ps mpeg_ts idct idctclassic motion imdct downmix mpeg_adec ac3_adec mpeg_vdec file udp http ipv4 memcpy lpcm_adec ac3_spdif spudec filter_deinterlace filter_invert filter_wall filter_transform filter_distort filter_clone filter_crop fx_scope chroma_i420_rgb chroma_i420_yuy2 chroma_i422_yuy2 chroma_i420_ymga"
PLUGINS="${PLUGINS} misc/dummy/dummy misc/null/null"
PLUGINS="${PLUGINS} control/rc/rc misc/logger/logger access/file access/udp access/http misc/network/ipv4 misc/memcpy/memcpy"
PLUGINS="${PLUGINS} demux/mpeg/es demux/mpeg/audio demux/mpeg/ps demux/mpeg/ts"
PLUGINS="${PLUGINS} codec/mpeg_video/idct/idct codec/mpeg_video/idct/idctclassic codec/mpeg_video/motion/motion codec/a52old/imdct/imdct codec/a52old/downmix/downmix codec/mpeg_audio/mpeg_audio codec/a52old/a52old codec/mpeg_video/mpeg_video codec/lpcm/lpcm codec/spdif/spdif codec/spudec/spudec"
PLUGINS="${PLUGINS} video_filter/deinterlace/deinterlace video_filter/invert video_filter/wall video_filter/transform video_filter/distort video_filter/clone video_filter/crop"
PLUGINS="${PLUGINS} visualization/scope/scope"
PLUGINS="${PLUGINS} video_chroma/i420_rgb video_chroma/i420_yuy2 video_chroma/i422_yuy2 video_chroma/i420_ymga"
dnl
dnl Accelerated modules
dnl
MMX_MODULES="memcpymmx idctmmx motionmmx chroma_i420_rgb_mmx chroma_i420_yuy2_mmx chroma_i422_yuy2_mmx chroma_i420_ymga_mmx"
MMXEXT_MODULES="memcpymmxext idctmmxext motionmmxext"
THREEDNOW_MODULES="memcpy3dn imdct3dn downmix3dn"
SSE_MODULES="imdctsse downmixsse"
ALTIVEC_MODULES="idctaltivec motionaltivec memcpyaltivec"
MMX_MODULES="misc/memcpy/memcpymmx codec/mpeg_video/idct/idctmmx codec/mpeg_video/motion/motionmmx video_chroma/i420_rgb_mmx video_chroma/i420_yuy2_mmx video_chroma/i422_yuy2_mmx video_chroma/i420_ymga_mmx"
MMXEXT_MODULES="misc/memcpy/memcpymmxext codec/mpeg_video/idct/idctmmxext codec/mpeg_video/motion/motionmmxext"
THREEDNOW_MODULES="misc/memcpy/memcpy3dn codec/a52old/imdct/imdct3dn codec/a52old/downmix/downmix3dn"
SSE_MODULES="codec/a52old/imdct/imdctsse codec/a52old/downmix/downmixsse"
ALTIVEC_MODULES="codec/mpeg_video/idct/idctaltivec codec/mpeg_video/motion/motionaltivec misc/memcpy/memcpyaltivec"
AC_CACHE_CHECK([if \$CC groks MMX inline assembly],
[ac_cv_mmx_inline],
@ -627,7 +633,7 @@ then
if test "x${with_dvdcss_tree}" = x
then
AC_CHECK_HEADERS(dvdcss/dvdcss.h,
[ PLUGINS="${PLUGINS} dvd"
[ PLUGINS="${PLUGINS} access/dvd/dvd"
dvd_LDFLAGS="${dvd_LDFLAGS} -ldvdcss" ],
[ AC_MSG_WARN([libdvdcss is no longer provided with vlc; please get libdvdcss from http://www.videolan.org/libdvdcss/ and build it. Then either use --with-dvdcss=<path/where/libdvdcss/was/installed> for dynamic linking (recommended under Unix) or --with-dvdcss-tree=<path/where/libdvdcss/was/built> for static linking (recommended under BeOS, Windows, MacOS X). Alternatively you can use --disable-dvd to disable the DVD plugin.])
AC_MSG_ERROR([cannot find libdvdcss headers]) ])
@ -644,7 +650,7 @@ then
then
dnl Use a custom libdvdcss
AC_MSG_RESULT(${real_dvdcss_tree}/src/.libs/libdvdcss.a)
BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} access/dvd/dvd"
dvd_LDFLAGS="${dvd_LDFLAGS} ${real_dvdcss_tree}/src/.libs/libdvdcss.a"
dvd_CFLAGS="${dvd_CFLAGS} -I${real_dvdcss_tree}/src"
else
@ -656,7 +662,7 @@ then
;;
xno)
dnl Compile without dvdcss (dlopen version, works only under Linux)
PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} access/dvd/dvd"
dvd_CFLAGS="${dvd_CFLAGS} -DGOD_DAMN_DMCA"
dvd_LDFLAGS="${dvd_LDFLAGS} -ldl"
;;
@ -666,7 +672,7 @@ then
then
dnl Use ${with_dvdcss}/include/dvdcss/dvdcss.h
AC_MSG_RESULT(yes)
PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} access/dvd/dvd"
dvd_LDFLAGS="${dvd_LDFLAGS} -L${with_dvdcss}/lib -ldvdcss"
dvd_CFLAGS="${dvd_CFLAGS} -I${with_dvdcss}/include"
else
@ -699,7 +705,7 @@ then
AC_CHECK_HEADERS(dvdread/dvd_reader.h, [
AC_TRY_COMPILE([#include <dvdread/dvd_reader.h>],
[void foo() { int i=DVD_VIDEO_LB_LEN; }],[
PLUGINS="${PLUGINS} dvdread"
PLUGINS="${PLUGINS} access/dvdread/dvdread"
dvdread_LDFLAGS="${dvdread_LDFLAGS} ${test_LDFLAGS} -ldvdread"
dvdread_CFLAGS="${dvdread_CFLAGS} ${test_CFLAGS}"
],[
@ -741,7 +747,7 @@ then
fi
CPPFLAGS="$save_CPPFLAGS $test_CFLAGS"
AC_CHECK_HEADERS(dvdplay/dvdplay.h, [
PLUGINS="${PLUGINS} dvdplay"
PLUGINS="${PLUGINS} access/dvdplay/dvdplay"
dvdplay_LDFLAGS="${dvdplay_LDFLAGS} ${test_LDFLAGS} -ldvdplay -ldvdread"
dvdplay_CFLAGS="${dvdplay_CFLAGS} ${test_CFLAGS}"
],[
@ -775,8 +781,8 @@ then
if test "x${with_dvbpsi_tree}" = "x"
then
AC_CHECK_HEADERS(dvbpsi/dr.h,
[ PLUGINS="${PLUGINS} mpeg_ts_dvbpsi"
mpeg_ts_dvbpsi_LDFLAGS="${mpeg_ts_dvbpsi_LDFLAGS} -ldvbpsi" ], [],
[ PLUGINS="${PLUGINS} demux/mpeg/ts_dvbpsi"
ts_dvbpsi_LDFLAGS="${ts_dvbpsi_LDFLAGS} -ldvbpsi" ], [],
[ AC_MSG_ERROR([cannot find libdvbpsi headers]) ])
else
AC_MSG_CHECKING(for libdvbpsi.a in ${with_dvbpsi_tree})
@ -791,9 +797,9 @@ then
then
dnl Use a custom libdvbpsi
AC_MSG_RESULT(${real_dvbpsi_tree}/src/.libs/libdvbpsi.a)
BUILTINS="${BUILTINS} mpeg_ts_dvbpsi"
mpeg_ts_dvbpsi_LDFLAGS="${mpeg_ts_dvbpsi_LDFLAGS} ${real_dvbpsi_tree}/src/.libs/libdvbpsi.a"
mpeg_ts_dvbpsi_CFLAGS="${mpeg_ts_dvbpsi_CFLAGS} -I${real_dvbpsi_tree}/src"
BUILTINS="${BUILTINS} demux/mpeg/ts_dvbpsi"
ts_dvbpsi_LDFLAGS="${ts_dvbpsi_LDFLAGS} ${real_dvbpsi_tree}/src/.libs/libdvbpsi.a"
ts_dvbpsi_CFLAGS="${ts_dvbpsi_CFLAGS} -I${real_dvbpsi_tree}/src"
else
dnl The given libdvbpsi wasn't built
AC_MSG_RESULT(no)
@ -816,9 +822,9 @@ then
fi
CPPFLAGS="${save_CPPFLAGS} ${test_CFLAGS}"
AC_CHECK_HEADER([dvbpsi/dr.h],[
PLUGINS="${PLUGINS} mpeg_ts_dvbpsi"
mpeg_ts_dvbpsi_LDFLAGS="${mpeg_ts_dvbpsi_LDFLAGS} ${test_LDFLAGS} -ldvbpsi"
mpeg_ts_dvbpsi_CFLAGS="${mpeg_ts_dvbpsi_CFLAGS} ${test_CFLAGS}"
PLUGINS="${PLUGINS} demux/mpeg/ts_dvbpsi"
ts_dvbpsi_LDFLAGS="${ts_dvbpsi_LDFLAGS} ${test_LDFLAGS} -ldvbpsi"
ts_dvbpsi_CFLAGS="${ts_dvbpsi_CFLAGS} ${test_CFLAGS}"
],[
if test "x${enable_dvbpsi}" != "x"
then
@ -839,17 +845,17 @@ AC_ARG_ENABLE(vcd,
if test "x${enable_vcd}" != "xno"
then
AC_EGREP_HEADER(cdrom_msf0,linux/cdrom.h,[
PLUGINS="${PLUGINS} vcd"
PLUGINS="${PLUGINS} access/vcd/vcd"
])
AC_EGREP_HEADER(ioc_toc_header ,sys/cdio.h,[
PLUGINS="${PLUGINS} vcd"
PLUGINS="${PLUGINS} access/vcd/vcd"
AC_DEFINE(HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H, 1, For FreeBSD VCD support)
])
if test "x${SYS}" = "xbsdi"
then
PLUGINS="${PLUGINS} vcd"
PLUGINS="${PLUGINS} access/vcd/vcd"
fi
if test "x${SYS}" = "xdarwin"
@ -866,7 +872,7 @@ AC_ARG_ENABLE(satellite,
[ --enable-satellite satellite card support (default disabled)],
[ if test "x${enable_satellite}" = "xyes"
then
PLUGINS="${PLUGINS} satellite"
PLUGINS="${PLUGINS} access/satellite/satellite"
fi])
dnl
@ -884,14 +890,14 @@ then
AC_EGREP_HEADER(sockaddr_in6,netinet/in.h,
[AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no); have_ipv6=0])
if test x$have_ipv6 = x1; then
PLUGINS="${PLUGINS} ipv6"
PLUGINS="${PLUGINS} misc/network/ipv6"
fi
fi
if test "x${SYS}" = "xmingw32"
then
AC_MSG_CHECKING(for getaddrinfo in ws2tcpip.h)
AC_EGREP_HEADER(addrinfo,ws2tcpip.h,[AC_MSG_RESULT(yes)
PLUGINS="${PLUGINS} ipv6"],[AC_MSG_RESULT(no)])
PLUGINS="${PLUGINS} misc/network/ipv6"],[AC_MSG_RESULT(no)])
fi
dnl
@ -901,7 +907,7 @@ AC_ARG_ENABLE(avi,
[ --enable-avi AVI demux module (default enabled)])
if test "x${enable_avi}" != "xno"
then
PLUGINS="${PLUGINS} avi"
PLUGINS="${PLUGINS} demux/avi/avi"
fi
dnl
@ -945,7 +951,7 @@ then
mad_LDFLAGS="${mad_LDFLAGS} -L${real_mad_tree}/libmad/.libs"
LDFLAGS="${save_LDFLAGS} ${mad_LDFLAGS}"
AC_CHECK_LIB(mad, mad_bit_init, [
BUILTINS="${BUILTINS} mad"
BUILTINS="${BUILTINS} codec/mad/mad"
mad_LDFLAGS="${mad_LDFLAGS} -lmad"
],[ AC_MSG_ERROR([the specified tree hasn't been compiled ])
],[])
@ -960,7 +966,7 @@ then
AC_CHECK_HEADERS(mad.h, ,
[ AC_MSG_ERROR([Cannot find development headers for libmad...]) ])
AC_CHECK_LIB(mad, mad_bit_init, [
PLUGINS="${PLUGINS} mad"
PLUGINS="${PLUGINS} codec/mad/mad"
mad_LDFLAGS="${mad_LDFLAGS} -lmad" ],
[ AC_MSG_ERROR([Cannot find libmad library...]) ])
CFLAGS="${save_CFLAGS}"
@ -999,7 +1005,7 @@ then
then
dnl Use a custom libffmpeg
AC_MSG_RESULT(${real_ffmpeg_tree}/libavcodec/libavcodec.a)
BUILTINS="${BUILTINS} ffmpeg"
BUILTINS="${BUILTINS} codec/ffmpeg/ffmpeg"
ffmpeg_LDFLAGS="${ffmpeg_LDFLAGS} ${real_ffmpeg_tree}/libavcodec/libavcodec.a -lm"
ffmpeg_CFLAGS="${ffmpeg_CFLAGS} -I${real_ffmpeg_tree}/libavcodec"
else
@ -1011,7 +1017,7 @@ then
CFLAGS="${save_CFLAGS} ${ffmpeg_CFLAGS}"
LDFLAGS="${save_LDFLAGS} ${ffmpeg_LDFLAGS} -lm"
AC_CHECK_LIB(avcodec, avcodec_init, [
BUILTINS="${BUILTINS} ffmpeg"
BUILTINS="${BUILTINS} codec/ffmpeg/ffmpeg"
ffmpeg_LDFLAGS="${ffmpeg_LDFLAGS} -lavcodec -lm" ],
[ AC_MSG_ERROR([Cannot find libavcodec library...]) ])
LDFLAGS="${save_LDFLAGS}"
@ -1028,7 +1034,7 @@ if test "x${enable_mp4}" = "xyes"
then
AC_CHECK_HEADER(zlib.h,
AC_CHECK_LIB(z, inflateEnd,
[ PLUGINS="${PLUGINS} mp4"
[ PLUGINS="${PLUGINS} demux/mp4/mp4"
mp4_LDFLAGS="${mp4_LDFLAGS} -lz" ],
[ AC_MSG_ERROR([cannot find zlib library...]) ]),
[ AC_MSG_ERROR([cannot find zlib header...]) ])
@ -1037,7 +1043,7 @@ fi
dnl special case for BeOS
if test "x${SYS}" = "xbeos"
then
PLUGINS="${PLUGINS} beos"
PLUGINS="${PLUGINS} gui/beos/beos"
fi
dnl
@ -1067,7 +1073,7 @@ then
a52_LDFLAGS="${a52_LDFLAGS} -L${real_a52_tree}/liba52/.libs"
LDFLAGS="${save_LDFLAGS} ${a52_LDFLAGS}"
AC_CHECK_LIB(a52, a52_free, [
BUILTINS="${BUILTINS} a52"
BUILTINS="${BUILTINS} codec/a52/a52"
a52_LDFLAGS="${a52_LDFLAGS} -la52 -lm"
a52_CFLAGS="${a52_CFLAGS} -DUSE_A52DEC_TREE"
],[
@ -1086,7 +1092,7 @@ then
else dnl no with args
AC_CHECK_HEADERS(a52dec/a52.h, [
AC_CHECK_LIB(a52, a52_free, [
BUILTINS="${BUILTINS} a52"
BUILTINS="${BUILTINS} codec/a52/a52"
a52_LDFLAGS="${a52_LDFLAGS} -la52 -lm"
a52_CFLAGS="${a52_CFLAGS}"
],[],[-lm])
@ -1101,7 +1107,7 @@ AC_ARG_ENABLE(cinepak,
[ --enable-cinepak Cinepak decoder (default enabled)])
if test "x${enable_cinepak}" != "xno"
then
PLUGINS="${PLUGINS} cinepak"
PLUGINS="${PLUGINS} codec/cinepak/cinepak"
fi
dnl
@ -1113,7 +1119,7 @@ if test "x${enable_vorbis}" != "xno"
then
AC_CHECK_HEADERS(ogg/ogg.h, [
dnl disabled for the moment
#PLUGINS="${PLUGINS} vorbis"
#PLUGINS="${PLUGINS} demux/ogg/ogg codec/vorbis/vorbis"
vorbis_LDFLAGS="${vorbis_LDFLAGS} -lvorbis"
],[])
fi
@ -1134,7 +1140,7 @@ if test "x${enable_x11}" != "xno" &&
(test "x${SYS}" != "xmingw32" || test "x${enable_x11}" = "xyes"); then
CPPFLAGS="${save_CPPFLAGS} -I${x_includes}"
AC_CHECK_HEADERS(X11/Xlib.h, [
PLUGINS="${PLUGINS} x11"
PLUGINS="${PLUGINS} video_output/x11/x11"
x11_LDFLAGS="${x11_LDFLAGS} -L${x_libraries} -lX11 -lXext"
x11_CFLAGS="${x11_CFLAGS} -I${x_includes}"
])
@ -1154,15 +1160,16 @@ if test "x${enable_xvideo}" != "xno" &&
CFLAGS="${save_CFLAGS} -L${x_libraries} -lX11 -lXext"
AC_CHECK_LIB(Xv_pic,XvPutImage,
# We have Xv_pic, that's good, we can build an xvideo.so plugin !
PLUGINS="${PLUGINS} xvideo"
PLUGINS="${PLUGINS} video_output/x11/xvideo"
xvideo_LDFLAGS="${xvideo_LDFLAGS} -L${x_libraries} -lX11 -lXext -lXv_pic"
xvideo_CFLAGS="${xvideo_CFLAGS} -I${x_includes}",
AC_CHECK_LIB(Xv,XvPutImage,
# We don't have Xv_pic, but we have Xv, let's make xvideo.a as builtin
PLUGINS="${PLUGINS} xvideo"
PLUGINS="${PLUGINS} video_output/x11/xvideo"
xvideo_LDFLAGS="${xvideo_LDFLAGS} -L${x_libraries} -lX11 -lXext -lXv"
xvideo_CFLAGS="${xvideo_CFLAGS} -I${x_includes}",
# Otherwise... well, do nothing.
:
)
)
CFLAGS="${save_CFLAGS}"
@ -1200,7 +1207,7 @@ then
fi
if test "x${SDL_CONFIG}" != "xno"
then
PLUGINS="${PLUGINS} sdl"
PLUGINS="${PLUGINS} video_output/sdl/sdl"
sdl_CFLAGS="${sdl_CFLAGS} `${SDL_CONFIG} --cflags`"
sdl_LDFLAGS="${sdl_LDFLAGS} `${SDL_CONFIG} --libs | sed 's,-rdynamic,,'`"
CPPFLAGS="${save_CPPFLAGS} ${sdl_CFLAGS}"
@ -1239,13 +1246,13 @@ then
if test "x${with_directx}" = "x"
then
AC_CHECK_HEADERS(ddraw.h,
[ PLUGINS="${PLUGINS} directx"
[ PLUGINS="${PLUGINS} video_output/directx/directx"
directx_LDFLAGS="${directx_LDFLAGS} -lgdi32" ])
else
AC_MSG_CHECKING(for directX headers in ${with_directx})
if test -f ${with_directx}/ddraw.h
then
PLUGINS="${PLUGINS} directx"
PLUGINS="${PLUGINS} video_output/directx/directx"
directx_LDFLAGS="${directx_LDFLAGS} -lgdi32"
directx_CFLAGS="${directx_CFLAGS} -I${with_directx}"
AC_MSG_RESULT(yes)
@ -1265,7 +1272,7 @@ AC_ARG_ENABLE(fb,
if test "x${enable_fb}" != "xno"
then
AC_CHECK_HEADERS(linux/fb.h, [
PLUGINS="${PLUGINS} fb"
PLUGINS="${PLUGINS} video_output/fb/fb"
])
fi
@ -1276,7 +1283,7 @@ AC_ARG_ENABLE(mga,
[ --enable-mga Linux kernel Matrox support (default disabled)],
[ if test "x${enable_mga}" = "xyes"
then
PLUGINS="${PLUGINS} mga xmga"
PLUGINS="${PLUGINS} video_output/mga/mga video_output/mga/xmga"
fi ])
dnl
@ -1286,7 +1293,7 @@ AC_ARG_ENABLE(ggi,
[ --enable-ggi GGI support (default disabled)])
if test "x${enable_ggi}" = "xyes"
then
PLUGINS="${PLUGINS} ggi"
PLUGINS="${PLUGINS} video_output/ggi/ggi"
ggi_LDFLAGS="${ggi_LDFLAGS} -lggi"
AC_ARG_WITH(ggi,
[ --with-ggi=PATH path to libggi],
@ -1304,7 +1311,7 @@ AC_ARG_ENABLE(glide,
[ --enable-glide Glide (3dfx) support (default disabled)])
if test "x${enable_glide}" = "xyes"
then
PLUGINS="${PLUGINS} glide"
PLUGINS="${PLUGINS} video_output/glide/glide"
glide_LDFLAGS="${glide_LDFLAGS} -lglide2x -lm"
glide_CFLAGS="${glide_CFLAGS} -I/usr/include/glide"
AC_ARG_WITH(glide,
@ -1326,7 +1333,7 @@ then
AC_CHECK_HEADER(aalib.h,have_aa="true",have_aa="false")
if test "x${have_aa}" = "xtrue"
then
PLUGINS="${PLUGINS} aa"
PLUGINS="${PLUGINS} video_output/aa/aa"
aa_LDFLAGS="${aa_LDFLAGS} -laa"
fi
fi
@ -1347,7 +1354,7 @@ if test "x${enable_dsp}" != "xno" &&
(test "x${SYS}" != "xmingw32" || test "x${enable_dsp}" = "xyes")
then
AC_CHECK_HEADERS(soundcard.h sys/soundcard.h machine/soundcard.h, [
PLUGINS="${PLUGINS} dsp"
PLUGINS="${PLUGINS} audio_output/dsp/dsp"
AC_CHECK_LIB(ossaudio,main,dsp_LDFLAGS="${dsp_LDFLAGS} -lossaudio")
])
fi
@ -1362,7 +1369,7 @@ AC_ARG_ENABLE(esd,
AC_PATH_PROG(ESD_CONFIG, esd-config, no)
if test "x${ESD_CONFIG}" != "xno"
then
PLUGINS="${PLUGINS} esd"
PLUGINS="${PLUGINS} audio_output/esd/esd"
esd_CFLAGS="${esd_CFLAGS} `${ESD_CONFIG} --cflags`"
esd_LDFLAGS="${esd_LDFLAGS} `${ESD_CONFIG} --libs`"
fi
@ -1378,7 +1385,7 @@ AC_ARG_ENABLE(arts,
AC_PATH_PROG(ARTS_CONFIG, artsc-config, no)
if test "x${ARTS_CONFIG}" != "xno"
then
PLUGINS="${PLUGINS} arts"
PLUGINS="${PLUGINS} audio_output/arts/arts"
arts_CFLAGS="${arts_CFLAGS} `${ARTS_CONFIG} --cflags`"
arts_LDFLAGS="${arts_LDFLAGS} `${ARTS_CONFIG} --libs `"
fi
@ -1394,7 +1401,7 @@ AC_ARG_ENABLE(alsa,
AC_CHECK_HEADER(alsa/asoundlib.h, AC_CHECK_LIB(asound, main, have_alsa="true", have_alsa="false"),have_alsa="false")
if test "x${have_alsa}" = "xtrue"
then
PLUGINS="${PLUGINS} alsa"
PLUGINS="${PLUGINS} audio_output/alsa/alsa"
alsa_LDFLAGS="${alsa_LDFLAGS} -lasound -lm -ldl"
fi
fi])
@ -1406,7 +1413,7 @@ AC_ARG_ENABLE(waveout,
[ --enable-waveout Win32 waveOut module (default enabled on Win32)])
if test "x${enable_waveout}" != "xno" -a "x${SYS}" = "xmingw32"
then
PLUGINS="${PLUGINS} waveout"
PLUGINS="${PLUGINS} audio_output/waveout/waveout"
waveout_LDFLAGS="-lwinmm"
fi
@ -1454,7 +1461,7 @@ then
])
if test "x${ac_cv_gtk_headers}" = "xyes"
then
PLUGINS="${PLUGINS} gtk"
PLUGINS="${PLUGINS} gui/gtk/gtk"
ALIASES="${ALIASES} gvlc"
fi
CPPFLAGS="${save_CPPFLAGS}"
@ -1499,7 +1506,7 @@ then
])
if test "x${ac_cv_gtk_headers}" = "xyes"
then
PLUGINS="${PLUGINS} familiar"
PLUGINS="${PLUGINS} gui/familiar/familiar"
fi
CPPFLAGS="${save_CPPFLAGS}"
fi
@ -1521,7 +1528,7 @@ AC_ARG_ENABLE(gnome,
# now look for the gnome.h header
CPPFLAGS="${save_CPPFLAGS} ${gnome_CFLAGS}"
AC_CHECK_HEADERS(gnome.h, [
PLUGINS="${PLUGINS} gnome"
PLUGINS="${PLUGINS} gui/gtk/gnome"
ALIASES="${ALIASES} gnome-vlc"
],[
AC_MSG_ERROR([Can't find gnome headers. Please install the gnome
@ -1536,7 +1543,7 @@ dnl
AC_ARG_ENABLE(qt,
[ --enable-qt Qt interface support (default disabled)],
[if test "x${enable_qt}" = "xyes"; then
PLUGINS="${PLUGINS} qt"
PLUGINS="${PLUGINS} gui/qt/qt"
ALIASES="${ALIASES} qvlc"
qt_LDFLAGS="${qt_LDFLAGS} -lqt -L${QTDIR}/lib"
qt_CFLAGS="${qt_CFLAGS} -I/usr/include/qt -I${QTDIR}/include"
@ -1554,7 +1561,7 @@ dnl
AC_ARG_ENABLE(kde,
[ --enable-kde KDE interface support (default disabled)],
[if test "x${enable_kde}" = "xyes"; then
PLUGINS="${PLUGINS} kde"
PLUGINS="${PLUGINS} gui/kde/kde"
ALIASES="${ALIASES} kvlc"
kde_LDFLAGS="${kde_LDFLAGS} -L${KDEDIR}/lib -lkfile"
kde_CFLAGS="${kde_CFLAGS} -I/usr/include/kde -I/usr/include/qt"
@ -1574,11 +1581,11 @@ AC_ARG_ENABLE(macosx,
[ --enable-macosx MacOS X support (default enabled on MacOS X)],
[if test "x${enable_macosx}" = "xyes"
then
BUILTINS="${BUILTINS} macosx"
BUILTINS="${BUILTINS} gui/macosx/macosx"
macosx_LDFLAGS="${macosx_LDFLAGS} -framework CoreAudio -framework AudioToolbox -framework IOKit -framework Cocoa -framework Carbon -framework AGL -framework QuickTime -lobjc -ObjC"
fi],
[AC_CHECK_HEADERS(Cocoa/Cocoa.h,
BUILTINS="${BUILTINS} macosx"
BUILTINS="${BUILTINS} gui/macosx/macosx"
macosx_LDFLAGS="${macosx_LDFLAGS} -framework CoreAudio -framework AudioToolbox -framework IOKit -framework Cocoa -framework Carbon -framework AGL -framework QuickTime -lobjc -ObjC"
)])
@ -1590,7 +1597,7 @@ AC_ARG_ENABLE(qnx,
if test "x${enable_qnx}" != "xno"
then
AC_CHECK_HEADERS(Ph.h, [
PLUGINS="${PLUGINS} qnx"
PLUGINS="${PLUGINS} gui/qnx/qnx"
qnx_LDFLAGS="${qnx_LDFLAGS} -lasound -lph"
])
fi
@ -1608,7 +1615,7 @@ AC_ARG_ENABLE(intfwin,
then
BCBUILDER="${with_bcbuilder}"
fi
PLUGINS="${PLUGINS} intfwin"
PLUGINS="${PLUGINS} gui/win32/win32"
fi ])
dnl
@ -1617,7 +1624,7 @@ dnl
AC_ARG_ENABLE(ncurses,
[ --enable-ncurses ncurses interface support (default disabled)],
[if test "x${enable_ncurses}" = "xyes"; then
PLUGINS="${PLUGINS} ncurses"
PLUGINS="${PLUGINS} gui/ncurses/ncurses"
ncurses_LDFLAGS="${ncurses_LDFLAGS} -lncurses"
fi])
@ -1631,7 +1638,7 @@ then
AC_CHECK_HEADER(xosd.h, have_xosd="true", have_xosd="false")
if test "x${have_xosd}" = "xtrue"
then
PLUGINS="${PLUGINS} xosd"
PLUGINS="${PLUGINS} visualization/xosd/xosd"
xosd_LDFLAGS="${xosd_LDFLAGS} -lxosd"
fi
fi
@ -1646,7 +1653,7 @@ then
AC_CHECK_HEADER(lirc/lirc_client.h, AC_CHECK_LIB(lirc_client, lirc_init, have_lirc="true", have_lirc="false"),have_lirc="false")
if test "x${have_lirc}" = "xtrue"
then
PLUGINS="${PLUGINS} lirc"
PLUGINS="${PLUGINS} control/lirc/lirc"
lirc_LDFLAGS="${lirc_LDFLAGS} -llirc_client"
fi
fi
@ -1879,11 +1886,11 @@ AC_SUBST(mozilla_CFLAGS)
AC_SUBST(a52_CFLAGS)
AC_SUBST(arts_CFLAGS)
AC_SUBST(chroma_i420_yuy2_mmx_CFLAGS)
AC_SUBST(i420_yuy2_mmx_CFLAGS)
AC_SUBST(dvd_CFLAGS)
AC_SUBST(dvdread_CFLAGS)
AC_SUBST(dvdplay_CFLAGS)
AC_SUBST(mpeg_ts_dvbpsi_CFLAGS)
AC_SUBST(ts_dvbpsi_CFLAGS)
AC_SUBST(directx_CFLAGS)
AC_SUBST(esd_CFLAGS)
AC_SUBST(familiar_CFLAGS)
@ -1912,16 +1919,16 @@ AC_SUBST(aa_LDFLAGS)
AC_SUBST(alsa_LDFLAGS)
AC_SUBST(arts_LDFLAGS)
AC_SUBST(beos_LDFLAGS)
AC_SUBST(chroma_i420_rgb_LDFLAGS)
AC_SUBST(i420_rgb_LDFLAGS)
AC_SUBST(directx_LDFLAGS)
AC_SUBST(dsp_LDFLAGS)
AC_SUBST(dvd_LDFLAGS)
AC_SUBST(dvdread_LDFLAGS)
AC_SUBST(dvdplay_LDFLAGS)
AC_SUBST(mpeg_ts_dvbpsi_LDFLAGS)
AC_SUBST(ts_dvbpsi_LDFLAGS)
AC_SUBST(esd_LDFLAGS)
AC_SUBST(familiar_LDFLAGS)
AC_SUBST(filter_distort_LDFLAGS)
AC_SUBST(distort_LDFLAGS)
AC_SUBST(ffmpeg_LDFLAGS)
AC_SUBST(mp4_LDFLAGS)
AC_SUBST(ggi_LDFLAGS)

262
doc/mad/API Normal file
View File

@ -0,0 +1,262 @@
MAD API documentation collected from e-mails of Joe Drew and Rob Leslie.
The original e-mails can be found in the docs directory. They contain the
same information as is presented below.
INDEX
======
1. I/O Synchronous Mode
2. Low-level API
1. I/O SYNCHRONOUS MODE (extract from Joe Drew)
===============================================
MAD operates with callbacks for functions. Each of these functions is
expected to return type enum mad_flow; this allows you to control the
decoding process.
MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take
this into account when outputting samples to the sound card.
Related to the above, since MAD outputs type mad_fixed_t, unless you can
output with 32-bit accuracy (most sound cards can't), you will have to
quantize, round, dither, etc these samples to 16-bit (or whatever you
need.) While there is a sample routine in minimad.c, if you want good
quality you'll either want to roll your own or take a look in madplay's
sources.
Integral to understanding MAD: MAD is a decoding library only. You
handle input and output; you're responsible for fast-forwarding and
rewinding, if you want that type of functionality. All that MAD will do
is take input from you, decode the MPEG frames, give you some
information about them, and give you the decoded PCM data.
Now, the nitty-gritty information.
First, you need a mad_decoder struct. This holds all information about
how you want your stream decoded, such as input/output functions, error
handling functions, etc.
mad_decoder_init() sets this structure up for you.
struct mad_decoder decoder;
struct my_playbuf playbuf;
mad_decoder_init(&decoder, &playbuf, input_func, header_func, /*filter*/
0, output_func, /*error*/ 0, /* message */ 0);
In this example, the function called to get more data is set to
input_func, the function called after MPEG headers have been decoded is
header_func, the function called after all sound data has been decoded
to PCM (for output) is output_func, and the filter, error, and message
functions are unset.
Now, MAD runs in a constant decoding loop. It runs something along the
following lines:
if I'm out of data
call input_func
if input_func says there's no more data,
quit
decode the header and call header_func
decode the mpeg audio data
call the filter function
call the output function
loop
Now, this is an oversimplification obviously. The important thing to
realise is that at every step of the process you can tell MAD what to
do.
Since all of these functions return enum mad_flow, you can tell MAD to
do any of the following:
enum mad_flow {
MAD_FLOW_CONTINUE = 0x0000, /* Keep decoding this stream */
MAD_FLOW_STOP = 0x0010, /* Stop decoding this stream, but exit
normally */
MAD_FLOW_BREAK = 0x0011, /* Stop decoding this stream, and exit
with an error */
MAD_FLOW_IGNORE = 0x0020 /* Don't decode this frame,
but continue afterwards */
};
Most of the time you'll probably want to return MAD_FLOW_CONTINUE. In
every case, you'll have to return one of these values from the functions
you define.
This is the definition of each of the functions:
enum mad_flow (*input_func)(void *, struct mad_stream *);
enum mad_flow (*header_func)(void *, struct mad_header const *);
enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct
mad_frame *);
enum mad_flow (*output_func)(void *, struct mad_header const *, struct
mad_pcm *);
enum mad_flow (*error_func)(void *, struct mad_stream *, struct
mad_frame *);
enum mad_flow (*message_func)(void *, void *, unsigned int *);
In each of these functions the void* pointer passed to the function is
your "playbuf" structure. This can hold whatever you want - for example,
song title, length, number of frames - just remember to re-cast it to
the type you've defined.
input_func takes a mad_stream pointer. Most of the time what you'll want
to do is something along the lines of the following:
if (more_data_available)
buffer = refill_buffer();
mad_stream_buffer(stream, buffer, length_of_buffer);
return MAD_FLOW_CONTINUE;
else
return MAD_FLOW_STOP;
(On many systems you'll want to use mmap() for this.)
header_func takes a mad_header pointer. This contains most of the
important information about a given frame; in constant bitrate files, it
can contain most of the important information about the stream. It will
give you the length of that frame, using mad_timer_t; the audio layer;
extension; bitrate... the list is long. Read frame.h or mad.h in the
frame.h area for more information.
Again, return MAD_FLOW_{CONTINUE,STOP,BREAK} depending on outside
conditions.
The only other function I have firsthand information on is output_func;
in this case, you are given a pointer to struct mad_pcm. This gives you
the sampling rate, number of channels, and number of samples per
channel; doing something like the following should work:
mad_fixed_t *left_channel = pcm->samples[0], *right_channel =
pcm->samples[1];
int nsamples = pcm->length;
signed int sample;
unsigned char * buffer = some_buffer;
unsigned char * ptr = buffer;
while (nsamples--)
{
sample = (signed int) do_downsample(*left_ch++)
*ptr++ = (unsigned char) (sample >> 0);
*ptr++ = (unsigned char) (sample >> 8);
sample = (signed int) do_downsample(*right_ch++)
*ptr++ = (unsigned char) (sample >> 0);
*ptr++ = (unsigned char) (sample >> 8);
}
output buffer to device.
Be sure to handle the big-endian case (autoconf can test for this), and
also the mono (1 channel) case. See mad.c in mpg321, at the end of the
file, for an example.
Information on the other (error, filter, message) functions would be
appreciated, though I think in knowing this information anyone should be
able to puzzle it out.
Now that the decoder is set up with all these callback functions, you
call
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
and then
mad_decoder_finish(&decoder);
Once you've called mad_decoder_finish, you can re-use the decoder
struct, if you're, for example, within a playlist. Incidentally, all MAD
structures have similar mad_(whatever)_init and mad_(whatever)_finish
functions.
I hope this helps people get their feet wet with MAD. Read the source,
and particularly mad.h - there are a lot of things there you might not
expect. Rob has done a good job in making MAD a complete solution. :)
2. LOW-LEVEL API (extract from Rob Leslie)
==========================================
By way of clarification, MAD also has a low-level API which does not use
callbacks. You can control the entire decoding process yourself more or less
as follows:
/* load buffer with your MPEG audio data */
mad_stream_buffer(&stream, buffer, buflen);
while (1) {
mad_frame_decode(&frame, &stream);
mad_synth_frame(&synth, &frame);
/* output PCM samples in synth.pcm */
}
This is vastly simplified, but it shows the general idea. mad_frame_decode()
decodes the next frame's header and subband samples. mad_synth_frame() takes
those subband samples and synthesizes PCM samples.
It is also possible to call mad_header_decode() before mad_frame_decode().
This just gives you the frame's header info, in case that's all you want, or
perhaps to help you decide whether you want to decode the rest of the frame.
As Joe mentions, each of the stream, frame, and synth structs needs to be
initialized and "finished" before and after use:
struct mad_stream stream;
struct mad_frame frame;
struct mad_synth synth;
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
/* ... */
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
You can work with just a struct mad_header instead of a struct mad_frame if
you only want to decode frame headers.
Joe writes:
> MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take
> this into account when outputting samples to the sound card.
This isn't quite right: the mad_fixed_t type is not necessarily little-endian.
It's the same endianness as the native integer types. Also, it's only
guaranteed to be *at least* 32 bits wide.
The fixed-point sample format is important to understand, and I recommend
reading the comments in libmad/fixed.h. The thing to remember when converting
MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD
encodes samples as numbers in the full-scale range [-1.0, +1.0) where the
binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer.
However, you need to be prepared to handle clipping as some numbers may be
less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka
1 << MAD_F_FRACBITS).
> Information on the other (error, filter, message) functions would be
> appreciated, though I think in knowing this information anyone should be
> able to puzzle it out.
In the high-level API, the error callback function is called whenever a
decoding error occurs. The error number is in stream->error.
The filter callback function is called after decoding a frame, but before
synthesis. Here it is possible to modify the frame's subband samples, for
example to perform a uniform attenuation/amplification, or to do other special
processing in the frequency domain.
The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is
called whenever the parent process sends a message via mad_decoder_message().
This callback can generate a reply by overwriting the message buffer that is
passed to it. (The size of the reply must be the same or smaller than the
message.)

27
doc/mad/BUGS Normal file
View File

@ -0,0 +1,27 @@
bug #09/11/2001-1: (FIXED 20/11/2001, by JP Saman)
Makefile.opts.in and Makefile.opts static libmad.a library is not filled in automatically by configure.
It should say in Makefile.opts LIB_MAD=lib/libmad.a
bug #09/11/2001-2: (FIXED december 2001)
Libmad is not included in the vlc source code. It is assumed that the library is already available on the machine
where the plugin is compiled on. The configure option --with-libmad tells the script where libmad.a or libmad.so library
and mad.h include file are installed. E.g. if libmad.a is in /usr/lib and mad.h is in /usr/include then the configure
option should be --with-libmad=/usr
bug #12/11/2001-1 (FIXED january 2002)
smoothen out audio in libmad_output callback function, by optimizing conversion routines. After investigation
and experimenting I found out that my input routine and output routine were not balanced correctly with
respect to buffer sizes. A lot of data got lost. I fixed that, but still need a bater scaling/smoothing routine
for the audio.
I tried a simpler audio scale function, but it did not improve the audio much. Not even on Intel machine, so I suspect the audio
decoding to need a bit too much time. The next thing to try is to steer the decoding process by hand (going to a lower level API).
Rewriting mad plugin to use a lower level API was not needed. I found the problem by reviewing libmad example code madlld and bbplay.
This resulted in a partial rewrite a some parts and a lot of testing. There are still some issues when trying on different CPU's
but this will sort itself gradually.
bug #20/11/2001-1 (FIXED 25/11/2001, by JP Saman)
synchronization between audio and video output is lost. In libmad_output a timestamp is set on the audio data, but
it points to a later video frame, then when the audio data was read. How can I set the correct timestamp on the
audio fifo at the time it was read from the bitstream, so that it matches the video frame it belongs to?
Solution: Do it in two steps, in the input function save i_pts of fifo and in output function pass saved i_pts to
aout_fifo.

63
doc/mad/DESIGN Normal file
View File

@ -0,0 +1,63 @@
File: Plugin mad for vlc is based upon libmad from the mad distribution.
Author: Jean-Paul Saman <jpsaman@wxs.nl>
Directories:
============
vlc/plugins/mad : mad audio decoder plugin for vlc
Interface functions
===================
The following interface functions are implemented in the mad plugin.
decoder_Probe : vlc probes for plugin capabilities
decoder_Run : vlc starts a decoder plugin by calling this function
InitThread : routine to do some initializations
EndThread : cleanup function
The following functions are callback functions for the mad decoder library:
libmad_input : called when input data is needed
libmad_output : called whenever a frame has been decoded
libmad_header : called upon decoding of only a frame header
libmad_messages : libmad messages
libmad_error : called whenever an error occured during the decoding process
Design: (ASCII art)
=======
It represents the function call flow viewed from the vlc main program. The main program is in charge of allocating decoders,
initializing, starting and stopping them.
---------------
| <library> |
| libmad |
---------------
^
|
---------------
| <plugin> |
| mad |
_______________
^
|
________________________
| <decoder interface> |
| vlc plugin interface |
________________________
Interface view:
===============
[mad decoder plugin]
----------------------
vlc decoder interface -> | mad_adec mad_libmad | -> libmad
-----------------------
Rationel:
========
Keeping libmad as a separate library on the system, either dynamic or statically linked in, makes maintenance so much simpeler.
Merging with a new libmad version should be straight forward as long as the interface stays stable.
There is another benefit: Disk (actually flash ROM) resources and memory are very limited on a iPaq.
Other programs or utilities like madplay and BBplay can make use of the same libmad version we do. In this way
limiting the needed storage place on disk (flash ROM). Also this is only possible when the interface stays the same.

40
doc/mad/TODO Normal file
View File

@ -0,0 +1,40 @@
TODO: (Jean-Paul Saman <jpsaman@wxs.nl>)
[1 - 30 October 2001, done]
introduce libmad in vlc-dev code tree, this includes:
configure from top level of source tree
compilable from top level of source tree
[2 - 25 November 2001, done]
creating basic mad plugin in vlc-dev code tree, this include:
writing most simple vlc-plugin (no fancy stuf)
configurable from top level of source tree
compilable from top level of source tree
[3 - 25 November 2001, done]
test basic mad plugin
native Intel
native iPaq
[4 - 26 November 2001, done]
commit to current vlc-dev tree in CVS at VideoLan
fix broken things and conflicts
run tests again (see [3])
[5 - all ready done by Christophe Massiot]
make cross-compile possible for vlc without interface. With interface it is to damn difficult to do cross-compilation.
[6 - done by fenrir ]
extending mad plugin with more features
do fancy stuff (enable MP3 decoding)
[7 - done ]
test extended plugin
native Intel
native iPaq
[8 - done ]
commit to current vlc-dev tree in CVS at Videolan
fix broken things and conflicts
run tests again (see [7])

174
doc/mad/joe_drew.txt Normal file
View File

@ -0,0 +1,174 @@
Subject: [mad-dev] Some information about programming with MAD (in synchronous mode)
As the author of mpg321, I too faced the problem of MAD not being
documented. However, in looking at minimad.c, and re-writing mpg321 to
use MAD, I came to understand it better. Here's some information which
will help anybody start out with MAD:
First, some basic information.
MAD operates with callbacks for functions. Each of these functions is
expected to return type enum mad_flow; this allows you to control the
decoding process.
MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take
this into account when outputting samples to the sound card.
Related to the above, since MAD outputs type mad_fixed_t, unless you can
output with 32-bit accuracy (most sound cards can't), you will have to
quantize, round, dither, etc these samples to 16-bit (or whatever you
need.) While there is a sample routine in minimad.c, if you want good
quality you'll either want to roll your own or take a look in madplay's
sources.
Integral to understanding MAD: MAD is a decoding library only. You
handle input and output; you're responsible for fast-forwarding and
rewinding, if you want that type of functionality. All that MAD will do
is take input from you, decode the MPEG frames, give you some
information about them, and give you the decoded PCM data.
Now, the nitty-gritty information.
First, you need a mad_decoder struct. This holds all information about
how you want your stream decoded, such as input/output functions, error
handling functions, etc.
mad_decoder_init() sets this structure up for you.
struct mad_decoder decoder;
struct my_playbuf playbuf;
mad_decoder_init(&decoder, &playbuf, input_func, header_func, /*filter*/
0, output_func, /*error*/ 0, /* message */ 0);
In this example, the function called to get more data is set to
input_func, the function called after MPEG headers have been decoded is
header_func, the function called after all sound data has been decoded
to PCM (for output) is output_func, and the filter, error, and message
functions are unset.
Now, MAD runs in a constant decoding loop. It runs something along the
following lines:
if I'm out of data
call input_func
if input_func says there's no more data,
quit
decode the header and call header_func
decode the mpeg audio data
call the filter function
call the output function
loop
Now, this is an oversimplification obviously. The important thing to
realise is that at every step of the process you can tell MAD what to
do.
Since all of these functions return enum mad_flow, you can tell MAD to
do any of the following:
enum mad_flow {
MAD_FLOW_CONTINUE = 0x0000, /* Keep decoding this stream */
MAD_FLOW_STOP = 0x0010, /* Stop decoding this stream, but exit
normally */
MAD_FLOW_BREAK = 0x0011, /* Stop decoding this stream, and exit
with an error */
MAD_FLOW_IGNORE = 0x0020 /* Don't decode this frame,
but continue afterwards */
};
Most of the time you'll probably want to return MAD_FLOW_CONTINUE. In
every case, you'll have to return one of these values from the functions
you define.
This is the definition of each of the functions:
enum mad_flow (*input_func)(void *, struct mad_stream *);
enum mad_flow (*header_func)(void *, struct mad_header const *);
enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct
mad_frame *);
enum mad_flow (*output_func)(void *, struct mad_header const *, struct
mad_pcm *);
enum mad_flow (*error_func)(void *, struct mad_stream *, struct
mad_frame *);
enum mad_flow (*message_func)(void *, void *, unsigned int *);
In each of these functions the void* pointer passed to the function is
your "playbuf" structure. This can hold whatever you want - for example,
song title, length, number of frames - just remember to re-cast it to
the type you've defined.
input_func takes a mad_stream pointer. Most of the time what you'll want
to do is something along the lines of the following:
if (more_data_available)
buffer = refill_buffer();
mad_stream_buffer(stream, buffer, length_of_buffer);
return MAD_FLOW_CONTINUE;
else
return MAD_FLOW_STOP;
(On many systems you'll want to use mmap() for this.)
header_func takes a mad_header pointer. This contains most of the
important information about a given frame; in constant bitrate files, it
can contain most of the important information about the stream. It will
give you the length of that frame, using mad_timer_t; the audio layer;
extension; bitrate... the list is long. Read frame.h or mad.h in the
frame.h area for more information.
Again, return MAD_FLOW_{CONTINUE,STOP,BREAK} depending on outside
conditions.
The only other function I have firsthand information on is output_func;
in this case, you are given a pointer to struct mad_pcm. This gives you
the sampling rate, number of channels, and number of samples per
channel; doing something like the following should work:
mad_fixed_t *left_channel = pcm->samples[0], *right_channel =
pcm->samples[1];
int nsamples = pcm->length;
signed int sample;
unsigned char * buffer = some_buffer;
unsigned char * ptr = buffer;
while (nsamples--)
{
sample = (signed int) do_downsample(*left_ch++)
*ptr++ = (unsigned char) (sample >> 0);
*ptr++ = (unsigned char) (sample >> 8);
sample = (signed int) do_downsample(*right_ch++)
*ptr++ = (unsigned char) (sample >> 0);
*ptr++ = (unsigned char) (sample >> 8);
}
output buffer to device.
Be sure to handle the big-endian case (autoconf can test for this), and
also the mono (1 channel) case. See mad.c in mpg321, at the end of the
file, for an example.
Information on the other (error, filter, message) functions would be
appreciated, though I think in knowing this information anyone should be
able to puzzle it out.
Now that the decoder is set up with all these callback functions, you
call
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
and then
mad_decoder_finish(&decoder);
Once you've called mad_decoder_finish, you can re-use the decoder
struct, if you're, for example, within a playlist. Incidentally, all MAD
structures have similar mad_(whatever)_init and mad_(whatever)_finish
functions.
I hope this helps people get their feet wet with MAD. Read the source,
and particularly mad.h - there are a lot of things there you might not
expect. Rob has done a good job in making MAD a complete solution. :)
--
Joe Drew <hoserhead@woot.net> <drew@debian.org>
Please encrypt email sent to me.

124
doc/mad/rob_leslie.txt Normal file
View File

@ -0,0 +1,124 @@
From - Mon Nov 5 09:19:09 2001
Return-Path: <mad-dev-admin@lists.mars.org>
Received: from smtp01.wxs.nl ([195.121.5.15]) by po05.wxs.nl
(Netscape Messaging Server 4.15) with ESMTP id GLLMFJ00.3DF for
<jpsaman@wxs.nl>; Mon, 22 Oct 2001 10:33:19 +0200
Received: from surveyor.mars.org ([216.98.134.66]) by
smtp01.wxs.nl (Netscape Messaging Server 4.15) with ESMTP id
GLLMFZ00.C2Z for <jpsaman@wxs.nl>; Mon, 22 Oct 2001 10:33:35 +0200
Received: from surveyor.mars.org (localhost [127.0.0.1])
by surveyor.mars.org (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id BAA07654;
Mon, 22 Oct 2001 01:32:07 -0700
Received: from mars.org (localhost [127.0.0.1])
by surveyor.mars.org (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id BAA07629
for <mad-dev@lists.mars.org>; Mon, 22 Oct 2001 01:31:30 -0700
Message-Id: <200110220831.BAA07629@surveyor.mars.org>
X-Authentication-Warning: surveyor.mars.org: Host localhost [127.0.0.1] claimed to be mars.org
From: Rob Leslie <rob@mars.org>
To: mad-dev@lists.mars.org
Subject: Re: [mad-dev] Some information about programming with MAD (in synchronous mode)
In-reply-to: Your message of "21 Oct 2001 16:13:19 EDT."
<1003695199.24019.56.camel@pisces>
Mime-Version: 1.0 (generated by tm-edit 7.106)
Content-Type: text/plain; charset=US-ASCII
Sender: mad-dev-admin@lists.mars.org
Errors-To: mad-dev-admin@lists.mars.org
X-BeenThere: mad-dev@lists.mars.org
X-Mailman-Version: 2.0.1
Precedence: bulk
List-Help: <mailto:mad-dev-request@lists.mars.org?subject=help>
List-Post: <mailto:mad-dev@lists.mars.org>
List-Subscribe: <http://www.mars.org/bin/mailman/listinfo/mad-dev>,
<mailto:mad-dev-request@lists.mars.org?subject=subscribe>
List-Id: MAD developer's mailing list <mad-dev.lists.mars.org>
List-Unsubscribe: <http://www.mars.org/bin/mailman/listinfo/mad-dev>,
<mailto:mad-dev-request@lists.mars.org?subject=unsubscribe>
List-Archive: <http://www.mars.org/mailman/public/mad-dev/>
Date: Mon, 22 Oct 2001 01:31:30 -0700
X-Mozilla-Status: 8011
X-Mozilla-Status2: 00000000
X-UIDL: 1879-1001307689
Joe Drew wrote some good info on the MAD high-level API that I hope will be
helpful to others.
By way of clarification, MAD also has a low-level API which does not use
callbacks. You can control the entire decoding process yourself more or less
as follows:
/* load buffer with your MPEG audio data */
mad_stream_buffer(&stream, buffer, buflen);
while (1) {
mad_frame_decode(&frame, &stream);
mad_synth_frame(&synth, &frame);
/* output PCM samples in synth.pcm */
}
This is vastly simplified, but it shows the general idea. mad_frame_decode()
decodes the next frame's header and subband samples. mad_synth_frame() takes
those subband samples and synthesizes PCM samples.
It is also possible to call mad_header_decode() before mad_frame_decode().
This just gives you the frame's header info, in case that's all you want, or
perhaps to help you decide whether you want to decode the rest of the frame.
As Joe mentions, each of the stream, frame, and synth structs needs to be
initialized and "finished" before and after use:
struct mad_stream stream;
struct mad_frame frame;
struct mad_synth synth;
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
/* ... */
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
You can work with just a struct mad_header instead of a struct mad_frame if
you only want to decode frame headers.
Joe writes:
> MAD always outputs 32-bit (well, mad_fixed_t) little-endian data. Take
> this into account when outputting samples to the sound card.
This isn't quite right: the mad_fixed_t type is not necessarily little-endian.
It's the same endianness as the native integer types. Also, it's only
guaranteed to be *at least* 32 bits wide.
The fixed-point sample format is important to understand, and I recommend
reading the comments in libmad/fixed.h. The thing to remember when converting
MAD's fixed-point integer samples to 16-bit PCM (or whatever) is that MAD
encodes samples as numbers in the full-scale range [-1.0, +1.0) where the
binary point is placed 28 (MAD_F_FRACBITS) bits to the left of the integer.
However, you need to be prepared to handle clipping as some numbers may be
less than -1.0 (-MAD_F_ONE) or greater than or equal to +1.0 (MAD_F_ONE, aka
1 << MAD_F_FRACBITS).
> Information on the other (error, filter, message) functions would be
> appreciated, though I think in knowing this information anyone should be
> able to puzzle it out.
In the high-level API, the error callback function is called whenever a
decoding error occurs. The error number is in stream->error.
The filter callback function is called after decoding a frame, but before
synthesis. Here it is possible to modify the frame's subband samples, for
example to perform a uniform attenuation/amplification, or to do other special
processing in the frequency domain.
The message callback function is only used with MAD_DECODER_MODE_ASYNC, and is
called whenever the parent process sends a message via mad_decoder_message().
This callback can generate a reply by overwriting the message buffer that is
passed to it. (The size of the reply must be the same or smaller than the
message.)
Cheers,
-rob

View File

@ -2,7 +2,7 @@
* audio_output.h : audio output thread interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: audio_output.h,v 1.50 2002/07/31 20:56:50 sam Exp $
* $Id: audio_output.h,v 1.51 2002/08/04 17:23:41 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
@ -163,7 +163,7 @@ struct aout_thread_t
#define AOUT_FMT_S8 0x00000040
#define AOUT_FMT_U16_LE 0x00000080 /* Little endian U16 */
#define AOUT_FMT_U16_BE 0x00000100 /* Big endian U16 */
#define AOUT_FMT_AC3 0x00000400 /* Dolby Digital AC3 */
#define AOUT_FMT_A52 0x00000400 /* Dolby Digital A52 */
#ifdef WORDS_BIGENDIAN
#define AOUT_FMT_S16_NE AOUT_FMT_S16_BE
@ -171,8 +171,8 @@ struct aout_thread_t
#define AOUT_FMT_S16_NE AOUT_FMT_S16_LE
#endif
/* Number of samples in an AC3 frame */
#define AC3_FRAME_SIZE 1536
/* Number of samples in an A52 frame */
#define A52_FRAME_SIZE 1536
/* Size of a frame for spdif output */
#define SPDIF_FRAME_SIZE 6144

View File

@ -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.65 2002/07/31 20:56:50 sam Exp $
* $Id: input_ext-dec.h,v 1.66 2002/08/04 17:23:41 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Kaempf <maxx@via.ecp.fr>
@ -32,7 +32,7 @@
#define MPEG2_VIDEO_ES 0x02
#define MPEG1_AUDIO_ES 0x03
#define MPEG2_AUDIO_ES 0x04
#define AC3_AUDIO_ES 0x81
#define A52_AUDIO_ES 0x81
/* These ones might violate the norm : */
#define DVD_SPU_ES 0x82
#define LPCM_AUDIO_ES 0x83

View File

@ -4,7 +4,7 @@
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: input_ext-intf.h,v 1.73 2002/07/31 20:56:50 sam Exp $
* $Id: input_ext-intf.h,v 1.74 2002/08/04 17:23:41 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
@ -31,7 +31,7 @@
*/
/* FIXME ! */
#define REQUESTED_MPEG 1
#define REQUESTED_AC3 2
#define REQUESTED_A52 2
#define REQUESTED_LPCM 3
#define REQUESTED_NOAUDIO 255

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

3
modules/access/Makefile Normal file
View File

@ -0,0 +1,3 @@
file_SOURCES = file.c
udp_SOURCES = udp.c
http_SOURCES = http.c

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
dvd_SOURCES = dvd.c access.c demux.c seek.c es.c ifo.c udf.c summary.c

827
modules/access/dvd/access.c Normal file
View File

@ -0,0 +1,827 @@
/* access.c: DVD access plugin.
*****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* especially the 2048 bytes logical block size.
* It depends on:
* -libdvdcss for access and unscrambling
* -ifo.* for ifo parsing and analyse
* -udf.* to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: access.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "es.h"
#include "seek.h"
#include "ifo.h"
#include "summary.h"
#include "iso_lang.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* called from outside */
static int DVDSetArea ( input_thread_t *, input_area_t * );
static int DVDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
static ssize_t DVDRead ( input_thread_t *, byte_t *, size_t );
static void DVDSeek ( input_thread_t *, off_t );
static char * DVDParse( input_thread_t * );
/*
* Data access functions
*/
#define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \
- p_input->stream.p_selected_area->i_start
/*****************************************************************************
* DVDOpen: open dvd
*****************************************************************************/
int E_(DVDOpen) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_device;
thread_dvd_data_t * p_dvd;
input_area_t * p_area;
int i;
char * psz_dvdcss_env;
p_dvd = malloc( sizeof(thread_dvd_data_t) );
if( p_dvd == NULL )
{
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_dvd;
p_input->pf_read = DVDRead;
p_input->pf_seek = DVDSeek;
p_input->pf_set_area = DVDSetArea;
p_input->pf_set_program = DVDSetProgram;
/* Parse command line */
if( !( psz_device = DVDParse( p_input ) ) )
{
free( p_dvd );
return -1;
}
/*
* set up input
*/
p_input->i_mtu = 0;
/* override environment variable DVDCSS_METHOD with config option
* (FIXME: this creates a small memory leak) */
psz_dvdcss_env = config_GetPsz( p_input, "dvd-css-method" );
if( psz_dvdcss_env && *psz_dvdcss_env )
{
char *psz_env;
psz_env = malloc( strlen("DVDCSS_METHOD=") +
strlen( psz_dvdcss_env ) + 1 );
if( !psz_env )
{
free( p_dvd );
return -1;
}
sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env );
putenv( psz_env );
}
if( psz_dvdcss_env ) free( psz_dvdcss_env );
/*
* get plugin ready
*/
p_dvd->dvdhandle = dvdcss_open( psz_device );
/* free allocated string */
free( psz_device );
if( p_dvd->dvdhandle == NULL )
{
msg_Err( p_input, "dvdcss cannot open device" );
free( p_dvd );
return -1;
}
if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
/* Ifo allocation & initialisation */
if( IfoCreate( p_dvd ) < 0 )
{
msg_Err( p_input, "allcation error in ifo" );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
if( IfoInit( p_dvd->p_ifo ) < 0 )
{
msg_Err( p_input, "fatal failure in ifo" );
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_DVD;
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 1;
p_input->stream.p_selected_area->i_size = 0;
p_input->stream.p_selected_area->i_tell = 0;
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
#define title_inf p_dvd->p_ifo->vmg.title_inf
msg_Dbg( p_input, "number of titles: %d", title_inf.i_title_nb );
#define area p_input->stream.pp_areas
/* We start from 1 here since the default area 0
* is reserved for video_ts.vob */
for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
{
input_AddArea( p_input );
/* Titles are Program Chains */
area[i]->i_id = i;
/* Absolute start offset and size
* We can only set that with vts ifo, so we do it during the
* first call to DVDSetArea */
area[i]->i_start = 0;
area[i]->i_size = 0;
/* Number of chapters */
area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
area[i]->i_part = 1;
/* Offset to vts_i_0.ifo */
area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
title_inf.p_attr[i-1].i_start_sector;
}
#undef area
p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
p_dvd->i_title : 1;
#undef title_inf
p_area = p_input->stream.pp_areas[p_dvd->i_title];
p_area->i_part = p_dvd->i_chapter <= p_area->i_part_nb ?
p_dvd->i_chapter : 1;
p_dvd->i_chapter = 1;
p_dvd->b_new_chapter = 0;
p_dvd->i_audio_nb = 0;
p_dvd->i_spu_nb = 0;
/* set title, chapter, audio and subpic */
if( DVDSetArea( p_input, p_area ) < 0 )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->psz_demux = "dvdold";
return 0;
}
/*****************************************************************************
* DVDClose: close dvd
*****************************************************************************/
void E_(DVDClose) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
thread_dvd_data_t *p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
}
/*****************************************************************************
* DVDSetProgram: used to change angle
*****************************************************************************/
static int DVDSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
if( p_input->stream.p_selected_program != p_program )
{
thread_dvd_data_t * p_dvd;
int i_angle;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
i_angle = p_program->i_number;
/* DVD is actually mono-program: we only need the current angle
* number, so copy the data between programs */
memcpy( p_program,
p_input->stream.p_selected_program,
sizeof(pgrm_descriptor_t) );
p_program->i_number = i_angle;
p_input->stream.p_selected_program = p_program;
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
{
if( ( p_program->i_number - p_dvd->i_angle ) < 0 )
{
/* we have to go backwards */
p_dvd->i_map_cell = 0;
}
p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle );
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
p_dvd->i_map_cell += p_dvd->i_angle_cell;
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_angle = p_program->i_number;
}
else
{
p_dvd->i_angle = p_program->i_number;
}
#undef title
msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle );
}
return 0;
}
/*****************************************************************************
* DVDSetArea: initialize input data for title x, chapter y.
* It should be called for each user navigation request.
*****************************************************************************
* Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
* Note that you have to take the lock before entering here.
*****************************************************************************/
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
static void DVDFlushStream( input_thread_t * p_input )
{
if( p_input->stream.pp_programs != NULL )
{
/* We don't use input_EndStream here since
* we keep area structures */
while( p_input->stream.i_es_number )
{
input_DelES( p_input, p_input->stream.pp_es[0] );
}
while( p_input->stream.i_pgrm_number )
{
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
}
if( p_input->stream.pp_selected_es )
{
free( p_input->stream.pp_selected_es );
p_input->stream.pp_selected_es = NULL;
}
p_input->stream.i_selected_es_number = 0;
}
return;
}
static int DVDReadAngle( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
int i_angle_nb;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
for( i = 1 ; i < i_angle_nb ; i++ )
{
input_AddProgram( p_input, i+1, 0 );
}
return i_angle_nb;
}
static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
{
thread_dvd_data_t * p_dvd;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* we can't use the interface slider until initilization is complete */
p_input->stream.b_seekable = 0;
if( p_area != p_input->stream.p_selected_area )
{
int i_vts_title;
u32 i_first;
u32 i_last;
/* Reset the Chapter position of the old title */
p_input->stream.p_selected_area->i_part = 1;
p_input->stream.p_selected_area = p_area;
/*
* We have to load all title information
*/
/* title number as it appears in the interface list */
p_dvd->i_title = p_area->i_id;
p_dvd->i_chapter_nb = p_area->i_part_nb;
if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 )
{
msg_Err( p_input, "fatal error in vts ifo" );
free( p_dvd );
return -1;
}
/* title position inside the selected vts */
i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
p_dvd->i_title_id =
vts.title_inf.p_title_start[i_vts_title-1].i_title_id;
msg_Dbg( p_input, "title %d vts_title %d pgc %d",
p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
/* title set offset XXX: convert to block values */
p_dvd->i_vts_start =
vts.i_pos + vts.manager_inf.i_title_vob_start_sector;
/* last cell */
p_dvd->i_prg_cell = -1 +
vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
p_dvd->i_map_cell = 0;
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
i_last = CellLastSector( p_dvd );
/* first cell */
p_dvd->i_prg_cell = 0;
p_dvd->i_map_cell = 0;
p_dvd->i_angle_cell = 0;
p_dvd->i_map_cell = CellPrg2Map ( p_dvd );
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector ( p_dvd );
/* Force libdvdcss to check its title key.
* It is only useful for title cracking method. Methods using the
* decrypted disc key are fast enough to check the key at each seek */
i_first = dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_KEY );
if( i_first < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
return -1;
}
/* Area definition */
p_input->stream.p_selected_area->i_start = LB2OFF( i_first );
p_input->stream.p_selected_area->i_size =
LB2OFF( i_last + 1 - p_dvd->i_vts_lb );
/* Destroy obsolete ES by reinitializing programs */
DVDFlushStream( p_input );
/* Angle management: angles are handled through programs */
p_dvd->i_angle_nb = DVDReadAngle( p_input );
if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
{
p_dvd->i_angle = 1;
}
DVDSetProgram( p_input,
p_input->stream.pp_programs[p_dvd->i_angle-1] );
msg_Dbg( p_input, "title first %i, last %i, size %i",
i_first, i_last, i_last + 1 - p_dvd->i_vts_lb );
IfoPrintTitle( p_dvd );
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.p_selected_program->b_is_ok = 1;
/* Find all ES in title with ifo data */
DVDReadVideo( p_input );
DVDReadAudio( p_input );
DVDReadSPU ( p_input );
if( p_input->p_demux )
{
DVDLaunchDecoders( p_input );
}
} /* i_title >= 0 */
else
{
p_area = p_input->stream.p_selected_area;
}
/* Chapter selection */
p_dvd->i_chapter = DVDSetChapter( p_dvd, p_area->i_part );
p_input->stream.p_selected_area->i_tell = DVDTell;
/* warn interface that something has changed */
p_input->stream.b_seekable = 1;
p_input->stream.b_changed = 1;
return 0;
}
#undef vts
#undef vmg
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
/*****************************************************************************
* DVDRead: reads data packets.
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* bytes.
*****************************************************************************/
static ssize_t DVDRead( input_thread_t * p_input,
byte_t * p_buffer, size_t i_count )
{
thread_dvd_data_t * p_dvd;
int i_read;
int i_blocks;
int i_block_once = 0;
p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
i_read = 0;
i_blocks = OFF2LB(i_count);
while( i_blocks )
{
i_block_once = LbMaxOnce( p_dvd );
if( i_block_once > i_blocks )
{
i_block_once = i_blocks;
}
else if( i_block_once <= 0 )
{
/* EOT */
break;
}
if( i_block_once != dvdcss_read( p_dvd->dvdhandle, p_buffer,
i_block_once, DVDCSS_READ_DECRYPT ) )
{
return -1;
}
i_blocks -= i_block_once;
i_read += i_block_once;
p_buffer += LB2OFF( i_block_once );
/* Update global position */
p_dvd->i_vts_lb += i_block_once;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_tell += LB2OFF( i_read );
if( p_dvd->b_new_chapter )
{
p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
p_dvd->b_new_chapter = 0;
}
if( ( p_input->stream.p_selected_area->i_tell
>= p_input->stream.p_selected_area->i_size )
|| ( i_block_once <= 0 ) )
{
if( ( p_dvd->i_title + 1 ) >= p_input->stream.i_area_nb )
{
/* EOF */
vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
}
/* EOT */
msg_Dbg( p_input, "new title" );
p_dvd->i_title++;
DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
return LB2OFF( i_read );
}
/*****************************************************************************
* DVDSeek : Goes to a given position on the stream.
*****************************************************************************
* This one is used by the input and translate chronological position from
* input to logical position on the device.
* The lock should be taken before calling this function.
*****************************************************************************/
static void DVDSeek( input_thread_t * p_input, off_t i_off )
{
thread_dvd_data_t * p_dvd;
p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
vlc_mutex_lock( &p_input->stream.stream_lock );
p_dvd->i_vts_lb = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
- p_dvd->i_vts_start;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_dvd->i_prg_cell = Lb2CellPrg( p_dvd );
p_dvd->i_map_cell = Lb2CellMap( p_dvd );
if( CellIsInterleaved( p_dvd ) )
{
/* if we're inside a multi-angle zone, we have to choose i_sector
* in the current angle ; we can't do it all the time since cells
* can be very wide out of such zones */
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
}
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_chapter = CellPrg2Chapter( p_dvd );
if( dvdcss_seek( p_dvd->dvdhandle, p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
p_input->b_error = 1;
return;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
p_input->stream.p_selected_area->i_tell = DVDTell;
vlc_mutex_unlock( &p_input->stream.stream_lock );
msg_Dbg( p_input, "program cell: %d cell: %d chapter: %d tell %lld",
p_dvd->i_prg_cell, p_dvd->i_map_cell, p_dvd->i_chapter, DVDTell );
return;
}
/*****************************************************************************
* DVDParse: parse command line
*****************************************************************************/
static char * DVDParse( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
struct stat stat_info;
char * psz_parser;
char * psz_device;
char * psz_raw;
char * psz_next;
vlc_bool_t b_options = 0;
int i_title = 1;
int i_chapter = 1;
int i_angle = 1;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
#ifdef WIN32
/* On Win32 we want the DVD access plugin to be explicitly requested,
* we end up with lots of problems otherwise */
if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
#endif
psz_parser = psz_device = strdup( p_input->psz_name );
if( !psz_parser )
{
return NULL;
}
/* Parse input string :
* [device][@rawdevice][@[title][,[chapter][,angle]]] */
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* Maybe found raw device or option list */
*psz_parser = '\0';
psz_raw = ++psz_parser;
}
else
{
psz_raw = "";
}
if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
{
/* what we've found is either a raw device or a partial option
* list e.g. @,29 or both a device and a list ; search end of string */
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* found end of raw device, and beginning of options */
*psz_parser = '\0';
++psz_parser;
b_options = 1;
}
else
{
psz_parser = psz_raw + 1;
for( i=0 ; i<3 ; i++ )
{
if( !*psz_parser )
{
/* we have only a raw device */
break;
}
if( strtol( psz_parser, NULL, 10 ) )
{
/* we have only a partial list of options, no device */
psz_parser = psz_raw;
psz_raw = "";
b_options = 1;
break;
}
psz_parser++;
}
}
}
else
{
/* found beginning of options ; no raw device specified */
psz_raw = "";
b_options = 1;
}
if( b_options )
{
/* Found options */
i_title = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
i_angle = (int)strtol( psz_next + 1, NULL, 10 );
}
}
p_dvd->i_title = i_title ? i_title : 1;
p_dvd->i_chapter = i_chapter ? i_chapter : 1;
p_dvd->i_angle = i_angle ? i_angle : 1;
}
if( *psz_raw )
{
if( *psz_raw )
{
/* check the raw device */
if( stat( psz_raw, &stat_info ) == -1 )
{
msg_Warn( p_input, "cannot stat() raw device `%s' (%s)",
psz_raw, strerror(errno));
/* put back '@' */
*(psz_raw - 1) = '@';
psz_raw = "";
}
else
{
char * psz_env;
#ifndef WIN32
if( !S_ISCHR(stat_info.st_mode) )
{
msg_Warn( p_input, "raw device %s is"
" not a valid char device", psz_raw );
/* put back '@' */
*(psz_raw - 1) = '@';
psz_raw = "";
}
else
#endif
{
psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
+ strlen( psz_raw ) + 1 );
sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
putenv( psz_env );
}
}
}
else
{
psz_raw = "";
}
}
if( !*psz_device )
{
free( psz_device );
if( !p_input->psz_access )
{
/* no device and no access specified: we probably don't want DVD */
return NULL;
}
psz_device = config_GetPsz( p_input, "dvd" );
}
#ifndef WIN32
/* check block device */
if( stat( psz_device, &stat_info ) == -1 )
{
msg_Err( p_input, "cannot stat() device `%s' (%s)",
psz_device, strerror(errno));
free( psz_device );
return NULL;
}
if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
{
msg_Warn( p_input,
"dvd module discarded (not a valid block device)" );
free( psz_device );
return NULL;
}
#endif
msg_Dbg( p_input, "dvd=%s raw=%s title=%d chapter=%d angle=%d",
psz_device, psz_raw, p_dvd->i_title,
p_dvd->i_chapter, p_dvd->i_angle );
return psz_device;
}

112
modules/access/dvd/demux.c Normal file
View File

@ -0,0 +1,112 @@
/* demux.c: DVD demux functions.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: demux.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
/* how many packets DVDDemux will read in each loop */
#define DVD_READ_ONCE 64
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int DVDDemux ( input_thread_t * );
void DVDLaunchDecoders( input_thread_t * );
/*
* Data demux functions
*/
/*****************************************************************************
* DVDInit: initializes DVD structures
*****************************************************************************/
int E_(DVDInit) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
if( p_input->stream.i_method != INPUT_METHOD_DVD )
{
return -1;
}
p_input->pf_demux = DVDDemux;
p_input->pf_rewind = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
DVDLaunchDecoders( p_input );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
}
/*****************************************************************************
* DVDDemux
*****************************************************************************/
static int DVDDemux( input_thread_t * p_input )
{
data_packet_t * p_data;
ssize_t i_result;
int i;
/* Read headers to compute payload length */
for( i = 0 ; i < DVD_READ_ONCE ; i++ )
{
i_result = input_ReadPS( p_input, &p_data );
if( i_result < 0 )
{
return i_result;
}
else if( i_result == 0 )
{
return i;
}
input_DemuxPS( p_input, p_data );
}
return i;
}

336
modules/access/dvd/dvd.c Normal file
View File

@ -0,0 +1,336 @@
/*****************************************************************************
* dvd.c : DVD input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: dvd.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.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> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
#ifdef GOD_DAMN_DMCA
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/uio.h> /* struct iovec */
# include <sys/ioctl.h>
# include <dlfcn.h>
# include <netinet/in.h>
# include <linux/cdrom.h>
# include "dvdcss.h"
#endif
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
int E_(DVDOpen) ( vlc_object_t * );
void E_(DVDClose) ( vlc_object_t * );
int E_(DVDInit) ( vlc_object_t * );
#ifdef GOD_DAMN_DMCA
static void *p_libdvdcss;
static void ProbeLibDVDCSS ( void );
static void UnprobeLibDVDCSS( void );
#endif
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define CSSMETHOD_TEXT N_("Method to use by libdvdcss for key decryption")
#define CSSMETHOD_LONGTEXT N_( \
"title: decrypted title key is guessed from the encrypted sectors of " \
"the stream. Thus it should work with a file as well as the " \
"DVD device. But it sometimes takes much time to decrypt a title " \
"key and may even fail. With this method, the key is only checked "\
"at the beginning of each title, so it won't work if the key " \
"changes in the middle of a title.\n" \
"disc: the disc key is first cracked, then all title keys can be " \
"decrypted instantly, which allows us to check them often.\n" \
"key: the same as \"disc\" if you don't have a file with player keys " \
"at compilation time. If you do, the decryption of the disc key " \
"will be faster with this method. It is the one that was used by " \
"libcss.\n" \
"The default method is: key.")
static char *cssmethod_list[] = { "title", "disc", "key", NULL };
vlc_module_begin();
int i;
add_category_hint( N_("[dvd:][device][@raw_device][@[title][,[chapter][,angle]]]"), NULL );
add_string_from_list( "dvd-css-method", NULL, cssmethod_list, NULL,
CSSMETHOD_TEXT, CSSMETHOD_LONGTEXT );
#ifdef GOD_DAMN_DMCA
set_description( _("DVD input module, uses libdvdcss if installed") );
i = 90;
#else
set_description( _("DVD input module, uses libdvdcss") );
i = 100;
#endif
add_shortcut( "dvdold" );
add_submodule();
set_capability( "access", i );
set_callbacks( E_(DVDOpen), E_(DVDClose) );
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(DVDInit), NULL );
#ifdef GOD_DAMN_DMCA
ProbeLibDVDCSS();
#endif
vlc_module_end();
#if 0 /* FIXME */
UnprobeLibDVDCSS();
#endif
/* Following functions are local */
#ifdef GOD_DAMN_DMCA
/*****************************************************************************
* ProbeLibDVDCSS: look for a libdvdcss object.
*****************************************************************************
* This functions looks for libdvdcss, using dlopen(), and fills function
* pointers with what it finds. On failure, uses the dummy libdvdcss
* replacement provided by vlc.
*****************************************************************************/
static void ProbeLibDVDCSS( void )
{
static char *pp_filelist[] = { "libdvdcss.so.2",
"./libdvdcss.so.2",
"./lib/libdvdcss.so.2",
"libdvdcss.so.1",
"./libdvdcss.so.1",
"./lib/libdvdcss.so.1",
NULL };
char **pp_file = pp_filelist;
/* Try to open the dynamic object */
do
{
p_libdvdcss = dlopen( *pp_file, RTLD_LAZY );
if( p_libdvdcss != NULL )
{
//X intf_WarnMsg( 2, "module: builtin module `dvd' found libdvdcss "
//X "in `%s'", *pp_file );
break;
}
pp_file++;
} while( *pp_file != NULL );
/* If libdvdcss.so was found, check that it's valid */
if( p_libdvdcss == NULL )
{
//X intf_ErrMsg( "dvd warning: libdvdcss.so.2 not present" );
}
else
{
____dvdcss_open = dlsym( p_libdvdcss, "dvdcss_open" );
____dvdcss_close = dlsym( p_libdvdcss, "dvdcss_close" );
____dvdcss_title = dlsym( p_libdvdcss, "dvdcss_title" );
____dvdcss_seek = dlsym( p_libdvdcss, "dvdcss_seek" );
____dvdcss_read = dlsym( p_libdvdcss, "dvdcss_read" );
____dvdcss_readv = dlsym( p_libdvdcss, "dvdcss_readv" );
____dvdcss_error = dlsym( p_libdvdcss, "dvdcss_error" );
if( ____dvdcss_open == NULL || ____dvdcss_close == NULL
|| ____dvdcss_title == NULL || ____dvdcss_seek == NULL
|| ____dvdcss_read == NULL || ____dvdcss_readv == NULL
|| ____dvdcss_error == NULL )
{
//X intf_ErrMsg( "dvd warning: missing symbols in libdvdcss.so.2, "
//X "this shouldn't happen !" );
dlclose( p_libdvdcss );
p_libdvdcss = NULL;
}
}
/* If libdvdcss was not found or was not valid, use the dummy
* replacement functions. */
if( p_libdvdcss == NULL )
{
//X intf_ErrMsg( "dvd warning: no valid libdvdcss found, "
//X "I will only play unencrypted DVDs" );
//X intf_ErrMsg( "dvd warning: get libdvdcss at "
//X "http://www.videolan.org/libdvdcss/" );
____dvdcss_open = dummy_dvdcss_open;
____dvdcss_close = dummy_dvdcss_close;
____dvdcss_title = dummy_dvdcss_title;
____dvdcss_seek = dummy_dvdcss_seek;
____dvdcss_read = dummy_dvdcss_read;
____dvdcss_readv = dummy_dvdcss_readv;
____dvdcss_error = dummy_dvdcss_error;
}
}
/*****************************************************************************
* UnprobeLibDVDCSS: free resources allocated by ProbeLibDVDCSS, if any.
*****************************************************************************/
static void UnprobeLibDVDCSS( void )
{
if( p_libdvdcss != NULL )
{
dlclose( p_libdvdcss );
p_libdvdcss = NULL;
}
}
/* Dummy libdvdcss with minimal DVD access. */
/*****************************************************************************
* Local structure
*****************************************************************************/
struct dvdcss_s
{
/* File descriptor */
int i_fd;
};
/*****************************************************************************
* dvdcss_open: initialize library, open a DVD device, crack CSS key
*****************************************************************************/
extern dvdcss_handle dummy_dvdcss_open ( char *psz_target )
{
dvdcss_handle dvdcss;
dvd_struct dvd;
/* Allocate the library structure */
dvdcss = malloc( sizeof( struct dvdcss_s ) );
if( dvdcss == NULL )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not allocate memory\n" );
return NULL;
}
/* Open the device */
dvdcss->i_fd = open( psz_target, 0 );
if( dvdcss->i_fd < 0 )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not open device\n" );
free( dvdcss );
return NULL;
}
/* Check for encryption or ioctl failure */
dvd.type = DVD_STRUCT_COPYRIGHT;
dvd.copyright.layer_num = 0;
if( ioctl( dvdcss->i_fd, DVD_READ_STRUCT, &dvd ) != 0
|| dvd.copyright.cpst )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not decrypt disc\n" );
close( dvdcss->i_fd );
free( dvdcss );
return NULL;
}
return dvdcss;
}
/*****************************************************************************
* dvdcss_error: return the last libdvdcss error message
*****************************************************************************/
extern char * dummy_dvdcss_error ( dvdcss_handle dvdcss )
{
return "generic error";
}
/*****************************************************************************
* dvdcss_seek: seek into the device
*****************************************************************************/
extern int dummy_dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks,
int i_flags )
{
off_t i_read;
i_read = lseek( dvdcss->i_fd,
(off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
return i_read / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_title: crack the current title key if needed
*****************************************************************************/
extern int dummy_dvdcss_title ( dvdcss_handle dvdcss, int i_block )
{
return 0;
}
/*****************************************************************************
* dvdcss_read: read data from the device, decrypt if requested
*****************************************************************************/
extern int dummy_dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
int i_blocks,
int i_flags )
{
int i_bytes;
i_bytes = read( dvdcss->i_fd, p_buffer,
(size_t)i_blocks * DVDCSS_BLOCK_SIZE );
return i_bytes / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_readv: read data to an iovec structure, decrypt if reaquested
*****************************************************************************/
extern int dummy_dvdcss_readv ( dvdcss_handle dvdcss, void *p_iovec,
int i_blocks,
int i_flags )
{
int i_read;
i_read = readv( dvdcss->i_fd, (struct iovec*)p_iovec, i_blocks );
return i_read / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_close: close the DVD device and clean up the library
*****************************************************************************/
extern int dummy_dvdcss_close ( dvdcss_handle dvdcss )
{
int i_ret;
i_ret = close( dvdcss->i_fd );
if( i_ret < 0 )
{
return i_ret;
}
free( dvdcss );
return 0;
}
#endif

65
modules/access/dvd/dvd.h Normal file
View File

@ -0,0 +1,65 @@
/*****************************************************************************
* dvd.h: thread structure of the DVD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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
*****************************************************************************/
/* Logical block size for DVD-VIDEO */
#define DVD_LB_SIZE 2048
#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_LB_SIZE))
#define OFF2LB(x) ((x) >> 11)
/*****************************************************************************
* thread_dvd_data_t: extension of input_thread_t for DVD specificity.
*****************************************************************************/
typedef struct thread_dvd_data_s
{
dvdcss_handle dvdhandle; /* libdvdcss handle */
int i_audio_nb;
int i_spu_nb;
/* Navigation information */
int i_title;
int i_title_id;
int i_chapter_nb;
int i_chapter;
vlc_bool_t b_new_chapter;
int i_angle_nb;
int i_angle;
int i_map_cell; /* cell index in adress map */
int i_prg_cell; /* cell index in program map */
int i_angle_cell; /* cell index in the current angle */
int i_vts_start; /* offset to beginning of vts */
int i_vts_lb; /* sector in vts */
int i_last_lb; /* last sector of current cell */
/* Structure that contains all information of the DVD */
struct ifo_s * p_ifo;
} thread_dvd_data_t;

View File

@ -0,0 +1,70 @@
/*****************************************************************************
* dvdcss.h: Dummy libdvdcss header.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: dvdcss.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.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.
*****************************************************************************/
/*****************************************************************************
* The libdvdcss structure
*****************************************************************************/
typedef struct dvdcss_s* dvdcss_handle;
/*****************************************************************************
* Defines and flags
*****************************************************************************/
#define DVDCSS_BLOCK_SIZE 2048
#define DVDCSS_NOFLAGS 0
#define DVDCSS_READ_DECRYPT (1 << 0)
#define DVDCSS_SEEK_MPEG (1 << 0)
#define DVDCSS_SEEK_KEY (1 << 1)
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
dvdcss_handle dummy_dvdcss_open ( char * );
int dummy_dvdcss_close ( dvdcss_handle );
int dummy_dvdcss_title ( dvdcss_handle, int );
int dummy_dvdcss_seek ( dvdcss_handle, int, int );
int dummy_dvdcss_read ( dvdcss_handle, void *, int, int );
int dummy_dvdcss_readv ( dvdcss_handle, void *, int, int );
char * dummy_dvdcss_error ( dvdcss_handle );
/*****************************************************************************
* Pointers which will be filled either with dummy_dvdcss functions or
* with the dlopen()ed ones.
*****************************************************************************/
#define ____dvdcss_open dvdcss_open
#define ____dvdcss_close dvdcss_close
#define ____dvdcss_title dvdcss_title
#define ____dvdcss_seek dvdcss_seek
#define ____dvdcss_read dvdcss_read
#define ____dvdcss_readv dvdcss_readv
#define ____dvdcss_error dvdcss_error
dvdcss_handle (* ____dvdcss_open ) ( char * );
int (* ____dvdcss_close ) ( dvdcss_handle );
int (* ____dvdcss_title ) ( dvdcss_handle, int );
int (* ____dvdcss_seek ) ( dvdcss_handle, int, int );
int (* ____dvdcss_read ) ( dvdcss_handle, void *, int, int );
int (* ____dvdcss_readv ) ( dvdcss_handle, void *, int, int );
char * (* ____dvdcss_error ) ( dvdcss_handle );

323
modules/access/dvd/es.c Normal file
View File

@ -0,0 +1,323 @@
/* es.c: functions to find and select ES
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: es.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#include "summary.h"
#include "iso_lang.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
void DVDLaunchDecoders( input_thread_t * p_input );
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
#define ADDES( stream_id, private_id, fourcc, cat, lang, size ) \
i_id = ( (private_id) << 8 ) | (stream_id); \
p_es = input_AddES( p_input, NULL, i_id, size ); \
p_es->i_stream_id = (stream_id); \
p_es->i_fourcc = (fourcc); \
p_es->i_cat = (cat); \
if( lang ) \
{ \
strcpy( p_es->psz_desc, DecodeLanguage( lang ) ); \
}
/*****************************************************************************
* DVDReadVideo: read video ES
*****************************************************************************/
void DVDReadVideo( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_id;
int i_ratio;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* ES 0 -> video MPEG2 */
IfoPrintVideo( p_dvd );
i_ratio = vts.manager_inf.video_attr.i_ratio;
if( i_ratio )
{
ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, sizeof(int) );
*(int*)(p_es->p_demux_data) = i_ratio;
}
else
{
ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, 0 );
}
}
/*****************************************************************************
* DVDReadAudio: read audio ES
*****************************************************************************/
#define audio_status \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
void DVDReadAudio( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_lang;
int i_id;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
p_dvd->i_audio_nb = 0;
/* Audio ES, in the order they appear in .ifo */
for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
{
IfoPrintAudio( p_dvd, i );
/* audio channel is active if first byte is 0x80 */
if( audio_status.i_available )
{
p_dvd->i_audio_nb++;
i_lang = vts.manager_inf.p_audio_attr[i-1].i_lang_code;
i_id = audio_status.i_position;
switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
{
case 0x00: /* A52 */
ADDES( 0xbd, 0x80 + audio_status.i_position,
VLC_FOURCC('a','5','2',' '), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (A52)" );
break;
case 0x02:
case 0x03: /* MPEG audio */
ADDES( 0xc0 + audio_status.i_position, 0,
VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (mpeg)" );
break;
case 0x04: /* LPCM */
ADDES( 0xbd, 0xa0 + audio_status.i_position,
VLC_FOURCC('l','p','c','m'), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (lpcm)" );
break;
case 0x06: /* DTS */
i_id = ( ( 0x88 + audio_status.i_position ) << 8 ) | 0xbd;
msg_Err( p_input, "DTS audio not handled yet (0x%x)", i_id );
break;
default:
i_id = 0;
msg_Err( p_input, "unknown audio type %.2x",
vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
}
}
}
}
#undef audio_status
/*****************************************************************************
* DVDReadSPU: read subpictures ES
*****************************************************************************/
#define spu_status \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
#define palette \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_yuv_color
void DVDReadSPU( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_id;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
p_dvd->i_spu_nb = 0;
for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
{
IfoPrintSpu( p_dvd, i );
if( spu_status.i_available )
{
p_dvd->i_spu_nb++;
/* there are several streams for one spu */
if( vts.manager_inf.video_attr.i_ratio )
{
/* 16:9 */
switch( vts.manager_inf.video_attr.i_perm_displ )
{
case 1:
i_id = spu_status.i_position_pan;
break;
case 2:
i_id = spu_status.i_position_letter;
break;
default:
i_id = spu_status.i_position_wide;
break;
}
}
else
{
/* 4:3 */
i_id = spu_status.i_position_43;
}
if( vmg.title.pi_yuv_color )
{
ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u',' '), SPU_ES,
vts.manager_inf.p_spu_attr[i-1].i_lang_code,
sizeof(int) + 16*sizeof(u32) );
*(int*)p_es->p_demux_data = 0xBeeF;
memcpy( (char*)p_es->p_demux_data + sizeof(int),
palette, 16*sizeof(u32) );
}
else
{
ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u',' '), SPU_ES,
vts.manager_inf.p_spu_attr[i-1].i_lang_code, 0 );
}
}
}
}
#undef palette
#undef spu_status
#undef vts
#undef vmg
/*****************************************************************************
* DVDLaunchDecoders: select ES for video, audio and spu
*****************************************************************************/
void DVDLaunchDecoders( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
int i_audio;
int i_spu;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* Select Video stream (always 0) */
if( config_GetInt( p_input, "video" ) )
{
input_SelectES( p_input, p_input->stream.pp_es[0] );
}
/* Select audio stream */
if( p_dvd->i_audio_nb > 0 && config_GetInt( p_input, "audio" ) )
{
/* For audio: first one if none or a not existing one specified */
i_audio = config_GetInt( p_input, "audio-channel" );
if( i_audio <= 0 || i_audio > p_dvd->i_audio_nb )
{
config_PutInt( p_input, "audio-channel", 1 );
i_audio = 1;
}
if( ( config_GetInt( p_input, "audio-type" )
== REQUESTED_A52 ) )
{
int i_a52 = i_audio;
while( ( p_input->stream.pp_es[i_a52]->i_fourcc !=
VLC_FOURCC('a','5','2',' ') ) && ( i_a52 <=
p_dvd->p_ifo->vts.manager_inf.i_audio_nb ) )
{
i_a52++;
}
if( p_input->stream.pp_es[i_a52]->i_fourcc
== VLC_FOURCC('a','5','2',' ') )
{
input_SelectES( p_input,
p_input->stream.pp_es[i_a52] );
}
}
else
{
input_SelectES( p_input,
p_input->stream.pp_es[i_audio] );
}
}
/* Select subtitle */
if( p_dvd->i_spu_nb > 0 && config_GetInt( p_input, "video" ) )
{
/* for spu, default is none */
i_spu = config_GetInt( p_input, "spu-channel" );
if( i_spu < 0 || i_spu > p_dvd->i_spu_nb )
{
config_PutInt( p_input, "spu-channel", 0 );
i_spu = 0;
}
if( i_spu > 0 )
{
int i = 0, j = 0;
for( i = 0; i < p_input->stream.i_es_number; i++ )
{
if ( p_input->stream.pp_es[i]->i_fourcc
== VLC_FOURCC('s','p','u',' ') )
{
j++;
if ( i_spu == j ) break;
}
}
if( i_spu == j )
{
input_SelectES( p_input, p_input->stream.pp_es[i] );
}
}
}
}

27
modules/access/dvd/es.h Normal file
View File

@ -0,0 +1,27 @@
/* dvd_es.h: functions to find and select ES
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: es.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
void DVDLaunchDecoders ( input_thread_t * );
void DVDReadVideo ( input_thread_t * );
void DVDReadAudio ( input_thread_t * );
void DVDReadSPU ( input_thread_t * );

2183
modules/access/dvd/ifo.c Normal file

File diff suppressed because it is too large Load Diff

563
modules/access/dvd/ifo.h Normal file
View File

@ -0,0 +1,563 @@
/*****************************************************************************
* dvd_ifo.h: Structures for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ifo.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* based on:
* - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
* - IFO structure documentation by Thomas Mirlacher, Björn Englund,
* Håkan Hjort
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Common structures for Video Management and Video Title sets
*****************************************************************************/
/*
* Program Chain structures
*/
typedef struct ifo_video_s
{
u8 i_compression ;// 2;
u8 i_system ;// 2;
u8 i_ratio ;// 2;
u8 i_perm_displ ;// 2;
u8 i_line21_1 ;// 1;
u8 i_line21_2 ;// 1;
u8 i_source_res ;// 2;
u8 i_letterboxed ;// 1;
u8 i_mode ;// 1;
} ifo_video_t;
/* Audio type information */
typedef struct ifo_audio_s
{
u8 i_coding_mode ;// 3;
u8 i_multichannel_extension ;// 1;
u8 i_type ;// 2;
u8 i_appl_mode ;// 2;
u8 i_quantization ;// 2;
u8 i_sample_freq ;// 2;
u8 i_test ;// 1;
u8 i_num_channels ;// 3;
u16 i_lang_code ;// 16; // <char> description
u8 i_foo ;// 8; // 0x00000000 ?
u8 i_caption ;// 8;
u8 i_bar ;// 8; // 0x00000000 ?
} ifo_audio_t;
/* Audio Status */
typedef struct audio_status_s
{
u8 i_available; // 1
u8 i_position; // 7
u8 i_foo; // 8
} audio_status_t;
typedef struct ifo_spu_t
{
u16 i_prefix ;// 16; // 0x0100 ?
u16 i_lang_code ;// 16; // <char> description
u8 i_foo ;// 8; // dont know
u8 i_caption ;// 8; // 0x00 ?
} ifo_spu_t;
/* Subpicture status */
typedef struct spu_status_s
{
u8 i_available; //1
u8 i_position_43; //7
u8 i_position_wide; //8
u8 i_position_letter; //8
u8 i_position_pan; //8
} spu_status_t;
/* Ifo vitual machine Commands */
typedef struct command_desc_s
{
u8 i_type :3;
u8 i_direct :1;
u8 i_cmd :4;
u8 i_dir_cmp :1;
u8 i_cmp :3;
u8 i_sub_cmd :4;
union
{
u8 pi_8[6];
u16 pi_16[3];
} data;
} command_desc_t;
/* Program Chain Command Table
- start at i_pgc_com_tab_sbyte */
typedef struct command_s
{
u16 i_pre_command_nb; // 2 bytes
u16 i_post_command_nb; // 2 bytes
u16 i_cell_command_nb; // 2 bytes
// char[2] ???
u64* p_pre_command; // i_pre_com_nb * 8 bytes
u64* p_post_command; // i_post_com_nb * 8 bytes
u64* p_cell_command; // i_pre_com_nb * 8 bytes
// command_desc_t* p_cell_command; // i_cell_com_nb * 8 bytes
// command_desc_t* p_post_command; // i_post_com_nb * 8 bytes
// command_desc_t* p_cell_command; // i_cell_com_nb * 8 bytes
} command_t;
/* Program Chain Map Table
* - start at "i_pgc_prg_map_sbyte" */
typedef struct chapter_map_s
{
u8* pi_start_cell; // i_prg_nb * 1 byte
} chapter_map_t;
/* Cell Playback Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_play_inf_sbyte" */
typedef struct cell_play_s
{
/* This information concerns the currently selected cell */
u16 i_category; // 2 bytes
u8 i_still_time; // 1 byte; in seconds; ff=inf
u8 i_command_nb; // 1 byte; 0 = no com
u32 i_play_time; // 4 bytes
u32 i_first_sector; // 4 bytes
u32 i_first_ilvu_vobu_esector; // 4 bytes; ???
u32 i_last_vobu_start_sector; // 4 bytes
u32 i_last_sector; // 4 bytes
} cell_play_t;
/* Cell Position Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_pos_inf_sbyte" */
typedef struct cell_pos_s
{
/* This information concerns the currently selected cell */
u16 i_vob_id; // 2 bytes
// char ???
u8 i_cell_id; // 1 byte
} cell_pos_t;
/* Main structure for Program Chain
* - start at i_fp_pgc_sbyte
* - or at i_vmgm_pgci_sbyte in vmgm_pgci_srp_t */
typedef struct title_s
{
/* Global features of program chain */
// char[2] ???
u8 i_chapter_nb; // 1 byte
u8 i_cell_nb; // 1 byte
u32 i_play_time; // 4 bytes
u32 i_prohibited_user_op; // 4 bytes
audio_status_t pi_audio_status[8]; // 8*2 bytes
spu_status_t pi_spu_status[32]; // 32*4 bytes
u16 i_next_title_num; // 2 bytes
u16 i_prev_title_num; // 2 bytes
u16 i_go_up_title_num; // 2 bytes
u8 i_still_time; // 1 byte ; in seconds
u8 i_play_mode; // 1 byte
/* In video_ts.ifo, the 3 significant bytes of each color are
* preceded by 1 unsignificant byte */
u32 pi_yuv_color[16]; // 16*3 bytes
/* Here come the start bytes of the following structures */
u16 i_command_start_byte; // 2 bytes
u16 i_chapter_map_start_byte; // 2 bytes
u16 i_cell_play_start_byte; // 2 bytes
u16 i_cell_pos_start_byte; // 2 bytes
/* Predefined structures */
command_t command;
chapter_map_t chapter_map;
cell_play_t* p_cell_play; // i_cell_nb * 24 bytes
cell_pos_t* p_cell_pos; // i_cell_nb * 4 bytes
} title_t;
/*
* Menu PGCI Unit Table
*/
/* Menu PGCI Language unit Descriptor */
typedef struct unit_s
{
u16 i_lang_code; // 2 bytes (ISO-xx)
// char ???
u8 i_existence_mask; // 1 byte
u32 i_unit_inf_start_byte; // 4 bytes
} unit_t;
typedef struct unit_title_s
{
u8 i_category_mask; // 1 byte
u8 i_category; // 1 byte
u16 i_parental_mask; // 2 bytes
u32 i_title_start_byte; // 4 bytes
title_t title;
} unit_title_t;
/* Menu PGCI Language Unit Table
* - start at i_lu_sbyte */
typedef struct unit_inf_s
{
u16 i_title_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
unit_title_t * p_title; // i_srp_nb * 8 bytes
} unit_inf_t;
/* Main Struct for Menu PGCI
* - start at i_*_pgci_ut_ssector */
typedef struct title_unit_s
{
u16 i_unit_nb; // 2 bytes; ???
// char[2] ???
u32 i_last_byte; // 4 bytes
unit_t* p_unit; // i_lu_nb * 8 bytes
unit_inf_t* p_unit_inf; // i_lu_nb * 8 bytes
} title_unit_t;
/*
* Cell Adress Table Information
*/
typedef struct cell_map_s
{
u16 i_vob_id; // 2 bytes
u8 i_cell_id; // 1 byte
// char ???
u32 i_first_sector; // 4 bytes
u32 i_last_sector; // 4 bytes
} cell_map_t;
typedef struct cell_inf_s
{
u16 i_vob_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
u16 i_cell_nb; // not in ifo; computed
// with e_byte
cell_map_t* p_cell_map;
} cell_inf_t;
/*
* VOBU Adress Map Table
*/
typedef struct vobu_map_s
{
u32 i_last_byte; // 4 bytes
u32* pi_vobu_start_sector; // (nb of vobu) * 4 bytes
} vobu_map_t;
/*****************************************************************************
* Structures for Video Management (cf video_ts.ifo)
*****************************************************************************/
/*
* Video Manager Information Management Table
*/
typedef struct manager_inf_s
{
char psz_id[13]; // 12 bytes (DVDVIDEO-VMG)
u32 i_vmg_end_sector; // 4 bytes
// char[12] ???
u32 i_vmg_inf_end_sector; // 4 bytes
// char ???
u8 i_spec_ver; // 1 byte
u32 i_cat; // 4 bytes
u16 i_volume_nb; // 2 bytes
u16 i_volume; // 2 bytes
u8 i_disc_side; // 1 bytes
// char[20] ???
u16 i_title_set_nb; // 2 bytes
char ps_provider_id[32]; // 32 bytes
u64 i_pos_code; // 8 bytes
// char[24] ???
u32 i_vmg_inf_end_byte; // 4 bytes
u32 i_first_play_title_start_byte; // 4 bytes
// char[56] ???
u32 i_vob_start_sector; // 4 bytes
u32 i_title_inf_start_sector; // 4 bytes
u32 i_title_unit_start_sector; // 4 bytes
u32 i_parental_inf_start_sector; // 4 bytes
u32 i_vts_inf_start_sector; // 4 bytes
u32 i_text_data_start_sector; // 4 bytes
u32 i_cell_inf_start_sector; // 4 bytes
u32 i_vobu_map_start_sector; // 4 bytes
// char[2] ???
ifo_video_t video_attr; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
ifo_audio_t p_audio_attr[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_spu_nb; // 1 byte
ifo_spu_t p_spu_attr[32]; // i_subpic_nb * 6 bytes
} manager_inf_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct title_attr_s
{
u8 i_play_type; // 1 byte
u8 i_angle_nb; // 1 byte
u16 i_chapter_nb; // 2 bytes; Chapters/PGs
u16 i_parental_id; // 2 bytes
u8 i_title_set_num; // 1 byte (VTS#)
u8 i_title_num; // 1 byte ???
u32 i_start_sector; // 4 bytes
} title_attr_t;
/* Main struct for tts
* - start at "i_vmg_ptt_srpt_ssector" */
typedef struct title_inf_s
{
u16 i_title_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
title_attr_t * p_attr; // i_ttu_nb * 12 bytes
} title_inf_t;
/*
* Parental Management Information Table
*/
typedef struct parental_desc_s
{
char ps_country_code[2]; // 2 bytes
// char[2] ???
u16 i_parental_mask_start_byte; // 2 bytes
// char[2] ???
} parental_desc_t;
typedef struct parental_mask_s
{
u16* ppi_mask[8]; // (i_vts_nb +1) * 8 * 2 bytes
} parental_mask_t;
/* Main struct for parental management
* - start at i_vmg_ptl_mait_ssector */
typedef struct parental_inf_s
{
u16 i_country_nb; // 2 bytes
u16 i_vts_nb; // 2 bytes
u32 i_last_byte; // 4 bytes
parental_desc_t* p_parental_desc; // i_country_nb * 8 bytes
parental_mask_t* p_parental_mask; // i_country_nb * sizeof(vmg_ptl_mask_t)
} parental_inf_t;
/*
* Video Title Set Attribute Table
*/
/* Attribute structure : one for each vts
* - start at pi_atrt_sbyte */
typedef struct vts_attr_s
{
u32 i_last_byte; // 4 bytes
u32 i_cat_app_type; // 4 bytes
ifo_video_t vts_menu_video_attr; // 2 bytes
// char ???
u8 i_vts_menu_audio_nb; // 1 byte
ifo_audio_t p_vts_menu_audio_attr[8]; // 8 * 8 bytes
// char[17] ???
u8 i_vts_menu_spu_nb; // 1 byte
ifo_spu_t p_vts_menu_spu_attr[28]; // i_vtsm_subpic_nb * 6 bytes
// char[2] ???
ifo_video_t vts_title_video_attr; // 2 bytes
// char ???
u8 i_vts_title_audio_nb; // 1 byte
ifo_audio_t p_vts_title_audio_attr[8]; // 8 * 8 bytes
// char[17] ???
u8 i_vts_title_spu_nb; // 1 byte
ifo_spu_t p_vts_title_spu_attr[28]; // i_vtstt_subpic_nb * 6 bytes
} vts_attr_t;
/* Main struct for vts attributes
* - start at i_vmg_vts_atrt_ssector */
typedef struct vts_inf_s
{
u16 i_vts_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
u32* pi_vts_attr_start_byte; // i_vts_nb * 4 bytes
vts_attr_t* p_vts_attr;
} vts_inf_t;
/*
* Global Structure for Video Manager
*/
typedef struct vmg_s
{
manager_inf_t manager_inf;
title_t title;
title_inf_t title_inf;
title_unit_t title_unit;
parental_inf_t parental_inf;
vts_inf_t vts_inf;
cell_inf_t cell_inf;
vobu_map_t vobu_map;
} vmg_t;
/*****************************************************************************
* Structures for Video Title Sets (cf vts_*.ifo)
****************************************************************************/
/*
* Video Title Sets Information Management Table
*/
typedef struct vts_manager_s
{
char psz_id[13]; // 12 bytes (DVDVIDEO-VTS)
u32 i_last_sector; // 4 bytes
// char[12] ???
u32 i_inf_last_sector; // 4 bytes
// char ???
u8 i_spec_ver; // 1 byte
u32 i_cat; // 4 bytes
// char[90] ???
u32 i_inf_end_byte; // 4 bytes
// char[60] ???
u32 i_menu_vob_start_sector; // 4 bytes
u32 i_title_vob_start_sector; // 4 bytes
u32 i_title_inf_start_sector; // 4 bytes
u32 i_title_unit_start_sector; // 4 bytes
u32 i_menu_unit_start_sector; // 4 bytes
u32 i_time_inf_start_sector; // 4 bytes
u32 i_menu_cell_inf_start_sector; // 4 bytes
u32 i_menu_vobu_map_start_sector; // 4 bytes
u32 i_cell_inf_start_sector; // 4 bytes
u32 i_vobu_map_start_sector; // 4 bytes
// char[24] ???
ifo_video_t menu_video_attr; // 2 bytes
// char ???
u8 i_menu_audio_nb; // 1 byte
ifo_audio_t p_menu_audio_attr[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_menu_spu_nb; // 1 byte
ifo_spu_t p_menu_spu_attr[32]; // i_subpic_nb * 6 bytes
// !!! only 28 subpics ???
// char[2] ???
ifo_video_t video_attr; // 2 bytes
// char ???
u8 i_audio_nb; // 1 byte
ifo_audio_t p_audio_attr[8]; // i_vmgm_audio_nb * 8 bytes
// char[16] ???
u8 i_spu_nb; // 1 byte
ifo_spu_t p_spu_attr[32]; // i_subpic_nb * 6 bytes
} vts_manager_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct title_start_s
{
u16 i_title_id; // 2 bytes; Chapters/PGs
u16 i_chapter; // 2 bytes
} title_start_t;
/* Main struct for tts
* - start at "i_vts_ptt_srpt_ssector" */
typedef struct vts_title_s
{
u16 i_title_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
u32* pi_start_byte;
title_start_t * p_title_start; // i_ttu_nb * 4 bytes
} vts_title_t;
/*
* Time Map table information
*/
/* Time Map structure */
typedef struct time_map_s
{
u8 i_time_unit; // 1 byte
// char ???
u16 i_entry_nb; // 2 bytes
u32* pi_sector; // i_entry_nb * 4 bytes
} time_map_t;
/* Main structure for tmap_ti
* - start at "i_tmap_ti_ssector" */
typedef struct time_inf_s
{
u16 i_nb; // 2 bytes
// char[2] ???
u32 i_last_byte; // 4 bytes
u32* pi_start_byte; // i_tmap_nb * 4 bytes
time_map_t* p_time_map;
} time_inf_t;
/*
* Video Title Set
*/
typedef struct vts_s
{
vlc_bool_t b_initialized;
int i_pos;
vts_manager_t manager_inf;
vts_title_t title_inf;
title_unit_t menu_unit;
unit_inf_t title_unit;
time_inf_t time_inf;
cell_inf_t menu_cell_inf;
vobu_map_t menu_vobu_map;
cell_inf_t cell_inf;
vobu_map_t vobu_map;
} vts_t;
/*
* Global Ifo Structure
*/
typedef struct ifo_s
{
dvdcss_handle dvdhandle; /* File descriptor for the device */
int i_start; /* Offset to video_ts.ifo on the device */
int i_pos; /* Position of stream pointer */
vlc_bool_t b_error; /* Error Management */
vmg_t vmg; /* Structure described in video_ts */
vts_t vts; /* Vts ifo for current title set */
/* Remap buffer for unaligned reads */
u8 p_remap[ 2 * DVD_LB_SIZE ];
} ifo_t;
/*****************************************************************************
* Prototypes in dvd_ifo.c
*****************************************************************************/
struct thread_dvd_data_s;
int IfoCreate ( struct thread_dvd_data_s * );
int IfoInit ( struct ifo_s * );
int IfoTitleSet ( struct ifo_s *, int );
void IfoDestroy ( struct ifo_s * );

324
modules/access/dvd/seek.c Normal file
View File

@ -0,0 +1,324 @@
/* seek.c: functions to navigate through DVD.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: seek.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "seek.h"
#include "ifo.h"
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
#define cell p_dvd->p_ifo->vts.cell_inf
int CellIsInterleaved( thread_dvd_data_t * p_dvd )
{
return title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000;
}
int CellPrg2Map( thread_dvd_data_t * p_dvd )
{
int i_cell;
i_cell = p_dvd->i_map_cell;
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
while( ( i_cell < cell.i_cell_nb ) &&
( ( title.p_cell_pos[p_dvd->i_prg_cell].i_vob_id !=
cell.p_cell_map[i_cell].i_vob_id ) ||
( title.p_cell_pos[p_dvd->i_prg_cell].i_cell_id !=
cell.p_cell_map[i_cell].i_cell_id ) ) )
{
i_cell++;
}
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
return i_cell;
}
int CellAngleOffset( thread_dvd_data_t * p_dvd, int i_prg_cell )
{
int i_cell_off;
if( i_prg_cell >= title.i_cell_nb )
{
return 0;
}
/* basic handling of angles */
switch( ( ( title.p_cell_play[i_prg_cell].i_category & 0xf000 )
>> 12 ) )
{
/* we enter a muli-angle section */
case 0x5:
i_cell_off = p_dvd->i_angle - 1;
p_dvd->i_angle_cell = 0;
break;
/* we exit a multi-angle section */
case 0x9:
case 0xd:
i_cell_off = p_dvd->i_angle_nb - p_dvd->i_angle;
break;
default:
i_cell_off = 0;
}
return i_cell_off;
}
int CellFirstSector( thread_dvd_data_t * p_dvd )
{
return __MAX( cell.p_cell_map[p_dvd->i_map_cell].i_first_sector,
title.p_cell_play[p_dvd->i_prg_cell].i_first_sector );
}
int CellLastSector( thread_dvd_data_t * p_dvd )
{
return __MIN( cell.p_cell_map[p_dvd->i_map_cell].i_last_sector,
title.p_cell_play[p_dvd->i_prg_cell].i_last_sector );
}
int NextCellPrg( thread_dvd_data_t * p_dvd )
{
int i_cell = p_dvd->i_prg_cell;
if( p_dvd->i_vts_lb > title.p_cell_play[i_cell].i_last_sector )
{
i_cell ++;
i_cell += CellAngleOffset( p_dvd, i_cell );
if( i_cell >= title.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int Lb2CellPrg( thread_dvd_data_t * p_dvd )
{
int i_cell = 0;
while( p_dvd->i_vts_lb > title.p_cell_play[i_cell].i_last_sector )
{
i_cell ++;
i_cell += CellAngleOffset( p_dvd, i_cell );
if( i_cell >= title.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int Lb2CellMap( thread_dvd_data_t * p_dvd )
{
int i_cell = 0;
while( p_dvd->i_vts_lb > cell.p_cell_map[i_cell].i_last_sector )
{
i_cell ++;
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int LbMaxOnce( thread_dvd_data_t * p_dvd )
{
int i_block_once = p_dvd->i_last_lb + 1 - p_dvd->i_vts_lb;
/* Get the position of the next cell if we're at cell end */
if( i_block_once <= 0 )
{
p_dvd->i_map_cell++;
p_dvd->i_angle_cell++;
p_dvd->i_prg_cell = NextCellPrg( p_dvd );
if( p_dvd->i_prg_cell < 0 )
{
/* EOF */
return 0;
}
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
if( p_dvd->i_map_cell < 0 )
{
return 0;
}
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_chapter = NextChapter( p_dvd );
if( p_dvd->i_chapter < 0 )
{
return 0;
}
/* Position the fd pointer on the right address */
if( dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
//X intf_ErrMsg( "dvd error: %s",
//X dvdcss_error( p_dvd->dvdhandle ) );
return 0;
}
i_block_once = p_dvd->i_last_lb + 1 - p_dvd->i_vts_lb;
}
return i_block_once;
}
int CellPrg2Chapter( thread_dvd_data_t * p_dvd )
{
int i_chapter = 1;
int i_cell = p_dvd->i_prg_cell;
if( CellIsInterleaved( p_dvd ) )
{
i_cell -= (p_dvd->i_angle - 1);
}
while( title.chapter_map.pi_start_cell[i_chapter] <= i_cell+1 )
{
i_chapter ++;
if( i_chapter >= p_dvd->i_chapter_nb )
{
return p_dvd->i_chapter_nb;
}
}
return i_chapter;
}
int NextChapter( thread_dvd_data_t * p_dvd )
{
int i_cell = p_dvd->i_prg_cell;
if( CellIsInterleaved( p_dvd ) )
{
i_cell -= (p_dvd->i_angle - 1);
}
if( title.chapter_map.pi_start_cell[p_dvd->i_chapter] <= i_cell+1 )
{
p_dvd->i_chapter++;
if( p_dvd->i_chapter > p_dvd->i_chapter_nb )
{
return -1;
}
p_dvd->b_new_chapter = 1;
return p_dvd->i_chapter;
}
return p_dvd->i_chapter;
}
int DVDSetChapter( thread_dvd_data_t * p_dvd, int i_chapter )
{
if( i_chapter <= 0 || i_chapter > p_dvd->i_chapter_nb )
{
i_chapter = 1;
}
if( p_dvd->i_chapter != i_chapter )
{
/* Find cell index in Program chain for current chapter */
p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
p_dvd->i_prg_cell += CellAngleOffset( p_dvd, p_dvd->i_prg_cell );
if( i_chapter < p_dvd->i_chapter )
{
p_dvd->i_map_cell = 0;
}
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
/* Position the fd pointer on the right address */
if( dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
//X intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
return -1;
}
//X intf_WarnMsg( 4, "dvd info: chapter %d prg_cell %d map_cell %d",
//X i_chapter, p_dvd->i_prg_cell, p_dvd->i_map_cell );
}
return i_chapter;
}
#undef cell
#undef title

37
modules/access/dvd/seek.h Normal file
View File

@ -0,0 +1,37 @@
/* dvd_seek.h: DVD access plugin.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: seek.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
int CellIsInterleaved( thread_dvd_data_t * );
int CellAngleOffset ( thread_dvd_data_t *, int );
int CellPrg2Map ( thread_dvd_data_t * );
int CellFirstSector ( thread_dvd_data_t * );
int CellLastSector ( thread_dvd_data_t * );
int NextCellPrg ( thread_dvd_data_t * );
int Lb2CellPrg ( thread_dvd_data_t * );
int Lb2CellMap ( thread_dvd_data_t * );
int LbMaxOnce ( thread_dvd_data_t * );
int CellPrg2Chapter ( thread_dvd_data_t * );
int NextChapter ( thread_dvd_data_t * );
int DVDSetChapter ( thread_dvd_data_t *, int );

View File

@ -0,0 +1,178 @@
/*****************************************************************************
* summary.c: set of functions to print options of selected title
* found in .ifo.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: summary.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if !defined( WIN32 )
# include <netinet/in.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include <errno.h>
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#include "iso_lang.h"
/*
* Local tools to decode some data in ifo
*/
/****************************************************************************
* IfoPrintTitle
****************************************************************************/
void IfoPrintTitle( thread_dvd_data_t * p_dvd )
{
//X intf_WarnMsg( 5, "dvd info: title %d, %d chapter%s, %d angle%s",
//X p_dvd->i_title, p_dvd->i_chapter_nb,
//X (p_dvd->i_chapter_nb == 1) ? "" : "s",
//X p_dvd->i_angle_nb,
//X (p_dvd->i_angle_nb == 1) ? "" : "s" );
}
/****************************************************************************
* IfoPrintVideo
****************************************************************************/
#define video p_dvd->p_ifo->vts.manager_inf.video_attr
void IfoPrintVideo( thread_dvd_data_t * p_dvd )
{
//X char* psz_perm_displ[4] =
//X {
//X "pan-scan & letterboxed",
//X "pan-scan",
//X "letterboxed",
//X "not specified"
//X };
//X char* psz_source_res[4] =
//X {
//X "720x480 ntsc or 720x576 pal",
//X "704x480 ntsc or 704x576 pal",
//X "352x480 ntsc or 352x576 pal",
//X "352x240 ntsc or 352x288 pal"
//X };
//X intf_WarnMsg( 5, "dvd info: MPEG-%d video, %sHz, aspect ratio %s",
//X video.i_compression + 1,
//X video.i_system ? "pal 625 @50" : "ntsc 525 @60",
//X video.i_ratio ? (video.i_ratio == 3) ? "16:9"
//X : "unknown"
//X : "4:3" );
//X intf_WarnMsg( 5, "dvd info: display mode %s, %s, %s",
//X psz_perm_displ[video.i_perm_displ],
//X video.i_line21_1 ? "line21-1 data in GOP"
//X : "no line21-1 data",
//X video.i_line21_2 ? "line21-2 data in GOP"
//X : "no line21-2 data" );
//X intf_WarnMsg( 5, "dvd info: source is %s, %sletterboxed, %s mode",
//X psz_source_res[video.i_source_res],
//X video.i_letterboxed ? "" : "not ",
//X video.i_mode ? "film (625/50 only)" : "camera" );
}
#undef video
/****************************************************************************
* IfoPrintAudio
****************************************************************************/
#define audio p_dvd->p_ifo->vts.manager_inf.p_audio_attr[i-1]
#define audio_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
void IfoPrintAudio( thread_dvd_data_t * p_dvd, int i )
{
if( audio_status.i_available )
{
//X char* ppsz_mode[8] =
//X { "A52", "unknown", "MPEG", "MPEG-2", "LPCM", "SDDS", "DTS", "" };
//X char* ppsz_appl_mode[4] =
//X { "no application specified", "karaoke", "surround sound", "" };
//X char* ppsz_quant[4] =
//X { "16 bits", "20 bits", "24 bits", "drc" };
//X intf_WarnMsg( 5, "dvd info: audio %d (%s) is %s, "
//X "%d%s channel%s, %dHz, %s", i,
//X DecodeLanguage( audio.i_lang_code ),
//X ppsz_mode[audio.i_coding_mode & 0x7],
//X audio.i_num_channels + 1,
//X audio.i_multichannel_extension ? " ext." : "",
//X audio.i_num_channels ? "s" : "",
//X audio.i_sample_freq ? 96000 : 48000,
//X ppsz_appl_mode[audio.i_appl_mode & 0x3] );
//X intf_WarnMsg( 5, "dvd info: %s, quantization %s, status %x",
//X (audio.i_caption == 1) ? "normal caption"
//X : (audio.i_caption == 3) ? "directors comments"
//X : "unknown caption",
//X ppsz_quant[audio.i_quantization & 0x3],
//X audio_status.i_position );
}
}
#undef audio_status
#undef audio
/****************************************************************************
* IfoPrintSpu
****************************************************************************/
#define spu p_dvd->p_ifo->vts.manager_inf.p_spu_attr[i-1]
#define spu_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
void IfoPrintSpu( thread_dvd_data_t * p_dvd, int i )
{
if( spu_status.i_available )
{
//X intf_WarnMsg( 5, "dvd info: spu %d (%s), caption %d "
//X "prefix %x, modes [%s%s%s%s ]", i,
//X DecodeLanguage( spu.i_lang_code ),
//X spu.i_caption, spu.i_prefix,
//X spu_status.i_position_43 ? " 4:3" : "",
//X spu_status.i_position_wide ? " wide" : "",
//X spu_status.i_position_letter ? " letter" : "",
//X spu_status.i_position_pan ? " pan" : "" );
}
}
#undef spu_status
#undef spu

View File

@ -0,0 +1,31 @@
/*****************************************************************************
* dvd_summary.h: prototype of functions that print out current options.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: summary.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
struct thread_dvd_data_s;
void IfoPrintTitle( struct thread_dvd_data_s * );
void IfoPrintVideo( struct thread_dvd_data_s * );
void IfoPrintAudio( struct thread_dvd_data_s *, int );
void IfoPrintSpu ( struct thread_dvd_data_s *, int );

740
modules/access/dvd/udf.c Normal file
View File

@ -0,0 +1,740 @@
/*****************************************************************************
* udf.c: udf filesystem tools.
*****************************************************************************
* Mainly used to find asolute logical block adress of *.ifo files. It only
* contains the basic udf handling functions
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: udf.c,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* based on:
* - dvdudf by Christian Wolff <scarabaeus@convergence.de>
* - fixes by Billy Biggs <vektor@dumbterm.net>
*
* 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 <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#define UDFADshort 1
#define UDFADlong 2
#define UDFADext 4
typedef struct partition_s
{
vlc_bool_t b_valid;
u8 pi_volume_desc[128];
u16 i_flags;
u16 i_number;
u8 pi_contents[32];
u32 i_access_type;
u32 i_start;
u32 i_length;
dvdcss_handle dvdhandle;
} partition_t;
typedef struct ad_s
{
u32 i_location;
u32 i_length;
u8 i_flags;
u16 i_partition;
} ad_t;
/* for direct data access, LSB first */
#define GETN1(p) ((u8)pi_data[p])
#define GETN2(p) ((u16)pi_data[p]|((u16)pi_data[(p)+1]<<8))
#define GETN4(p) ((u32)pi_data[p]|((u32)pi_data[(p)+1]<<8)|((u32)pi_data[(p)+2]<<16)|((u32)pi_data[(p)+3]<<24))
#define GETN(p,n,target) memcpy(target,&pi_data[p],n)
/*****************************************************************************
* UDFReadLB: reads absolute Logical Block of the disc
*****************************************************************************
* Returns number of read bytes on success, 0 on error
*****************************************************************************/
static int UDFReadLB( dvdcss_handle dvdhandle, off_t i_lba,
size_t i_block_count, u8 *pi_data )
{
if( dvdcss_seek( dvdhandle, i_lba, DVDCSS_NOFLAGS ) < 0 )
{
//X intf_ErrMsg( "dvd error: block %i not found", i_lba );
return 0;
}
return dvdcss_read( dvdhandle, pi_data, i_block_count, DVDCSS_NOFLAGS );
}
/*****************************************************************************
* UDFDecode: decode unicode encoded udf data
*****************************************************************************/
static int UDFDecode( u8 * pi_data, int i_len, char * psz_target )
{
int p = 1;
int i = 0;
if( !( pi_data[0] & 0x18 ) )
{
psz_target[0] = '\0';
return 0;
}
if( pi_data[0] & 0x10 )
{
/* ignore MSB of unicode16 */
p++;
while( p < i_len )
{
psz_target[i++] = pi_data[p+=2];
}
}
else
{
while( p < i_len )
{
psz_target[i++] = pi_data[p++];
}
}
psz_target[i]='\0';
return 0;
}
#if 0
/**
*
**/
int UDFEntity (u8 *data, u8 *Flags, char *Identifier)
{
Flags[0] = data[0];
strncpy (Identifier, &data[1], 5);
return 0;
}
#endif
/*****************************************************************************
* UDFDescriptor: gives a tag ID from your data to find out what it refers to
*****************************************************************************/
static int UDFDescriptor( u8 * pi_data, u16 * pi_tag_id )
{
pi_tag_id[0] = GETN2( 0 );
/* TODO: check CRC 'n stuff */
return 0;
}
/*****************************************************************************
* UDFExtendAD: main volume information
*****************************************************************************/
static int UDFExtentAD (u8 * pi_data, u32 * pi_length, u32 * pi_location)
{
pi_length[0] = GETN4( 0 );
pi_location[0] = GETN4( 4 );
return 0;
}
/*****************************************************************************
* UDFAD: file set information
*****************************************************************************/
static int UDFAD( u8 * pi_data, struct ad_s * p_ad, u8 i_type,
struct partition_s partition )
{
p_ad->i_length = GETN4( 0 );
p_ad->i_flags = p_ad->i_length >> 30;
p_ad->i_length &= 0x3FFFFFFF;
switch( i_type )
{
case UDFADshort:
p_ad->i_location = GETN4( 4 );
/* use number of current partition */
p_ad->i_partition = partition.i_number;
break;
case UDFADlong:
p_ad->i_location = GETN4( 4 );
p_ad->i_partition = GETN2( 8 );
break;
case UDFADext:
p_ad->i_location = GETN4( 12 );
p_ad->i_partition = GETN2( 16 );
break;
}
return 0;
}
/*****************************************************************************
* UDFICB: takes Information Control Block from pi_data
*****************************************************************************/
static int UDFICB( u8 * pi_data, u8 * pi_file_type, u16 * pi_flags)
{
pi_file_type[0] = GETN1( 11 );
pi_flags[0] = GETN2( 18 );
return 0;
}
/*****************************************************************************
* UDFPartition: gets partition descriptor
*****************************************************************************/
static int UDFPartition( u8 * pi_data, u16 * pi_flags, u16 * pi_nb,
char * ps_contents, u32 * pi_start, u32 * pi_length )
{
pi_flags[0] = GETN2( 20 );
pi_nb[0] = GETN2( 22 );
GETN( 24, 32, ps_contents );
pi_start[0] = GETN4( 188 );
pi_length[0] = GETN4( 192 );
return 0;
}
/*****************************************************************************
* UDFLogVolume: reads the volume descriptor and checks the parameters
*****************************************************************************
* Returns 0 on OK, 1 on error
*****************************************************************************/
static int UDFLogVolume(u8 * pi_data, char * p_volume_descriptor )
{
u32 i_lb_size;
u32 i_MT_L;
u32 i_N_PM;
UDFDecode( &pi_data[84], 128, p_volume_descriptor );
i_lb_size = GETN4( 212 ); // should be 2048
i_MT_L = GETN4( 264 ); // should be 6
i_N_PM = GETN4( 268 ); // should be 1
if( i_lb_size != DVD_LB_SIZE )
{
//X intf_ErrMsg( "dvd error: invalid UDF sector size (%d)", i_lb_size );
return 1;
}
return 0;
}
/*****************************************************************************
* UDFFileEntry: fills a ad_t struct with information at pi_data
*****************************************************************************/
static int UDFFileEntry( u8 * pi_data, u8 * pi_file_type, struct ad_s * p_ad,
struct partition_s partition )
{
u8 i_file_type;
u16 i_flags;
u32 i_L_EA;
u32 i_L_AD;
int p;
UDFICB( &pi_data[16], &i_file_type, &i_flags );
pi_file_type[0] = i_file_type;
i_L_EA = GETN4( 168 );
i_L_AD = GETN4( 172 );
p = 176 + i_L_EA;
while( p < 176 + i_L_EA + i_L_AD )
{
switch( i_flags & 0x07 )
{
case 0:
UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
p += 0x08;
break;
case 1:
UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
p += 0x10;
break;
case 2:
UDFAD( &pi_data[p], p_ad, UDFADext, partition );
p += 0x14;
break;
case 3:
switch( i_L_AD )
{
case 0x08:
UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
break;
case 0x10:
UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
break;
case 0x14:
UDFAD( &pi_data[p], p_ad, UDFADext, partition );
break;
}
default:
p += i_L_AD;
break;
}
}
return 0;
}
/*****************************************************************************
* UDFFileIdentifier: gives filename and characteristics of pi_data
*****************************************************************************/
static int UDFFileIdentifier( u8 * pi_data, u8 * pi_file_characteristics,
char * psz_filename, struct ad_s * p_file_icb,
struct partition_s partition )
{
u8 i_L_FI;
u16 i_L_IU;
pi_file_characteristics[0] = GETN1( 18 );
i_L_FI = GETN1( 19 );
UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
i_L_IU = GETN2( 36 );
if( i_L_FI )
{
UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
}
else
{
psz_filename[0]='\0';
}
return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
}
/*****************************************************************************
* UDFMapICB: Maps ICB to FileAD
*****************************************************************************
* ICB: Location of ICB of directory to scan
* FileType: Type of the file
* File: Location of file the ICB is pointing to
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFMapICB( struct ad_s icb, u8 * pi_file_type, struct ad_s * p_file,
struct partition_s partition )
{
u8 pi_lb[DVD_LB_SIZE];
u32 i_lba;
u16 i_tag_id;
i_lba = partition.i_start + icb.i_location;
do
{
if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb , &i_tag_id );
}
if( i_tag_id == 261 )
{
UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
return 1;
}
} while( ( i_lba <= partition.i_start + icb.i_location +
( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
return 0;
}
/*****************************************************************************
* UDFScanDir: serach filename in dir
*****************************************************************************
* Dir: Location of directory to scan
* FileName: Name of file to look for
* FileICB: Location of ICB of the found file
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFScanDir( struct ad_s dir, char * psz_filename,
struct ad_s * p_file_icb, struct partition_s partition )
{
u8 pi_lb[2*DVD_LB_SIZE];
u32 i_lba;
u16 i_tag_id;
u8 i_file_char;
char psz_temp[DVD_LB_SIZE];
int p;
/* Scan dir for ICB of file */
i_lba = partition.i_start + dir.i_location;
#if 0
do
{
if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
p=0;
while( p < DVD_LB_SIZE )
{
UDFDescriptor( &pi_lb[p], &i_tag_id );
if( i_tag_id == 257 )
{
p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
psz_temp, p_file_icb, partition );
if( !strcasecmp( psz_filename, psz_temp ) )
{
return 1;
}
}
else
{
p = DVD_LB_SIZE;
}
}
}
} while( i_lba <=
partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
#else
if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 ) {
return 0;
}
p = 0;
while( p < dir.i_length )
{
if( p > DVD_LB_SIZE )
{
++i_lba;
p -= DVD_LB_SIZE;
dir.i_length -= DVD_LB_SIZE;
if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 )
{
return 0;
}
}
UDFDescriptor( &pi_lb[p], &i_tag_id );
if( i_tag_id == 257 )
{
p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
psz_temp, p_file_icb, partition );
if( !strcasecmp( psz_filename, psz_temp ) )
{
return 1;
}
}
else
{
return 0;
}
}
#endif
return 0;
}
/*****************************************************************************
* UDFFindPartition: looks for a partition on the disc
*****************************************************************************
* partnum: number of the partition, starting at 0
* part: structure to fill with the partition information
* return 1 if partition found, 0 on error;
*****************************************************************************/
static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
{
u8 pi_lb[DVD_LB_SIZE];
u8 pi_anchor[DVD_LB_SIZE];
u16 i_tag_id;
u32 i_lba;
u32 i_MVDS_location;
u32 i_MVDS_length;
u32 i_last_sector;
vlc_bool_t b_term;
vlc_bool_t b_vol_valid;
int i;
/* Find Anchor */
i_last_sector = 0;
/* try #1, prime anchor */
i_lba = 256;
b_term = 0;
/* Search anchor loop */
while( 1 )
{
if( UDFReadLB( p_partition->dvdhandle, i_lba, 1, pi_anchor ) )
{
UDFDescriptor( pi_anchor, &i_tag_id );
}
else
{
i_tag_id = 0;
}
if( i_tag_id != 2 )
{
/* not an anchor? */
if( b_term )
{
/* final try failed */
return 0;
}
if( i_last_sector )
{
/* we already found the last sector
* try #3, alternative backup anchor */
i_lba = i_last_sector;
/* but that's just about enough, then! */
b_term = 1;
}
else
{
/* TODO: find last sector of the disc (this is optional) */
if( i_last_sector )
{
/* try #2, backup anchor */
i_lba = i_last_sector - 256;
}
else
{
/* unable to find last sector */
return 0;
}
}
}
else
{
/* it is an anchor! continue... */
break;
}
}
/* main volume descriptor */
UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
p_partition->b_valid = 0;
b_vol_valid = 0;
p_partition->pi_volume_desc[0] = '\0';
i = 1;
/* Find Volume Descriptor */
do
{
i_lba = i_MVDS_location;
do
{
if( !UDFReadLB( p_partition->dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
{
/* Partition Descriptor */
UDFPartition( pi_lb,
&p_partition->i_flags,
&p_partition->i_number,
p_partition->pi_contents,
&p_partition->i_start,
&p_partition->i_length );
p_partition->b_valid = ( i_part_nb == p_partition->i_number );
}
else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
{
/* Logical Volume Descriptor */
if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
{
/* TODO: sector size wrong! */
}
else
{
b_vol_valid = 1;
}
}
} while( ( i_lba <= i_MVDS_location +
( i_MVDS_length - 1 ) / DVD_LB_SIZE )
&& ( i_tag_id != 8 )
&& ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
{
/* backup volume descriptor */
UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
}
} while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
/* we only care for the partition, not the volume */
return( p_partition->b_valid);
}
/*****************************************************************************
* DVDUDFFindFile: looks for a file on the UDF disc/imagefile
*****************************************************************************
* Path has to be the absolute pathname on the UDF filesystem,
* starting with '/'.
* returns absolute LB number, or 0 on error
*****************************************************************************/
u32 DVDUDFFindFile( dvdcss_handle dvdhandle, char * psz_path )
{
struct partition_s partition;
struct ad_s root_icb;
struct ad_s file;
struct ad_s icb;
u32 i_lba;
u16 i_tag_id;
u8 pi_lb[DVD_LB_SIZE];
u8 i_file_type;
char psz_tokenline[DVD_LB_SIZE] = "";
char * psz_token;
int i_partition;
strcat( psz_tokenline, psz_path );
/* Init file descriptor of UDF filesystem (== DVD) */
partition.dvdhandle = dvdhandle;
/* Find partition 0, standard partition for DVD-Video */
i_partition = 0;
if( !UDFFindPartition( i_partition, &partition ) )
{
//X intf_ErrMsg( "dvd error: partition 0 not found" );
return 0;
}
/* Find root dir ICB */
i_lba = partition.i_start;
do
{
if( !UDFReadLB( dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( i_tag_id == 256 )
{
/* File Set Descriptor */
UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
}
} while( ( i_lba < partition.i_start + partition.i_length )
&& ( i_tag_id != 8) && ( i_tag_id != 256 ) );
if( i_tag_id != 256 )
{
//X intf_ErrMsg( "dvd error: bad UDF descriptor" );
return 0;
}
if( root_icb.i_partition != i_partition )
{
//X intf_ErrMsg( "dvd error: bad UDF partition" );
return 0;
}
/* Find root dir */
if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
{
//X intf_ErrMsg( "dvd error: can't find root dir" );
return 0;
}
/* root dir should be dir */
if( i_file_type != 4 )
{
//X intf_ErrMsg( "dvd error: root dir error" );
return 0;
}
/* Tokenize filepath */
psz_token = strtok( psz_tokenline, "/" );
while( psz_token )
{
if( !UDFScanDir( file, psz_token, &icb, partition ) )
{
//X intf_ErrMsg( "dvd error: scan dir error" );
return 0;
}
if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
{
//X intf_ErrMsg( "dvd error: ICB error" );
return 0;
}
psz_token = strtok( NULL, "/" );
}
return partition.i_start + file.i_location;
}

31
modules/access/dvd/udf.h Normal file
View File

@ -0,0 +1,31 @@
/*****************************************************************************
* dvd_udf.h: structures for udf filesystem tools.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: udf.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* based on:
* - dvdudf by Christian Wolff <scarabaeus@convergence.de>
*
* 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.
*****************************************************************************/
/*
* Fonctions in dvd_udf.c
*/
u32 DVDUDFFindFile( dvdcss_handle, char * );

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
dvdplay_SOURCES = dvd.c access.c demux.c intf.c es.c tools.c

View File

@ -0,0 +1,501 @@
/*****************************************************************************
* access.c: access capabilities for dvdplay plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: access.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#if defined( WIN32 )
# include <io.h> /* read() */
#else
# include <sys/uio.h> /* struct iovec */
#endif
#if defined( WIN32 )
# include "input_iovec.h"
#endif
#include "dvd.h"
#include "es.h"
#include "tools.h"
#include "intf.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* called from outside */
static int dvdplay_SetArea ( input_thread_t *, input_area_t * );
static int dvdplay_SetProgram ( input_thread_t *, pgrm_descriptor_t * );
static int dvdplay_Read ( input_thread_t *, byte_t *, size_t );
static void dvdplay_Seek ( input_thread_t *, off_t );
static void pf_vmg_callback ( void*, dvdplay_event_t );
/* only from inside */
static int dvdNewArea( input_thread_t *, input_area_t * );
static int dvdNewPGC ( input_thread_t * );
/*****************************************************************************
* OpenDVD: open libdvdplay
*****************************************************************************/
int E_(OpenDVD) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_source;
dvd_data_t * p_dvd;
input_area_t * p_area;
int i_title_nr;
int i_title;
int i_chapter;
int i_angle;
int i;
p_dvd = malloc( sizeof(dvd_data_t) );
if( p_dvd == NULL )
{
msg_Err( p_input, "dvdplay error: out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_dvd;
p_input->pf_read = dvdplay_Read;
p_input->pf_seek = dvdplay_Seek;
p_input->pf_set_area = dvdplay_SetArea;
p_input->pf_set_program = dvdplay_SetProgram;
/* command line */
if( ( psz_source = dvdplay_ParseCL( p_input,
&i_title, &i_chapter, &i_angle ) ) == NULL )
{
free( p_dvd );
return -1;
}
/* Open libdvdplay */
p_dvd->vmg = dvdplay_open( psz_source, pf_vmg_callback, (void*)p_input );
/* free allocated strings */
free( psz_source );
if( p_dvd->vmg == NULL )
{
msg_Err( p_input, "dvdplay error: can't open source" );
free( p_dvd );
return -1;
}
p_dvd->p_intf = NULL;
p_dvd->i_still_time = 0;
/* set up input */
p_input->i_mtu = 0;
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
/* If we are here we can control the pace... */
p_input->stream.b_pace_control = 1;
/* seek is only allowed when we have size info */
p_input->stream.b_seekable = 0;
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
/* disc input method */
p_input->stream.i_method = INPUT_METHOD_DVD;
i_title_nr = dvdplay_title_nr( p_dvd->vmg );
#define area p_input->stream.pp_areas
/* Area 0 for menu */
area[0]->i_plugin_data = 0;
for( i = 1 ; i <= i_title_nr ; i++ )
{
input_AddArea( p_input );
/* Titles id */
area[i]->i_id = i;
/* Number of chapters */
area[i]->i_part_nb = dvdplay_chapter_nr( p_dvd->vmg, i );
area[i]->i_plugin_data = 0;
}
#undef area
msg_Dbg( p_input, "number of titles: %d", i_title_nr );
i_title = i_title <= i_title_nr ? i_title : 0;
p_area = p_input->stream.pp_areas[i_title];
p_area->i_part = i_chapter;
p_input->stream.p_selected_area = NULL;
/* set title, chapter, audio and subpic */
if( dvdplay_SetArea( p_input, p_area ) )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
return -1;
}
if( i_angle <= p_input->stream.i_pgrm_number )
{
dvdplay_SetProgram( p_input,
p_input->stream.pp_programs[i_angle - 1] );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->psz_demux = "dvdplay";
return 0;
}
/*****************************************************************************
* CloseDVD: close libdvdplay
*****************************************************************************/
void E_(CloseDVD) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data;
/* close libdvdplay */
dvdplay_close( p_dvd->vmg );
free( p_dvd );
p_input->p_access_data = NULL;
}
/*****************************************************************************
* dvdplay_SetProgram: set dvd angle.
*****************************************************************************
* This is actually a hack to make angle change through vlc interface with
* no need for a specific button.
*****************************************************************************/
static int dvdplay_SetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
if( p_input->stream.p_selected_program != p_program )
{
dvd_data_t * p_dvd;
int i_angle;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
i_angle = p_program->i_number;
if( !dvdplay_angle( p_dvd->vmg, i_angle ) )
{
memcpy( p_program, p_input->stream.p_selected_program,
sizeof(pgrm_descriptor_t) );
p_program->i_number = i_angle;
p_input->stream.p_selected_program = p_program;
msg_Dbg( p_input, "angle %d selected", i_angle );
}
}
return 0;
}
/*****************************************************************************
* dvdplay_SetArea: initialize input data for title x, chapter y.
* It should be called for each user navigation request.
*****************************************************************************
* Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
* Note that you have to take the lock before entering here.
*****************************************************************************/
static int dvdplay_SetArea( input_thread_t * p_input, input_area_t * p_area )
{
dvd_data_t * p_dvd;
p_dvd = (dvd_data_t*)p_input->p_access_data;
/*
* Title selection
*/
if( p_area != p_input->stream.p_selected_area )
{
int i_chapter;
/* prevent intf to try to seek */
p_input->stream.b_seekable = 0;
/* Store selected chapter */
i_chapter = p_area->i_part;
dvdNewArea( p_input, p_area );
dvdplay_start( p_dvd->vmg, p_area->i_id );
p_area->i_part = i_chapter;
} /* i_title >= 0 */
else
{
p_area = p_input->stream.p_selected_area;
}
/*
* Chapter selection
*/
if( p_area->i_part != dvdplay_chapter_cur( p_dvd->vmg ) )
{
if( ( p_area->i_part > 0 ) &&
( p_area->i_part <= p_area->i_part_nb ))
{
dvdplay_pg( p_dvd->vmg, p_area->i_part );
}
p_area->i_part = dvdplay_chapter_cur( p_dvd->vmg );
}
/* warn interface that something has changed */
p_area->i_tell =
LB2OFF( dvdplay_position( p_dvd->vmg ) ) - p_area->i_start;
p_input->stream.b_changed = 1;
return 0;
}
/*****************************************************************************
* dvdplay_Read: reads data packets.
*****************************************************************************
* Returns -1 in case of error, the number of bytes read if everything went
* well.
*****************************************************************************/
static int dvdplay_Read( input_thread_t * p_input,
byte_t * p_buffer, size_t i_count )
{
dvd_data_t * p_dvd;
off_t i_read;
p_dvd = (dvd_data_t *)p_input->p_access_data;
vlc_mutex_lock( &p_input->stream.stream_lock );
i_read = LB2OFF( dvdplay_read( p_dvd->vmg, p_buffer, OFF2LB( i_count ) ) );
p_input->stream.p_selected_area->i_tell =
LB2OFF( dvdplay_position( p_dvd->vmg ) ) -
p_input->stream.p_selected_area->i_start;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return i_read;
}
/*****************************************************************************
* dvdplay_Seek : Goes to a given position on the stream.
*****************************************************************************
* This one is used by the input and translate chronological position from
* input to logical position on the device.
* The lock should be taken before calling this function.
*****************************************************************************/
static void dvdplay_Seek( input_thread_t * p_input, off_t i_off )
{
dvd_data_t * p_dvd;
p_dvd = (dvd_data_t *)p_input->p_access_data;
vlc_mutex_lock( &p_input->stream.stream_lock );
dvdplay_seek( p_dvd->vmg, OFF2LB( i_off ) );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return;
}
/*****************************************************************************
* pf_vmg_callback: called by libdvdplay when some event happens
*****************************************************************************
* The stream lock has to be taken before entering here
*****************************************************************************/
static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
int i;
p_input = (input_thread_t*)p_args;
p_dvd = (dvd_data_t*)p_input->p_access_data;
switch( event )
{
case NEW_DOMAIN:
break;
case NEW_VTS:
break;
case NEW_FILE:
break;
case NEW_PGC:
/* prevent intf to try to seek by default */
p_input->stream.b_seekable = 0;
if( ( i = dvdplay_title_cur( p_dvd->vmg ) ) !=
p_input->stream.p_selected_area->i_id )
{
/* the title number has changed: update area */
msg_Warn( p_input, "new title %d (%d)", i,
p_input->stream.p_selected_area->i_id );
dvdNewArea( p_input,
p_input->stream.pp_areas[i] );
}
/* new pgc in same title: reinit ES */
dvdNewPGC( p_input );
p_input->stream.b_changed = 1;
break;
case NEW_PG:
/* update current chapter */
p_input->stream.p_selected_area->i_part =
dvdplay_chapter_cur( p_dvd->vmg );
break;
case NEW_CELL:
p_dvd->b_end_of_cell = 0;
break;
case END_OF_CELL:
p_dvd->b_end_of_cell = 1;
break;
case JUMP:
dvdplay_ES( p_input );
break;
case STILL_TIME:
/* we must pause only from demux
* when the data in cache has been decoded */
p_dvd->i_still_time = dvdplay_still_time( p_dvd->vmg );
msg_Dbg( p_input, "still time %d", p_dvd->i_still_time );
break;
case COMPLETE_VIDEO:
break;
case NEW_HIGHLIGHT:
break;
default:
msg_Err( p_input, "unknown event from libdvdplay (%d)",
event );
}
return;
}
static int dvdNewArea( input_thread_t * p_input, input_area_t * p_area )
{
dvd_data_t * p_dvd;
int i_angle_nb, i_angle;
int i;
p_dvd = (dvd_data_t*)p_input->p_access_data;
p_input->stream.p_selected_area = p_area;
/*
* One program for each angle
*/
while( p_input->stream.i_pgrm_number )
{
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
}
input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
dvdplay_angle_info( p_dvd->vmg, &i_angle_nb, &i_angle );
for( i = 1 ; i < i_angle_nb ; i++ )
{
input_AddProgram( p_input, i+1, 0 );
}
dvdplay_SetProgram( p_input,
p_input->stream.pp_programs[i_angle-1] );
// dvdNewPGC( p_input );
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.p_selected_program->b_is_ok = 1;
return 0;
}
static int dvdNewPGC( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
// int i_audio_nr = -1;
// int i_audio = -1;
// int i_subp_nr = -1;
// int i_subp = -1;
// int i_sec;
p_dvd = (dvd_data_t*)p_input->p_access_data;
// dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
// dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
dvdplay_ES( p_input );
p_input->stream.p_selected_area->i_start =
LB2OFF( dvdplay_title_first( p_dvd->vmg ) );
p_input->stream.p_selected_area->i_size =
LB2OFF( dvdplay_title_end ( p_dvd->vmg ) ) -
p_input->stream.p_selected_area->i_start;
if( p_input->stream.p_selected_area->i_size > 0 )
{
p_input->stream.b_seekable = 1;
}
else
{
p_input->stream.b_seekable = 0;
}
#if 0
i_sec = dvdplay_title_time( p_dvd->vmg );
msg_Dbg( p_input, "title time: %d:%02d:%02d (%d)",
i_sec/3600, (i_sec%3600)/60, i_sec%60, i_sec );
#endif
return 0;
}

View File

@ -0,0 +1,26 @@
/*****************************************************************************
* access.h: send info to access plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: access.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
union dvdplay_ctrl_u;
void dvdAccessSendControl( struct input_thread_t *, union dvdplay_ctrl_u * );

View File

@ -0,0 +1,172 @@
/*****************************************************************************
* demux.c: demux functions for dvdplay.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: demux.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "interface.h"
#include "dvd.h"
#include "intf.h"
#include "es.h"
/* how many packets dvdplay_Demux will read in each loop */
#define dvdplay_READ_ONCE 64
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Demux ( input_thread_t * );
/*****************************************************************************
* InitDVD: initializes dvdplay structures
*****************************************************************************/
int E_(InitDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd;
char * psz_intf = NULL;
if( p_input->stream.i_method != INPUT_METHOD_DVD )
{
return -1;
}
p_input->p_demux_data = (void*)p_input->p_access_data;
p_dvd = (dvd_data_t *)p_input->p_demux_data;
p_input->pf_demux = Demux;
p_input->pf_rewind = NULL;
psz_intf = config_GetPsz( p_input, "intf" );
config_PutPsz( p_input, "intf", "dvdplay" );
p_dvd->p_intf = intf_Create( p_input );
p_dvd->p_intf->b_block = VLC_FALSE;
intf_RunThread( p_dvd->p_intf );
if( psz_intf != NULL )
{
config_PutPsz( p_input, "intf", psz_intf );
}
return 0;
}
/*****************************************************************************
* EndDVD: frees unused data
*****************************************************************************/
void E_(EndDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd;
intf_thread_t * p_intf = NULL;
p_intf = vlc_object_find( p_input, VLC_OBJECT_INTF, FIND_CHILD );
if( p_intf != NULL )
{
intf_StopThread( p_intf );
vlc_object_detach_all( p_intf );
vlc_object_release( p_intf );
intf_Destroy( p_intf );
}
p_dvd = (dvd_data_t *)p_input->p_demux_data;
p_dvd->p_intf = NULL;
}
/*****************************************************************************
* Demux
*****************************************************************************/
static int Demux( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
data_packet_t * p_data;
ssize_t i_result;
ptrdiff_t i_remains;
int i_data_nb = 0;
p_dvd = (dvd_data_t *)p_input->p_demux_data;
/* Read headers to compute payload length */
do
{
if( ( i_result = input_ReadPS( p_input, &p_data ) ) <= 0)
{
return i_result;
}
i_remains = p_input->p_last_data - p_input->p_current_data;
input_DemuxPS( p_input, p_data );
++i_data_nb;
}
while( i_remains );
// if( p_dvd->b_still && p_dvd->b_end_of_cell && p_dvd->p_intf != NULL )
if( p_dvd->i_still_time && p_dvd->b_end_of_cell && p_dvd->p_intf != NULL )
{
pgrm_descriptor_t * p_pgrm;
/* when we receive still_time flag, we have to pause immediately */
input_SetStatus( p_input, INPUT_STATUS_PAUSE );
dvdIntfStillTime( p_dvd->p_intf, p_dvd->i_still_time );
p_dvd->i_still_time = 0;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_pgrm = p_input->stream.p_selected_program;
p_pgrm->i_synchro_state = SYNCHRO_REINIT;
vlc_mutex_unlock( &p_input->stream.stream_lock );
input_ClockManageControl( p_input, p_pgrm, 0 );
}
return i_data_nb;
}

View File

@ -0,0 +1,29 @@
/*****************************************************************************
* es.h: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: demux.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
void dvdplay_DeleteES( struct input_thread_s * );
void dvdplay_Video( struct input_thread_s * );
void dvdplay_Audio( struct input_thread_s * );
void dvdplay_Subp( struct input_thread_s * );
void dvdplay_ES( struct input_thread_s * );
void dvdplay_LaunchDecoders( struct input_thread_s * );

View File

@ -0,0 +1,64 @@
/*****************************************************************************
* dvd.c : dvdplay module for vlc
*****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* especially the 2048 bytes logical block size.
* It depends on: libdvdplay for ifo files and block reading.
*****************************************************************************
*
* Copyright (C) 2001 VideoLAN
* $Id: dvd.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.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> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
int E_(OpenDVD) ( vlc_object_t * );
void E_(CloseDVD) ( vlc_object_t * );
int E_(InitDVD) ( vlc_object_t * );
void E_(EndDVD) ( vlc_object_t * );
int E_(OpenIntf) ( vlc_object_t * );
void E_(CloseIntf) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( "[dvdplay:][device][@[title][,[chapter][,angle]]]", NULL );
set_description( "dvdplay input module" );
add_submodule();
set_capability( "access", 120 );
set_callbacks( E_(OpenDVD), E_(CloseDVD) );
add_shortcut( "dvd" );
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(InitDVD), E_(EndDVD) );
add_submodule();
set_capability( "interface", 0 );
set_callbacks( E_(OpenIntf), E_(CloseIntf) );
vlc_module_end();

View File

@ -0,0 +1,61 @@
/*****************************************************************************
* dvd.h: structure of the dvdplay plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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 <dvdread/dvd_reader.h>
#include <dvdread/ifo_types.h>
#include <dvdread/ifo_read.h>
#include <dvdread/nav_read.h>
#include <dvdread/nav_print.h>
#include <dvdplay/dvdplay.h>
#include <dvdplay/info.h>
#include <dvdplay/nav.h>
#include <dvdplay/state.h>
#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_VIDEO_LB_LEN))
#define OFF2LB(x) ((x) / DVD_VIDEO_LB_LEN)
/*****************************************************************************
* dvd_data_t: structure for communication between dvdplay access, demux
* and intf.
*****************************************************************************/
typedef struct
{
dvdplay_ptr vmg;
intf_thread_t * p_intf;
int i_audio_nb;
int i_spu_nb;
int i_still_time;
vlc_bool_t b_end_of_cell;
dvdplay_event_t event;
dvdplay_ctrl_t control;
} dvd_data_t;

299
modules/access/dvdplay/es.c Normal file
View File

@ -0,0 +1,299 @@
/*****************************************************************************
* es.c: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: es.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "dvd.h"
#include "iso_lang.h"
void dvdplay_LaunchDecoders( input_thread_t * p_input );
/*****************************************************************************
* dvdplay_DeleteES:
*****************************************************************************/
void dvdplay_DeleteES( input_thread_t* p_input )
{
free( p_input->stream.pp_selected_es );
p_input->stream.pp_selected_es = NULL;
p_input->stream.i_selected_es_number = 0;
while( p_input->stream.i_es_number )
{
input_DelES( p_input, p_input->stream.pp_es[0] );
}
free( p_input->stream.pp_es );
p_input->stream.pp_es = NULL;
p_input->stream.i_es_number = 0;
}
#define ADDES( id, fourcc, cat, lang, size ) \
msg_Dbg( p_input, "new es 0x%x", i_id ); \
p_es = input_AddES( p_input, NULL, id, size ); \
p_es->i_stream_id = i_id & 0xff; \
p_es->i_fourcc = (fourcc); \
p_es->i_cat = (cat); \
if( lang ) \
{ \
strcpy( p_es->psz_desc, DecodeLanguage( lang ) ); \
}
/*****************************************************************************
* dvdplay_Video: read video ES
*****************************************************************************/
void dvdplay_Video( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
video_attr_t * p_attr;
int i_id;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_attr = dvdplay_video_attr( p_dvd->vmg );
/* ES 0 -> video MPEG2 */
i_id = 0xe0;
if( p_attr->display_aspect_ratio )
{
ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, sizeof(int) );
*(int*)(p_es->p_demux_data) = p_attr->display_aspect_ratio;
}
else
{
ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, 0 );
}
}
/*****************************************************************************
* dvdplay_Audio: read audio ES
*****************************************************************************/
void dvdplay_Audio( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
audio_attr_t * p_attr;
int i_audio_nr = -1;
int i_audio = -1;
int i_channels;
int i_lang;
int i_id;
int i;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_dvd->i_audio_nb = 0;
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
/* Audio ES, in the order they appear in .ifo */
for( i = 1 ; i <= i_audio_nr ; i++ )
{
if( ( i_id = dvdplay_audio_id( p_dvd->vmg, i-1 ) ) > 0 )
{
p_attr = dvdplay_audio_attr( p_dvd->vmg, i-1 );
i_channels = p_attr->channels;
i_lang = p_attr->lang_code;
++p_dvd->i_audio_nb;
switch( p_attr->audio_format )
{
case 0x00: /* A52 */
ADDES( i_id, VLC_FOURCC('a','5','2',' '), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (A52)" );
break;
case 0x02:
case 0x03: /* MPEG audio */
ADDES( i_id, VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (mpeg)" );
break;
case 0x04: /* LPCM */
ADDES( i_id, VLC_FOURCC('l','p','c','m'), AUDIO_ES, i_lang, 0 );
strcat( p_es->psz_desc, " (lpcm)" );
break;
case 0x05: /* SDDS */
msg_Warn( p_input, "SDDS audio not handled" );
break;
case 0x06: /* DTS */
msg_Warn( p_input, "DTS audio not handled yet"
"(0x%x)", i_id );
break;
default:
i_id = 0;
msg_Warn( p_input, "unknown audio type %.2x",
p_attr->audio_format );
}
}
}
}
/*****************************************************************************
* dvdplay_Subp: read subpictures ES
*****************************************************************************/
void dvdplay_Subp( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
subp_attr_t * p_attr;
u32 * pi_palette;
int i_subp_nr = -1;
int i_subp = -1;
int i_id;
int i;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_dvd->i_spu_nb = 0;
dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
pi_palette = dvdplay_subp_palette( p_dvd->vmg );
for( i = 1 ; i <= i_subp_nr; i++ )
{
if( ( i_id = dvdplay_subp_id( p_dvd->vmg, i-1 ) ) >= 0 )
{
p_attr = dvdplay_subp_attr( p_dvd->vmg, i-1 );
++p_dvd->i_spu_nb;
if( pi_palette )
{
ADDES( i_id, VLC_FOURCC('s','p','u',' '), SPU_ES,
p_attr->lang_code, 16*sizeof(u32) );
*(int*)p_es->p_demux_data = 0xBeeF;
memcpy( (void*)p_es->p_demux_data + sizeof(int),
pi_palette, 16*sizeof(u32) );
}
else
{
ADDES( i_id, VLC_FOURCC('s','p','u',' '), SPU_ES,
p_attr->lang_code, 0 );
}
}
}
}
/*****************************************************************************
* dvdplay_LaunchDecoders
*****************************************************************************/
void dvdplay_LaunchDecoders( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
int i_audio_nr = -1;
int i_audio = -1;
int i_subp_nr = -1;
int i_subp = -1;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
if( config_GetInt( p_input, "video" ) )
{
input_SelectES( p_input, p_input->stream.pp_es[0] );
}
// if( !i_audio ) i_audio = 1;
if( i_audio > p_dvd->i_audio_nb ) i_audio = 1;
if( config_GetInt( p_input, "audio" )
&&( i_audio > 0 ) && ( p_dvd->i_audio_nb > 0 ) )
{
if( config_GetInt( p_input, "audio-type" ) == REQUESTED_A52 )
{
int i_a52 = i_audio;
while( ( i_a52 < p_dvd->i_audio_nb ) &&
( p_input->stream.pp_es[i_a52]->i_fourcc !=
VLC_FOURCC('a','5','2',' ') ) )
{
i_a52++;
}
if( p_input->stream.pp_es[i_a52]->i_fourcc ==
VLC_FOURCC('a','5','2',' ') )
{
input_SelectES( p_input,
p_input->stream.pp_es[i_a52] );
/* warn libdvdplay that we have chosen another stream */
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_a52 );
}
else
{
// input_SelectES( p_input,
// p_input->stream.pp_es[i_audio] );
}
}
else
{
input_SelectES( p_input,
p_input->stream.pp_es[i_audio] );
}
}
if( config_GetInt( p_input, "video" )
&& ( i_subp > 0 ) && ( p_dvd->i_spu_nb > 0 ) )
{
i_subp += p_dvd->i_audio_nb;
input_SelectES( p_input, p_input->stream.pp_es[i_subp] );
}
}
/*****************************************************************************
* dvdplay_ES:
*****************************************************************************/
void dvdplay_ES( input_thread_t * p_input )
{
dvdplay_DeleteES ( p_input );
dvdplay_Video ( p_input );
dvdplay_Audio ( p_input );
dvdplay_Subp ( p_input );
dvdplay_LaunchDecoders( p_input );
}

View File

@ -0,0 +1,29 @@
/*****************************************************************************
* es.h: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: es.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
void dvdplay_DeleteES( struct input_thread_t * );
void dvdplay_Video( struct input_thread_t * );
void dvdplay_Audio( struct input_thread_t * );
void dvdplay_Subp( struct input_thread_t * );
void dvdplay_ES( struct input_thread_t * );
void dvdplay_LaunchDecoders( struct input_thread_t * );

View File

@ -0,0 +1,318 @@
/*****************************************************************************
* intf.c: interface for DVD video manager
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: intf.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Stéphane Borel <stef@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> /* malloc(), free() */
#include <string.h>
#include <unistd.h>
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "video.h"
#include "video_output.h"
#include "dvd.h"
/*****************************************************************************
* intf_sys_t: description and status of interface
*****************************************************************************/
struct intf_sys_t
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
vlc_bool_t b_still;
vlc_bool_t b_inf_still;
mtime_t m_still_time;
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int InitThread ( intf_thread_t *p_intf );
/* Exported functions */
static void RunIntf ( intf_thread_t *p_intf );
/*****************************************************************************
* OpenIntf: initialize dummy interface
*****************************************************************************/
int E_(OpenIntf) ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
/* Allocate instance and initialize some members */
p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
if( p_intf->p_sys == NULL )
{
return( 1 );
};
p_intf->pf_run = RunIntf;
p_intf->p_sys->m_still_time = 0;
p_intf->p_sys->b_inf_still = 0;
p_intf->p_sys->b_still = 0;
return( 0 );
}
/*****************************************************************************
* CloseIntf: destroy dummy interface
*****************************************************************************/
void E_(CloseIntf) ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
/* Destroy structure */
free( p_intf->p_sys );
}
/*****************************************************************************
* RunIntf: main loop
*****************************************************************************/
static void RunIntf( intf_thread_t *p_intf )
{
vout_thread_t * p_vout;
dvdplay_ctrl_t control;
mtime_t mtime = 0;
mtime_t mlast = 0;
if( InitThread( p_intf ) < 0 )
{
msg_Err( p_intf, "can't initialize intf" );
return;
}
msg_Dbg( p_intf, "intf initialized" );
p_vout = NULL;
control.mouse.i_x = 0;
control.mouse.i_y = 0;
/* Main loop */
while( !p_intf->b_die )
{
vlc_mutex_lock( &p_intf->change_lock );
/*
* still images
*/
#if 1
if( p_intf->p_sys->b_still && !p_intf->p_sys->b_inf_still )
{
if( p_intf->p_sys->m_still_time > 0 )
{
/* update remaining still time */
mtime = mdate();
if( mlast )
{
p_intf->p_sys->m_still_time -= mtime - mlast;
}
mlast = mtime;
}
else
{
/* still time elasped */
input_SetStatus( p_intf->p_sys->p_input,
INPUT_STATUS_PLAY );
p_intf->p_sys->m_still_time = 0;
p_intf->p_sys->b_still = 0;
mlast = 0;
}
}
#else
if( p_intf->p_sys->m_still_time != (mtime_t)(-1) )
{
if( p_intf->p_sys->m_still_time )
{
mtime = mdate();
if( mlast )
{
p_intf->p_sys->m_still_time -= mtime - mlast;
}
if( !p_intf->p_sys->m_still_time )
{
input_SetStatus( p_intf->p_sys->p_input,
INPUT_STATUS_PLAY );
}
mlast = mtime;
}
}
#endif
/*
* mouse cursor
*/
p_vout = vlc_object_find( p_intf->p_sys->p_input,
VLC_OBJECT_VOUT, FIND_CHILD );
if( p_vout != NULL )
{
vlc_mutex_lock( &p_vout->change_lock );
if( control.mouse.i_x != p_vout->i_mouse_x ||
control.mouse.i_y != p_vout->i_mouse_y ||
p_vout->i_mouse_button )
{
int i_activate = 0;
control.mouse.i_x = p_vout->i_mouse_x;
control.mouse.i_y = p_vout->i_mouse_y;
if( p_vout->i_mouse_button )
{
control.type = DVDCtrlMouseActivate;
msg_Dbg( p_intf, "Activate coordinates: %dx%d",
p_vout->i_mouse_x, p_vout->i_mouse_y );
}
else
{
control.type = DVDCtrlMouseSelect;
msg_Dbg( p_intf, "Select coordinates: %dx%d",
p_vout->i_mouse_x, p_vout->i_mouse_y );
}
p_vout->i_mouse_button = 0;
vlc_mutex_unlock( &p_vout->change_lock );
msg_Dbg( p_intf, "send button" );
/* we can safely interact with libdvdplay
* with the stream lock */
vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
i_activate =
dvdplay_button( p_intf->p_sys->p_dvd->vmg, &control );
vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
if( i_activate && p_intf->p_sys->b_still )
{
input_SetStatus( p_intf->p_sys->p_input,
INPUT_STATUS_PLAY );
p_intf->p_sys->b_still = 0;
p_intf->p_sys->b_inf_still = 0;
p_intf->p_sys->m_still_time = 0;
}
}
else
{
vlc_mutex_unlock( &p_vout->change_lock );
}
vlc_object_release( p_vout );
}
vlc_mutex_unlock( &p_intf->change_lock );
/* Wait a bit */
msleep( INTF_IDLE_SLEEP );
}
vlc_object_release( p_intf->p_sys->p_input );
}
/*****************************************************************************
* InitThread:
*****************************************************************************/
static int InitThread( intf_thread_t * p_intf )
{
/* we might need some locking here */
if( !p_intf->b_die )
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT );
p_dvd = (dvd_data_t*)p_input->p_access_data;
p_dvd->p_intf = p_intf;
vlc_mutex_lock( &p_intf->change_lock );
p_intf->p_sys->p_input = p_input;
p_intf->p_sys->p_dvd = p_dvd;
vlc_mutex_unlock( &p_intf->change_lock );
return 0;
}
else
{
return -1;
}
}
/*****************************************************************************
* dvdIntfStillTime: function provided to demux plugin to request
* still images
*****************************************************************************/
int dvdIntfStillTime( intf_thread_t *p_intf, int i_sec )
{
vlc_mutex_lock( &p_intf->change_lock );
#if 1
if( i_sec == 0xff )
{
p_intf->p_sys->b_still = 1;
p_intf->p_sys->b_inf_still = 1;
}
else if( i_sec > 0 )
{
p_intf->p_sys->b_still = 1;
p_intf->p_sys->m_still_time = 1000000 * i_sec;
}
#else
if( i_sec > 0 )
{
if( i_sec == 0xff )
{
p_intf->p_sys->m_still_time = (mtime_t)(-1);
msg_Warn( p_intf, "%lld", p_intf->p_sys->m_still_time );
}
else
{
p_intf->p_sys->m_still_time = 1000000 * i_sec;
}
}
#endif
vlc_mutex_unlock( &p_intf->change_lock );
return 0;
}

View File

@ -0,0 +1,24 @@
/*****************************************************************************
* intf.h: send info to intf.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: intf.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
int dvdIntfStillTime( struct intf_thread_t *, int );

View File

@ -0,0 +1,121 @@
/*****************************************************************************
* tools.c: tools for dvd plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: tools.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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 <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "dvd.h"
/*****************************************************************************
* dvdplay_ParseCL: parse command line
*****************************************************************************/
char * dvdplay_ParseCL( input_thread_t * p_input,
int * i_title, int * i_chapter, int * i_angle )
{
dvd_data_t * p_dvd;
struct stat stat_info;
char * psz_parser;
char * psz_source;
char * psz_next;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
psz_parser = psz_source = strdup( p_input->psz_name );
if( !psz_parser )
{
return NULL;
}
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
*i_title = 0;
*i_chapter = 1;
*i_angle = 1;
if( *psz_parser == '@' )
{
/* Found options */
*psz_parser = '\0';
++psz_parser;
*i_title = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
*i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
*i_angle = (int)strtol( psz_next + 1, NULL, 10 );
}
}
}
*i_title = *i_title >= 0 ? *i_title : 0;
*i_chapter = *i_chapter ? *i_chapter : 1;
*i_angle = *i_angle ? *i_angle : 1;
if( !*psz_source )
{
free( psz_source );
if( !p_input->psz_access )
{
return NULL;
}
psz_source = config_GetPsz( p_input, "dvd" );
}
if( stat( psz_source, &stat_info ) == -1 )
{
msg_Err( p_input, "cannot stat() source `%s' (%s)",
psz_source, strerror(errno));
return NULL;
}
if( !S_ISBLK(stat_info.st_mode) &&
!S_ISCHR(stat_info.st_mode) &&
!S_ISDIR(stat_info.st_mode) )
{
msg_Dbg( p_input, "plugin discarded"
" (not a valid source)" );
return NULL;
}
msg_Dbg( p_input, "dvdroot=%s title=%d chapter=%d angle=%d",
psz_source, *i_title, *i_chapter, *i_angle );
return psz_source;
}

View File

@ -0,0 +1,24 @@
/*****************************************************************************
* tools.h: tools for dvdplay plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: tools.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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.
*****************************************************************************/
char * dvdplay_ParseCL( struct input_thread_t *, int*, int*, int* );

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
dvdread_SOURCES = dvdread.c input.c

View File

@ -0,0 +1,53 @@
/*****************************************************************************
* dvdread.c : DvdRead input module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: dvdread.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.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> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
/*****************************************************************************
* External prototypes
*****************************************************************************/
int E_(OpenDVD) ( vlc_object_t * );
void E_(CloseDVD) ( vlc_object_t * );
int E_(InitDVD) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( "[dvdread:][device][@[title][,[chapter][,angle]]]", NULL );
set_description( _("DVDRead input module") );
add_submodule();
set_capability( "access", 110 );
set_callbacks( E_(OpenDVD), E_(CloseDVD) );
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(InitDVD), NULL );
vlc_module_end();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/*****************************************************************************
* input.h: thread structure of the DVD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: input.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@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
*****************************************************************************/
/* Logical block size for DVD-VIDEO */
#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_VIDEO_LB_LEN))
#define OFF2LB(x) ((x) >> 11)
/*****************************************************************************
* thread_dvd_data_t: extension of input_thread_t for DVD specificity.
*****************************************************************************/
typedef struct thread_dvd_data_s
{
dvd_reader_t * p_dvdread;
dvd_file_t * p_title;
ifo_handle_t * p_vmg_file;
ifo_handle_t * p_vts_file;
int i_title;
int i_chapter;
int i_angle;
int i_angle_nb;
tt_srpt_t * p_tt_srpt;
pgc_t * p_cur_pgc;
dsi_t dsi_pack;
int i_ttn;
unsigned int i_pack_len;
unsigned int i_cur_block;
unsigned int i_next_vobu;
unsigned int i_end_block;
int i_cur_cell;
int i_next_cell;
vlc_bool_t b_eoc;
} thread_dvd_data_t;

151
modules/access/file.c Normal file
View File

@ -0,0 +1,151 @@
/*****************************************************************************
* file.c: file input (file: access plug-in)
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: file.c,v 1.1 2002/08/04 17:23:41 sam 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 <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
/*****************************************************************************
* Open: open the file
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_name = p_input->psz_name;
int i_stat;
struct stat stat_info;
input_socket_t * p_access_data;
vlc_bool_t b_stdin;
p_input->i_mtu = 0;
b_stdin = psz_name[0] == '-' && psz_name[1] == '\0';
if( !b_stdin && (i_stat = stat( psz_name, &stat_info )) == (-1) )
{
msg_Err( p_input, "cannot stat() file `%s' (%s)",
psz_name, strerror(errno));
return( -1 );
}
p_input->pf_read = input_FDRead;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
p_input->pf_seek = input_FDSeek;
vlc_mutex_lock( &p_input->stream.stream_lock );
if( *p_input->psz_access && !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 );
msg_Err( p_input, "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 );
msg_Dbg( p_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 )
{
msg_Err( p_input, "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) )
{
msg_Err( p_input, "cannot open file %s (%s)", psz_name,
strerror(errno) );
free( p_access_data );
return( -1 );
}
return( 0 );
}
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("Standard filesystem file reading") );
set_capability( "access", 50 );
add_shortcut( "stream" );
set_callbacks( Open, __input_FDClose );
vlc_module_end();

500
modules/access/http.c Normal file
View File

@ -0,0 +1,500 @@
/*****************************************************************************
* http.c: HTTP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: http.c,v 1.1 2002/08/04 17:23:41 sam 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 <vlc/vlc.h>
#include <vlc/input.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>
# ifndef IN_MULTICAST
# define IN_MULTICAST(a) IN_CLASSD(a)
# endif
#else
# include <sys/socket.h>
#endif
#include "network.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetProgram ( input_thread_t *, pgrm_descriptor_t * );
static void Seek ( input_thread_t *, off_t );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("HTTP access module") );
set_capability( "access", 0 );
add_shortcut( "http4" );
add_shortcut( "http6" );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* _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];
char * psz_name;
} _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;
module_t * p_network;
char psz_buffer[256];
byte_t * psz_parser;
int i_returncode, i;
char * psz_return_alpha;
/* Find an appropriate network module */
p_input->p_private = (void*) &p_access_data->socket_desc;
p_network = module_Need( p_input, "network", p_access_data->psz_network );
if( p_network == NULL )
{
return( -1 );
}
module_Unneed( p_input, 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"
if ( p_input->stream.b_seekable )
{
snprintf( psz_buffer, sizeof(psz_buffer),
"%s"
"Range: bytes=%lld-\r\n"
HTTP_USERAGENT HTTP_END,
p_access_data->psz_buffer, i_tell );
}
else
{
snprintf( psz_buffer, sizeof(psz_buffer),
"%s"
HTTP_USERAGENT HTTP_END,
p_access_data->psz_buffer );
}
psz_buffer[sizeof(psz_buffer) - 1] = '\0';
/* Send GET ... */
if( send( p_access_data->_socket.i_handle, psz_buffer,
strlen( psz_buffer ), 0 ) == (-1) )
{
msg_Err( p_input, "cannot send request (%s)", strerror(errno) );
input_FDNetworkClose( 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 ! It's UGLY but mandatory because
* input_FillBuffer assumes p_input->pf_read exists */
p_input->pf_read = input_FDNetworkRead;
while( !input_FillBuffer( p_input ) )
{
if( p_input->b_die || p_input->b_error )
{
input_FDNetworkClose( p_input );
return( -1 );
}
}
/* Parse HTTP header. */
#define MAX_LINE 1024
/* get the returncode */
if( input_Peek( p_input, &psz_parser, MAX_LINE ) <= 0 )
{
msg_Err( p_input, "not enough data" );
input_FDNetworkClose( p_input );
return( -1 );
}
if( !strncmp( psz_parser, "HTTP/1.",
strlen("HTTP/1.") ) )
{
psz_parser += strlen("HTTP 1.") + 2;
i_returncode = atoi( psz_parser );
msg_Dbg( p_input, "HTTP server replied: %i", i_returncode );
psz_parser += 4;
for ( i = 0; psz_parser[i] != '\r' || psz_parser[i+1] != '\n'; i++ )
{
;
}
psz_return_alpha = malloc( i + 1 );
memcpy( psz_return_alpha, psz_parser, i );
psz_return_alpha[i] = '\0';
}
else
{
msg_Err( p_input, "invalid http reply" );
return -1;
}
if ( i_returncode >= 400 ) /* something is wrong */
{
msg_Err( p_input, "%i %s", i_returncode,
psz_return_alpha );
return -1;
}
for( ; ; )
{
if( input_Peek( p_input, &psz_parser, MAX_LINE ) <= 0 )
{
msg_Err( p_input, "not enough data" );
input_FDNetworkClose( 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: ");
vlc_mutex_lock( &p_input->stream.stream_lock );
#ifdef HAVE_ATOLL
p_input->stream.p_selected_area->i_size = atoll( psz_parser )
+ i_tell;
#else
/* FIXME : this won't work for 64-bit lengths */
p_input->stream.p_selected_area->i_size = atoi( psz_parser )
+ i_tell;
#endif
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 );
}
/*****************************************************************************
* Open: parse URL and open the remote file at the beginning
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
_input_socket_t * p_access_data;
char * psz_name = strdup(p_input->psz_name);
char * psz_parser = psz_name;
char * psz_server_addr = "";
char * psz_server_port = "";
char * psz_path = "";
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 )
{
msg_Err( p_input, "out of memory" );
free(psz_name);
return( -1 );
}
p_access_data->psz_name = psz_name;
p_access_data->psz_network = "";
if( config_GetInt( p_input, "ipv4" ) )
{
p_access_data->psz_network = "ipv4";
}
if( config_GetInt( p_input, "ipv6" ) )
{
p_access_data->psz_network = "ipv6";
}
if( *p_input->psz_access )
{
/* Find out which shortcut was used */
if( !strncmp( p_input->psz_access, "http6", 6 ) )
{
p_access_data->psz_network = "ipv6";
}
else if( !strncmp( p_input->psz_access, "http4", 6 ) )
{
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 )
{
i_server_port = strtol( psz_server_port, &psz_parser, 10 );
if( *psz_parser )
{
msg_Err( p_input, "cannot parse server port near %s", psz_parser );
free( p_input->p_access_data );
free( psz_name );
return( -1 );
}
}
if( i_server_port == 0 )
{
i_server_port = 80;
}
if( !*psz_server_addr )
{
msg_Err( p_input, "no server given" );
free( p_input->p_access_data );
free( psz_name );
return( -1 );
}
/* Check proxy */
if( (psz_proxy = getenv( "http_proxy" )) != NULL && *psz_proxy )
{
/* 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
{
msg_Err( p_input, "http_proxy environment variable is invalid!" );
free( p_input->p_access_data );
free( psz_name );
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\r\n HTTP/1.0\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';
msg_Dbg( p_input, "opening server=%s port=%d path=%s",
psz_server_addr, i_server_port, psz_path );
p_input->pf_read = input_FDNetworkRead;
p_input->pf_set_program = SetProgram;
p_input->pf_set_area = NULL;
p_input->pf_seek = Seek;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 1;
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;
if( HTTPConnect( p_input, 0 ) )
{
char * psz_pos = strstr(p_access_data->psz_buffer, "HTTP/1.1");
p_input->stream.b_seekable = 0;
psz_pos[7] = '0';
if( HTTPConnect( p_input, 0 ) )
{
free( p_input->p_access_data );
free( psz_name );
return( -1 );
}
}
return 0;
}
/*****************************************************************************
* Close: free unused data structures
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
_input_socket_t * p_access_data =
(_input_socket_t *)p_input->p_access_data;
free( p_access_data->psz_name );
input_FDNetworkClose( p_input );
}
/*****************************************************************************
* SetProgram: do nothing
*****************************************************************************/
static int SetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
return( 0 );
}
/*****************************************************************************
* Seek: close and re-open a connection at the right place
*****************************************************************************/
static void Seek( 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 );
msg_Dbg( p_input, "seeking to position %lld", i_pos );
HTTPConnect( p_input, i_pos );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
satellite_SOURCES = satellite.c access.c dvb.c

View File

@ -0,0 +1,434 @@
/*****************************************************************************
* access.c: Satellite card input
*****************************************************************************
* Copyright (C) 1998-2002 VideoLAN
*
* Authors: Johan Bilien <jobi@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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "dvb.h"
#define SATELLITE_READ_ONCE 3
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len );
static int SatelliteSetArea ( input_thread_t *, input_area_t * );
static int SatelliteSetProgram ( input_thread_t *, pgrm_descriptor_t * );
static void SatelliteSeek ( input_thread_t *, off_t );
/*****************************************************************************
* Open: open the dvr device
*****************************************************************************/
int E_(Open) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
input_socket_t * p_satellite;
char * psz_parser;
char * psz_next;
int i_fd = 0;
int i_freq = 0;
int i_srate = 0;
vlc_bool_t b_pol = 0;
int i_fec = 0;
float f_fec = 1./2;
vlc_bool_t b_diseqc;
int i_lnb_lof1;
int i_lnb_lof2;
int i_lnb_slof;
/* parse the options passed in command line : */
psz_parser = strdup( p_input->psz_name );
if( !psz_parser )
{
return( -1 );
}
p_input->pf_read = SatelliteRead;
p_input->pf_set_program = SatelliteSetProgram;
p_input->pf_set_area = SatelliteSetArea;
p_input->pf_seek = SatelliteSeek;
i_freq = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
b_pol = (vlc_bool_t)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
i_fec = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
i_srate = (int)strtol( psz_parser, &psz_next, 10 );
}
}
}
if( i_freq > 12999 || i_freq < 10000 )
{
msg_Warn( p_input, "invalid frequency, using default one" );
i_freq = config_GetInt( p_input, "frequency" );
if( i_freq > 12999 || i_freq < 10000 )
{
msg_Err( p_input, "invalid default frequency" );
return -1;
}
}
if( i_srate > 30000 || i_srate < 1000 )
{
msg_Warn( p_input, "invalid symbol rate, using default one" );
i_srate = config_GetInt( p_input, "symbol-rate" );
if( i_srate > 30000 || i_srate < 1000 )
{
msg_Err( p_input, "invalid default symbol rate" );
return -1;
}
}
if( b_pol && b_pol != 1 )
{
msg_Warn( p_input, "invalid polarization, using default one" );
b_pol = config_GetInt( p_input, "polarization" );
if( b_pol && b_pol != 1 )
{
msg_Err( p_input, "invalid default polarization" );
return -1;
}
}
if( i_fec > 7 || i_fec < 1 )
{
msg_Warn( p_input, "invalid FEC, using default one" );
i_fec = config_GetInt( p_input, "fec" );
if( i_fec > 7 || i_fec < 1 )
{
msg_Err( p_input, "invalid default FEC" );
return -1;
}
}
switch( i_fec )
{
case 1:
f_fec = 1./2;
break;
case 2:
f_fec = 2./3;
break;
case 3:
f_fec = 3./4;
break;
case 4:
f_fec = 4./5;
break;
case 5:
f_fec = 5./6;
break;
case 6:
f_fec = 6./7;
break;
case 7:
f_fec = 7./8;
break;
default:
/* cannot happen */
break;
}
/* Initialise structure */
p_satellite = malloc( sizeof( input_socket_t ) );
if( p_satellite == NULL )
{
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_satellite;
/* Open the DVR device */
msg_Dbg( p_input, "opening DVR device `%s'", DVR );
if( (p_satellite->i_handle = open( DVR,
/*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
{
msg_Warn( p_input, "cannot open `%s' (%s)", DVR, strerror(errno) );
free( p_satellite );
return -1;
}
/* Get antenna configuration options */
b_diseqc = config_GetInt( p_input, "diseqc" );
i_lnb_lof1 = config_GetInt( p_input, "lnb-lof1" );
i_lnb_lof2 = config_GetInt( p_input, "lnb-lof2" );
i_lnb_slof = config_GetInt( p_input, "lnb-slof" );
/* Initialize the Satellite Card */
msg_Dbg( p_input, "initializing Sat Card with Freq: %d, Pol: %d, "
"FEC: %03f, Srate: %d", i_freq, b_pol, f_fec, i_srate );
if ( ioctl_SECControl( i_freq * 1000, b_pol, i_lnb_slof * 1000,
b_diseqc ) < 0 )
{
msg_Err( p_input, "an error occured when controling SEC" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
}
msg_Dbg( p_input, "initializing frontend device" );
switch (ioctl_SetQPSKFrontend ( i_freq * 1000, i_srate* 1000, f_fec,
i_lnb_lof1 * 1000, i_lnb_lof2 * 1000, i_lnb_slof * 1000))
{
case -2:
msg_Err( p_input, "frontend returned an unexpected event" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
break;
case -3:
msg_Err( p_input, "frontend returned no event" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
break;
case -4:
msg_Err( p_input, "frontend: timeout when polling for event" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
break;
case -5:
msg_Err( p_input, "an error occured when polling frontend device" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
break;
case -1:
msg_Err( p_input, "frontend returned a failure event" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
break;
default:
break;
}
msg_Dbg( p_input, "setting filter on PAT" );
if ( ioctl_SetDMXFilter( 0, &i_fd, 3 ) < 0 )
{
msg_Err( p_input, "an error occured when setting filter on PAT" );
close( p_satellite->i_handle );
free( p_satellite );
return -1;
}
if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
{
msg_Err( p_input, "could not initialize stream structure" );
close( p_satellite->i_handle );
free( p_satellite );
return( -1 );
}
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;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->i_mtu = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
p_input->stream.i_method = INPUT_METHOD_SATELLITE;
return 0;
}
/*****************************************************************************
* Close : Close the device
*****************************************************************************/
void E_(Close) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
input_socket_t * p_satellite;
int i_es_index;
if ( p_input->stream.p_selected_program )
{
for ( i_es_index = 1 ;
i_es_index < p_input->stream.p_selected_program->
i_es_number ;
i_es_index ++ )
{
#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
if ( p_es->p_decoder_fifo )
{
ioctl_UnsetDMXFilter( p_es->i_demux_fd );
}
#undef p_es
}
}
p_satellite = (input_socket_t *)p_input;
close( p_satellite->i_handle );
}
/*****************************************************************************
* SatelliteRead: reads data from the satellite card
*****************************************************************************/
static ssize_t SatelliteRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
int i;
/* if not set, set filters to the PMTs */
for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
{
if ( p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd == 0 )
{
msg_Dbg( p_input, "setting filter on pmt pid %d",
p_input->stream.pp_programs[i]->pp_es[0]->i_id );
ioctl_SetDMXFilter( p_input->stream.pp_programs[i]->pp_es[0]->i_id,
&p_input->stream.pp_programs[i]->pp_es[0]->i_demux_fd,
3 );
}
}
return input_FDRead( p_input, p_buffer, i_len );
}
/*****************************************************************************
* SatelliteSetArea : Does nothing
*****************************************************************************/
static int SatelliteSetArea( input_thread_t * p_input, input_area_t * p_area )
{
return -1;
}
/*****************************************************************************
* SatelliteSetProgram : Sets the card filters according to the
* selected program,
* and makes the appropriate changes to stream structure.
*****************************************************************************/
int SatelliteSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_new_prg )
{
int i_es_index;
if ( p_input->stream.p_selected_program )
{
for ( i_es_index = 1 ; /* 0 should be the PMT */
i_es_index < p_input->stream.p_selected_program->
i_es_number ;
i_es_index ++ )
{
#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
if ( p_es->p_decoder_fifo )
{
input_UnselectES( p_input , p_es );
}
if ( p_es->i_demux_fd )
{
ioctl_UnsetDMXFilter( p_es->i_demux_fd );
p_es->i_demux_fd = 0;
}
#undef p_es
}
}
for (i_es_index = 1 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
{
#define p_es p_new_prg->pp_es[i_es_index]
switch( p_es->i_cat )
{
case MPEG1_VIDEO_ES:
case MPEG2_VIDEO_ES:
if ( config_GetInt( p_input, "video" ) )
{
ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 1);
input_SelectES( p_input , p_es );
}
break;
case MPEG1_AUDIO_ES:
case MPEG2_AUDIO_ES:
if ( config_GetInt( p_input, "audio" ) )
{
ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 2);
input_SelectES( p_input , p_es );
}
break;
default:
ioctl_SetDMXFilter( p_es->i_id, &p_es->i_demux_fd, 3);
input_SelectES( p_input , p_es );
break;
#undef p_es
}
}
p_input->stream.p_selected_program = p_new_prg;
return( 0 );
}
/*****************************************************************************
* SatelliteSeek: does nothing (not a seekable stream
*****************************************************************************/
static void SatelliteSeek( input_thread_t * p_input, off_t i_off )
{
return;
}

View File

@ -0,0 +1,235 @@
/*****************************************************************************
* dvb.c : functions to control a DVB card under Linux
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
*
* Authors: Damien Lucas <nitrox@via.ecp.fr>
* Johan Bilien <jobi@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.
*****************************************************************************/
#include <vlc/vlc.h>
#include <sys/ioctl.h>
#include <stdio.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h> /* int16_t .. */
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
/* DVB Card Drivers */
#include <ost/sec.h>
#include <ost/dmx.h>
#include <ost/frontend.h>
#include "dvb.h"
/*****************************************************************************
* ioctl_SECControl : commands the SEC device
*****************************************************************************/
int ioctl_SECControl( int freq, int pol, int lnb_slof, int diseqc)
{
struct secCommand scmd;
struct secCmdSequence scmds;
int sec;
if((sec = open(SEC,O_RDWR)) < 0)
{
return -1;
}
/* Set the frequency of the transponder, taking into account the
local frequencies of the LNB */
scmds.continuousTone = (freq<lnb_slof) ? SEC_TONE_OFF : SEC_TONE_ON;
/* Set the polarity of the transponder by setting the correct
voltage on the universal LNB */
scmds.voltage = (pol) ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13;
/* In case we have a DiSEqC, set it to the correct address */
scmd.type=0;
scmd.u.diseqc.addr=0x10;
scmd.u.diseqc.cmd=0x38;
scmd.u.diseqc.numParams=1;
scmd.u.diseqc.params[0] = 0xF0 | ((diseqc * 4) & 0x0F) |
(scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
(scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
scmds.miniCommand=SEC_MINI_NONE;
scmds.numCommands=1;
scmds.commands=&scmd;
/* Send the data to the SEC device to prepare the LNB for tuning */
/*intf_Msg("Sec: Sending data\n");*/
if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0)
{
return -1;
}
close(sec);
return 0;
}
static int check_qpsk( int );
/*****************************************************************************
* ioctl_SetQPSKFrontend : controls the FE device
*****************************************************************************/
int ioctl_SetQPSKFrontend (int freq, int srate, int fec,\
int lnb_lof1, int lnb_lof2, int lnb_slof)
{
FrontendParameters fep;
int front;
int rc;
/* Open the frontend device */
if((front = open(FRONTEND,O_RDWR)) < 0)
{
return -1;
}
/* Set the frequency of the transponder, taking into account the
local frequencies of the LNB */
fep.Frequency = (freq < lnb_slof) ? freq - lnb_lof1 : freq - lnb_lof2;
/* Set symbol rate and FEC */
fep.u.qpsk.SymbolRate = srate;
fep.u.qpsk.FEC_inner = FEC_AUTO;
/* Now send it all to the frontend device */
if (ioctl(front, FE_SET_FRONTEND, &fep) < 0)
{
return -1;
}
/* Check if it worked */
rc=check_qpsk(front);
/* Close front end device */
close(front);
return rc;
}
/******************************************************************
* Check completion of the frontend control sequence
******************************************************************/
static int check_qpsk(int front)
{
struct pollfd pfd[1];
FrontendEvent event;
/* poll for QPSK event to check if tuning worked */
pfd[0].fd = front;
pfd[0].events = POLLIN;
if (poll(pfd,1,3000))
{
if (pfd[0].revents & POLLIN)
{
if ( ioctl(front, FE_GET_EVENT, &event) == -EBUFFEROVERFLOW)
{
return -5;
}
switch(event.type)
{
case FE_UNEXPECTED_EV:
return -2;
case FE_FAILURE_EV:
return -1;
case FE_COMPLETION_EV:
break;
}
}
else
{
/* should come here */
return -3;
}
}
else
{
return -4;
}
return 0;
}
/*****************************************************************************
* ioctl_SetDMXAudioFilter : controls the demux to add a filter
*****************************************************************************/
int ioctl_SetDMXFilter( int i_pid, int * pi_fd , int i_type )
{
struct dmxPesFilterParams s_filter_params;
/* We first open the device */
if ((*pi_fd = open(DMX, O_RDWR|O_NONBLOCK)) < 0)
{
return -1;
}
/* We fill the DEMUX structure : */
s_filter_params.pid = i_pid;
s_filter_params.input = DMX_IN_FRONTEND;
s_filter_params.output = DMX_OUT_TS_TAP;
switch ( i_type )
{
case 1:
s_filter_params.pesType = DMX_PES_VIDEO;
break;
case 2:
s_filter_params.pesType = DMX_PES_AUDIO;
break;
case 3:
s_filter_params.pesType = DMX_PES_OTHER;
break;
}
s_filter_params.flags = DMX_IMMEDIATE_START;
/* We then give the order to the device : */
if (ioctl(*pi_fd, DMX_SET_PES_FILTER, &s_filter_params) < 0)
{
return -1;
}
return 0;
}
/*****************************************************************************
* ioctl_UnsetDMXFilter : removes a filter
*****************************************************************************/
int ioctl_UnsetDMXFilter(int demux)
{
ioctl(demux, DMX_STOP);
close(demux);
return 0;
}

View File

@ -0,0 +1,39 @@
/*****************************************************************************
* linux_dvb_tools.h : functions to control a DVB card under Linux
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
*
* Authors: Johan Bilien <jobi@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.
*****************************************************************************/
/*****************************************************************************
* Devices location
*****************************************************************************/
#define SEC "/dev/ost/sec"
#define DMX "/dev/ost/demux"
#define FRONTEND "/dev/ost/frontend"
#define DVR "/dev/ost/dvr"
/*****************************************************************************
* Prototypes
*****************************************************************************/
int ioctl_SECControl( int , int , int , int );
int ioctl_SetQPSKFrontend ( int , int , int , int , int , int );
int ioctl_SetDMXFilter( int , int *, int );
int ioctl_UnsetDMXFilter( int );

View File

@ -0,0 +1,83 @@
/*****************************************************************************
* satellite.c : Satellite input module for vlc
*****************************************************************************
* Copyright (C) 2000 VideoLAN
*
* Authors: Samuel Hocevar <sam@zoy.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> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
/*****************************************************************************
* External prototypes
*****************************************************************************/
int E_(Open) ( vlc_object_t * );
void E_(Close) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define FREQ_TEXT N_("satellite default transponder frequency")
#define FREQ_LONGTEXT ""
#define POL_TEXT N_("satellite default transponder polarization")
#define POL_LONGTEXT ""
#define FEC_TEXT N_("satellite default transponder FEC")
#define FEC_LONGTEXT ""
#define SRATE_TEXT N_("satellite default transponder symbol rate")
#define SRATE_LONGTEXT ""
#define DISEQC_TEXT N_("use diseqc with antenna")
#define DISEQC_LONGTEXT ""
#define LNB_LOF1_TEXT N_("antenna lnb_lof1 (kHz)")
#define LNB_LOF1_LONGTEXT ""
#define LNB_LOF2_TEXT N_("antenna lnb_lof2 (kHz)")
#define LNB_LOF2_LONGTEXT ""
#define LNB_SLOF_TEXT N_("antenna lnb_slof (kHz)")
#define LNB_SLOF_LONGTEXT ""
vlc_module_begin();
add_category_hint( N_("Input"), NULL );
add_integer( "frequency", 11954, NULL, FREQ_TEXT, FREQ_LONGTEXT );
add_integer( "polarization", 0, NULL, POL_TEXT, POL_LONGTEXT );
add_integer( "fec", 3, NULL, FEC_TEXT, FEC_LONGTEXT );
add_integer( "symbol-rate", 27500, NULL, SRATE_TEXT, SRATE_LONGTEXT );
add_bool( "diseqc", 0, NULL, DISEQC_TEXT, DISEQC_LONGTEXT );
add_integer( "lnb-lof1", 10000, NULL,
LNB_LOF1_TEXT, LNB_LOF1_LONGTEXT );
add_integer( "lnb-lof2", 10000, NULL,
LNB_LOF2_TEXT, LNB_LOF2_LONGTEXT );
add_integer( "lnb-slof", 11700, NULL,
LNB_SLOF_TEXT, LNB_SLOF_LONGTEXT );
set_description( _("satellite input module") );
set_capability( "access", 0 );
add_shortcut( "sat" );
set_callbacks( E_(Open), E_(Close) );
vlc_module_end();

251
modules/access/udp.c Normal file
View File

@ -0,0 +1,251 @@
/*****************************************************************************
* udp.c: raw UDP access plug-in
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
* $Id: udp.c,v 1.1 2002/08/04 17:23:41 sam 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 <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#elif defined( _MSC_VER ) && defined( _WIN32 )
# include <io.h>
#endif
#include "network.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("raw UDP access module") );
set_capability( "access", 0 );
add_shortcut( "udpstream" );
add_shortcut( "udp4" );
add_shortcut( "udp6" );
set_callbacks( Open, __input_FDNetworkClose );
vlc_module_end();
/*****************************************************************************
* Open: open the socket
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
input_socket_t * p_access_data;
module_t * p_network;
char * psz_network = "";
char * psz_name = strdup(p_input->psz_name);
char * psz_parser = psz_name;
char * psz_server_addr = "";
char * psz_server_port = "";
char * psz_bind_addr = "";
char * psz_bind_port = "";
int i_bind_port = 0, i_server_port = 0;
network_socket_t socket_desc;
if( config_GetInt( p_input, "ipv4" ) )
{
psz_network = "ipv4";
}
if( config_GetInt( p_input, "ipv6" ) )
{
psz_network = "ipv6";
}
if( *p_input->psz_access )
{
/* 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 != '@' )
{
if( *psz_parser == '[' )
{
/* IPv6 address */
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 != ':' )
{
if( *psz_parser == '[' )
{
/* IPv6 address */
while( *psz_parser && *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 )
{
i_server_port = strtol( psz_server_port, &psz_parser, 10 );
if( *psz_parser )
{
msg_Err( p_input, "cannot parse server port near %s", psz_parser );
free(psz_name);
return( -1 );
}
}
if( *psz_bind_port )
{
i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
if( *psz_parser )
{
msg_Err( p_input, "cannot parse bind port near %s", psz_parser );
free(psz_name);
return( -1 );
}
}
p_input->pf_read = input_FDNetworkRead;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
p_input->pf_seek = NULL;
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 );
if( *psz_server_addr || i_server_port )
{
msg_Err( p_input, "this UDP syntax is deprecated; the server argument will be");
msg_Err( p_input, "ignored (%s:%d). If you wanted to enter a multicast address",
psz_server_addr, i_server_port);
msg_Err( p_input, "or local port, type : %s:@%s:%d",
*p_input->psz_access ? p_input->psz_access : "udp",
psz_server_addr, i_server_port );
i_server_port = 0;
psz_server_addr = "";
}
msg_Dbg( p_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_input->p_private = (void*) &socket_desc;
p_network = module_Need( p_input, "network", psz_network );
free(psz_name);
if( p_network == NULL )
{
return( -1 );
}
module_Unneed( p_input, p_network );
p_access_data = p_input->p_access_data = malloc( sizeof(input_socket_t) );
if( p_access_data == NULL )
{
msg_Err( p_input, "out of memory" );
return( -1 );
}
p_access_data->i_handle = socket_desc.i_handle;
p_input->i_mtu = socket_desc.i_mtu;
return( 0 );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
vcd_SOURCES = vcd.c cdrom.c

486
modules/access/vcd/cdrom.c Normal file
View File

@ -0,0 +1,486 @@
/****************************************************************************
* cdrom.c: cdrom tools
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: cdrom.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Johan Bilien <jobi@via.ecp.fr>
* Jon Lech Johansen <jon-vl@nanocrew.net>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#if defined( SYS_BSDI )
# include <dvd.h>
#elif defined ( SYS_DARWIN )
# include <CoreFoundation/CFBase.h>
# include <IOKit/IOKitLib.h>
# include <IOKit/storage/IOCDTypes.h>
# include <IOKit/storage/IOCDMedia.h>
# include <IOKit/storage/IOCDMediaBSDClient.h>
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
# include <sys/cdio.h>
# include <sys/cdrio.h>
#else
# include <linux/cdrom.h>
#endif
#include "cdrom.h"
/*****************************************************************************
* Platform specific
*****************************************************************************/
#if defined( SYS_DARWIN )
CDTOC *getTOC( const char * );
#define freeTOC( p ) free( (void*)p )
int getNumberOfDescriptors( CDTOC * );
int getNumberOfTracks( CDTOC *, int );
#define CD_MIN_TRACK_NO 01
#define CD_MAX_TRACK_NO 99
#endif
/*****************************************************************************
* ioctl_ReadTocHeader: Read the TOC header and return the track number.
*****************************************************************************/
int ioctl_GetTrackCount( int i_fd, const char *psz_dev )
{
int i_count = -1;
#if defined( SYS_DARWIN )
CDTOC *pTOC;
int i_descriptors;
if( ( pTOC = getTOC( psz_dev ) ) == NULL )
{
//X intf_ErrMsg( "vcd error: failed to get the TOC" );
return( -1 );
}
i_descriptors = getNumberOfDescriptors( pTOC );
i_count = getNumberOfTracks( pTOC, i_descriptors );
freeTOC( pTOC );
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
struct ioc_toc_header tochdr;
if( ioctl( i_fd, CDIOREADTOCHEADER, &tochdr ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read TOCHDR" );
return -1;
}
i_count = tochdr.ending_track - tochdr.starting_track + 1;
#else
struct cdrom_tochdr tochdr;
/* First we read the TOC header */
if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read TOCHDR" );
return -1;
}
i_count = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
#endif
return( i_count );
}
/*****************************************************************************
* ioctl_GetSectors: Read the Table of Contents and fill p_vcd.
*****************************************************************************/
int * ioctl_GetSectors( int i_fd, const char *psz_dev )
{
int i, i_tracks;
int *p_sectors = NULL;
#if defined( SYS_DARWIN )
CDTOC *pTOC;
u_char track;
int i_descriptors;
int i_leadout = -1;
CDTOCDescriptor *pTrackDescriptors;
if( ( pTOC = getTOC( psz_dev ) ) == NULL )
{
//X intf_ErrMsg( "vcd error: failed to get the TOC" );
return( NULL );
}
i_descriptors = getNumberOfDescriptors( pTOC );
i_tracks = getNumberOfTracks( pTOC, i_descriptors );
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
//X intf_ErrMsg( "vcd error: could not allocate p_sectors" );
freeTOC( pTOC );
return NULL;
}
pTrackDescriptors = pTOC->descriptors;
for( i_tracks = 0, i = 0; i <= i_descriptors; i++ )
{
track = pTrackDescriptors[i].point;
if( track == 0xA2 )
i_leadout = i;
if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
continue;
p_sectors[i_tracks++] =
CDConvertMSFToLBA( pTrackDescriptors[i].p );
}
if( i_leadout == -1 )
{
//X intf_ErrMsg( "vcd error: leadout not found" );
free( p_sectors );
freeTOC( pTOC );
return( NULL );
}
/* set leadout sector */
p_sectors[i_tracks] =
CDConvertMSFToLBA( pTrackDescriptors[i_leadout].p );
freeTOC( pTOC );
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
struct ioc_read_toc_entry toc_entries;
i_tracks = ioctl_GetTrackCount( i_fd, psz_dev );
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
//X intf_ErrMsg( "vcd error: could not allocate p_sectors" );
return NULL;
}
toc_entries.address_format = CD_LBA_FORMAT;
toc_entries.starting_track = 0;
toc_entries.data_len = ( i_tracks + 1 ) * sizeof( struct cd_toc_entry );
toc_entries.data = (struct cd_toc_entry *) malloc( toc_entries.data_len );
if( toc_entries.data == NULL )
{
//X intf_ErrMsg( "vcd error: not enoug memory" );
free( p_sectors );
return NULL;
}
/* Read the TOC */
if( ioctl( i_fd, CDIOREADTOCENTRYS, &toc_entries ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read the TOC" );
free( p_sectors );
free( toc_entries.data );
return NULL;
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
p_sectors[ i ] = ntohl( toc_entries.data[i].addr.lba );
}
#else
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent;
/* First we read the TOC header */
if( ioctl( i_fd, CDROMREADTOCHDR, &tochdr ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read TOCHDR" );
return NULL;
}
i_tracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
p_sectors = malloc( (i_tracks + 1) * sizeof(int) );
if( p_sectors == NULL )
{
//X intf_ErrMsg( "vcd error: could not allocate p_sectors" );
return NULL;
}
/* Fill the p_sectors structure with the track/sector matches */
for( i = 0 ; i <= i_tracks ; i++ )
{
tocent.cdte_format = CDROM_LBA;
tocent.cdte_track =
( i == i_tracks ) ? CDROM_LEADOUT : tochdr.cdth_trk0 + i;
if( ioctl( i_fd, CDROMREADTOCENTRY, &tocent ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read TOCENTRY" );
free( p_sectors );
return NULL;
}
p_sectors[ i ] = tocent.cdte_addr.lba;
}
#endif
return p_sectors;
}
/****************************************************************************
* ioctl_ReadSector: Read a sector (2324 bytes)
****************************************************************************/
int ioctl_ReadSector( int i_fd, int i_sector, byte_t * p_buffer )
{
byte_t p_block[ VCD_SECTOR_SIZE ];
#if defined( SYS_DARWIN )
dk_cd_read_t cd_read;
memset( &cd_read, 0, sizeof(cd_read) );
cd_read.offset = i_sector * VCD_SECTOR_SIZE;
cd_read.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader |
kCDSectorAreaSubHeader | kCDSectorAreaUser |
kCDSectorAreaAuxiliary;
cd_read.sectorType = kCDSectorTypeUnknown;
cd_read.buffer = p_block;
cd_read.bufferLength = sizeof(p_block);
if( ioctl( i_fd, DKIOCCDREAD, &cd_read ) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read block %d", i_sector );
return( -1 );
}
#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H )
int i_size = VCD_SECTOR_SIZE;
if( ioctl( i_fd, CDRIOCSETBLOCKSIZE, &i_size ) == -1 )
{
//X intf_ErrMsg( "vcd error: Could not set block size" );
return( -1 );
}
if( lseek( i_fd, i_sector * VCD_SECTOR_SIZE, SEEK_SET ) == -1 )
{
//X intf_ErrMsg( "vcd error: Could not lseek to sector %d", i_sector );
return( -1 );
}
if( read( i_fd, p_block, VCD_SECTOR_SIZE ) == -1 )
{
//X intf_ErrMsg( "vcd error: Could not read sector %d", i_sector );
return( -1 );
}
#else
int i_dummy = i_sector + 2 * CD_FRAMES;
#define p_msf ((struct cdrom_msf0 *)p_block)
p_msf->minute = i_dummy / (CD_FRAMES * CD_SECS);
p_msf->second = ( i_dummy % (CD_FRAMES * CD_SECS) ) / CD_FRAMES;
p_msf->frame = ( i_dummy % (CD_FRAMES * CD_SECS) ) % CD_FRAMES;
#undef p_msf
if( ioctl(i_fd, CDROMREADRAW, p_block) == -1 )
{
//X intf_ErrMsg( "vcd error: could not read block %i from disc",
//X i_sector );
return( -1 );
}
#endif
/* We don't want to keep the header of the read sector */
memcpy( p_buffer, p_block + VCD_DATA_START, VCD_DATA_SIZE );
return( 0 );
}
#if defined( SYS_DARWIN )
/****************************************************************************
* getTOC: get the TOC
****************************************************************************/
CDTOC *getTOC( const char *psz_dev )
{
mach_port_t port;
char *psz_devname;
kern_return_t ret;
CDTOC *pTOC = NULL;
io_iterator_t iterator;
io_registry_entry_t service;
CFDictionaryRef properties;
CFDataRef data;
if( psz_dev == NULL )
{
//X intf_ErrMsg( "vcd error: invalid device path" );
return( NULL );
}
/* get the device name */
if( ( psz_devname = strrchr( psz_dev, '/') ) != NULL )
++psz_devname;
else
psz_devname = (char *)psz_dev;
/* unraw the device name */
if( *psz_devname == 'r' )
++psz_devname;
/* get port for IOKit communication */
if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS )
{
//X intf_ErrMsg( "vcd error: IOMasterPort: 0x%08x", ret );
return( NULL );
}
/* get service iterator for the device */
if( ( ret = IOServiceGetMatchingServices(
port, IOBSDNameMatching( port, 0, psz_devname ),
&iterator ) ) != KERN_SUCCESS )
{
//X intf_ErrMsg( "vcd error: IOServiceGetMatchingServices: 0x%08x", ret );
return( NULL );
}
/* first service */
service = IOIteratorNext( iterator );
IOObjectRelease( iterator );
/* search for kIOCDMediaClass */
while( service && !IOObjectConformsTo( service, kIOCDMediaClass ) )
{
if( ( ret = IORegistryEntryGetParentIterator( service,
kIOServicePlane, &iterator ) ) != KERN_SUCCESS )
{
//X intf_ErrMsg( "vcd error: "
//X "IORegistryEntryGetParentIterator: 0x%08x", ret );
IOObjectRelease( service );
return( NULL );
}
IOObjectRelease( service );
service = IOIteratorNext( iterator );
IOObjectRelease( iterator );
}
if( service == NULL )
{
//X intf_ErrMsg( "vcd error: search for kIOCDMediaClass came up empty" );
return( NULL );
}
/* create a CF dictionary containing the TOC */
if( ( ret = IORegistryEntryCreateCFProperties( service, &properties,
kCFAllocatorDefault, kNilOptions ) ) != KERN_SUCCESS )
{
//X intf_ErrMsg( "vcd error: "
//X " IORegistryEntryCreateCFProperties: 0x%08x", ret );
IOObjectRelease( service );
return( NULL );
}
/* get the TOC from the dictionary */
if( ( data = (CFDataRef) CFDictionaryGetValue( properties,
CFSTR(kIOCDMediaTOCKey) ) ) != NULL )
{
CFRange range;
CFIndex buf_len;
buf_len = CFDataGetLength( data ) + 1;
range = CFRangeMake( 0, buf_len );
if( ( pTOC = (CDTOC *)malloc( buf_len ) ) != NULL )
{
CFDataGetBytes( data, range, (u_char *)pTOC );
}
}
else
{
//X intf_ErrMsg( "vcd error: CFDictionaryGetValue failed" );
}
CFRelease( properties );
IOObjectRelease( service );
return( pTOC );
}
/****************************************************************************
* getNumberOfDescriptors: get number of descriptors in TOC
****************************************************************************/
int getNumberOfDescriptors( CDTOC *pTOC )
{
int i_descriptors;
/* get TOC length */
i_descriptors = pTOC->length;
/* remove the first and last session */
i_descriptors -= ( sizeof(pTOC->sessionFirst) +
sizeof(pTOC->sessionLast) );
/* divide the length by the size of a single descriptor */
i_descriptors /= sizeof(CDTOCDescriptor);
return( i_descriptors );
}
/****************************************************************************
* getNumberOfTracks: get number of tracks in TOC
****************************************************************************/
int getNumberOfTracks( CDTOC *pTOC, int i_descriptors )
{
u_char track;
int i, i_tracks = 0;
CDTOCDescriptor *pTrackDescriptors;
pTrackDescriptors = pTOC->descriptors;
for( i = i_descriptors; i >= 0; i-- )
{
track = pTrackDescriptors[i].point;
if( track > CD_MAX_TRACK_NO || track < CD_MIN_TRACK_NO )
continue;
i_tracks++;
}
return( i_tracks );
}
#endif

View File

@ -0,0 +1,37 @@
/****************************************************************************
* cdrom.h: cdrom tools header
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: cdrom.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Johan Bilien <jobi@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.
*****************************************************************************/
/* where the data start on a VCD sector */
#define VCD_DATA_START 24
/* size of the availablr data on a VCD sector */
#define VCD_DATA_SIZE 2324
/* size of a VCD sector, header and tail included */
#define VCD_SECTOR_SIZE 2352
/******************************************************************************
* Prototypes *
******************************************************************************/
int ioctl_GetTrackCount ( int, const char *psz_dev );
int * ioctl_GetSectors ( int, const char *psz_dev );
int ioctl_ReadSector ( int, int, byte_t * );

409
modules/access/vcd/vcd.c Normal file
View File

@ -0,0 +1,409 @@
/*****************************************************************************
* vcd.c : VCD input module for vlc
*****************************************************************************
* Copyright (C) 2000 VideoLAN
* $Id: vcd.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Johan Bilien <jobi@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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.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 "vcd.h"
#include "cdrom.h"
/* how many blocks VCDRead will read in each loop */
#define VCD_BLOCKS_ONCE 20
#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * VCD_DATA_SIZE)
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int VCDOpen ( vlc_object_t * );
static void VCDClose ( vlc_object_t * );
static int VCDRead ( input_thread_t *, byte_t *, size_t );
static void VCDSeek ( input_thread_t *, off_t );
static int VCDSetArea ( input_thread_t *, input_area_t * );
static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
/*****************************************************************************
* Module descriptior
*****************************************************************************/
vlc_module_begin();
set_description( _("VCD input module") );
set_capability( "access", 80 );
set_callbacks( VCDOpen, VCDClose );
add_shortcut( "svcd" );
vlc_module_end();
/*
* Data reading functions
*/
/*****************************************************************************
* VCDOpen: open vcd
*****************************************************************************/
static int VCDOpen( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_orig;
char * psz_parser;
char * psz_source;
char * psz_next;
struct stat stat_info;
thread_vcd_data_t * p_vcd;
int i;
input_area_t * p_area;
int i_title = 1;
int i_chapter = 1;
p_input->pf_read = VCDRead;
p_input->pf_seek = VCDSeek;
p_input->pf_set_area = VCDSetArea;
p_input->pf_set_program = VCDSetProgram;
/* parse the options passed in command line : */
psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
if( !psz_orig )
{
return( -1 );
}
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* Found options */
*psz_parser = '\0';
++psz_parser;
i_title = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
}
i_title = i_title ? i_title : 1;
i_chapter = i_chapter ? i_chapter : 1;
}
if( !*psz_source )
{
if( !p_input->psz_access )
{
free( psz_orig );
return -1;
}
psz_source = config_GetPsz( p_input, "vcd" );
}
/* test the type of file given */
if( stat( psz_source, &stat_info ) == -1 )
{
msg_Err( p_input, "cannot stat() source `%s' (%s)",
psz_source, strerror(errno));
return( -1 );
}
if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode))
{
msg_Warn( p_input, "vcd module discarded (not a valid drive)" );
return -1;
}
p_vcd = malloc( sizeof(thread_vcd_data_t) );
if( p_vcd == NULL )
{
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_vcd;
p_input->i_mtu = VCD_DATA_ONCE;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 1;
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 );
p_vcd->i_handle = open( psz_source, O_RDONLY | O_NONBLOCK );
if( p_vcd->i_handle == -1 )
{
msg_Err( p_input, "could not open %s\n", psz_source );
free (p_vcd);
return -1;
}
/* We read the Table Of Content information */
p_vcd->nb_tracks = ioctl_GetTrackCount( p_vcd->i_handle,
psz_source );
if( p_vcd->nb_tracks < 0 )
{
msg_Err( p_input, "unable to count tracks" );
close( p_vcd->i_handle );
free( p_vcd );
return -1;
}
else if( p_vcd->nb_tracks <= 1 )
{
msg_Err( p_input, "no movie tracks found" );
close( p_vcd->i_handle );
free( p_vcd );
return -1;
}
p_vcd->p_sectors = ioctl_GetSectors( p_vcd->i_handle,
psz_source );
if( p_vcd->p_sectors == NULL )
{
input_BuffersEnd( p_input, p_input->p_method_data );
close( p_vcd->i_handle );
free( p_vcd );
return -1;
}
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
/* disc input method */
p_input->stream.i_method = INPUT_METHOD_VCD;
#define area p_input->stream.pp_areas
for( i = 1 ; i <= p_vcd->nb_tracks - 1 ; i++ )
{
input_AddArea( p_input );
/* Titles are Program Chains */
area[i]->i_id = i;
/* Absolute start offset and size */
area[i]->i_start = (off_t)p_vcd->p_sectors[i] * (off_t)VCD_DATA_SIZE;
area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
* (off_t)VCD_DATA_SIZE;
/* Number of chapters */
area[i]->i_part_nb = 0; // will be the entry points
area[i]->i_part = 1;
area[i]->i_plugin_data = p_vcd->p_sectors[i];
}
#undef area
p_area = p_input->stream.pp_areas[i_title];
VCDSetArea( p_input, p_area );
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->psz_demux = "ps";
return 0;
}
/*****************************************************************************
* VCDClose: closes vcd
*****************************************************************************/
static void VCDClose( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
close( p_vcd->i_handle );
free( p_vcd );
}
/*****************************************************************************
* VCDRead: reads from the VCD into PES packets.
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* bytes.
*****************************************************************************/
static int VCDRead( input_thread_t * p_input, byte_t * p_buffer,
size_t i_len )
{
thread_vcd_data_t * p_vcd;
int i_blocks;
int i_index;
int i_read;
byte_t p_last_sector[ VCD_DATA_SIZE ];
p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
i_read = 0;
/* Compute the number of blocks we have to read */
i_blocks = i_len / VCD_DATA_SIZE;
for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
{
if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector,
p_buffer + i_index * VCD_DATA_SIZE ) < 0 )
{
msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
return -1;
}
p_vcd->i_sector ++;
if ( p_vcd->i_sector == p_vcd->p_sectors[p_vcd->i_track + 1] )
{
input_area_t *p_area;
if ( p_vcd->i_track >= p_vcd->nb_tracks - 1 )
return 0; /* EOF */
p_area = p_input->stream.pp_areas[
p_input->stream.p_selected_area->i_id + 1 ];
msg_Dbg( p_input, "new title" );
p_area->i_part = 1;
VCDSetArea( p_input, p_area );
}
i_read += VCD_DATA_SIZE;
}
if ( i_len % VCD_DATA_SIZE ) /* this should not happen */
{
if ( ioctl_ReadSector( p_vcd->i_handle, p_vcd->i_sector,
p_last_sector ) < 0 )
{
msg_Err( p_input, "could not read sector %d", p_vcd->i_sector );
return -1;
}
p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * VCD_DATA_SIZE,
p_last_sector, i_len % VCD_DATA_SIZE );
i_read += i_len % VCD_DATA_SIZE;
}
p_input->stream.p_selected_area->i_tell =
(off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE
- p_input->stream.p_selected_area->i_start;
return i_read;
}
/*****************************************************************************
* VCDSetProgram: Does nothing since a VCD is mono_program
*****************************************************************************/
static int VCDSetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program)
{
return 0;
}
/*****************************************************************************
* VCDSetArea: initialize input data for title x, chapter y.
* It should be called for each user navigation request.
****************************************************************************/
static int VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
{
thread_vcd_data_t * p_vcd;
p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
/* we can't use the interface slider until initilization is complete */
p_input->stream.b_seekable = 0;
if( p_area != p_input->stream.p_selected_area )
{
/* Reset the Chapter position of the current title */
p_input->stream.p_selected_area->i_part = 1;
p_input->stream.p_selected_area->i_tell = 0;
/* Change the default area */
p_input->stream.p_selected_area = p_area;
/* Change the current track */
/* The first track is not a valid one */
p_vcd->i_track = p_area->i_id;
p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track];
}
/* warn interface that something has changed */
p_input->stream.b_seekable = 1;
p_input->stream.b_changed = 1;
return 0;
}
/****************************************************************************
* VCDSeek
****************************************************************************/
static void VCDSeek( input_thread_t * p_input, off_t i_off )
{
thread_vcd_data_t * p_vcd;
p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
p_vcd->i_sector = p_vcd->p_sectors[p_vcd->i_track]
+ i_off / (off_t)VCD_DATA_SIZE;
p_input->stream.p_selected_area->i_tell =
(off_t)p_vcd->i_sector * (off_t)VCD_DATA_SIZE
- p_input->stream.p_selected_area->i_start;
}

37
modules/access/vcd/vcd.h Normal file
View File

@ -0,0 +1,37 @@
/*****************************************************************************
* vcd.h: thread structure of the VCD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: vcd.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Johan Bilien <jobi@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.
*****************************************************************************/
/*****************************************************************************
* thread_vcd_data_t: VCD information
*****************************************************************************/
typedef struct thread_vcd_data_s
{
int i_handle; /* File descriptor */
int nb_tracks; /* Nb of tracks (titles) */
int i_track; /* Current track */
int i_sector; /* Current Sector */
int * p_sectors; /* Track sectors */
vlc_bool_t b_end_of_track; /* If the end of track was reached */
} thread_vcd_data_t;

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
alsa_SOURCES = alsa.c

View File

@ -0,0 +1,420 @@
/*****************************************************************************
* alsa.c : alsa plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: alsa.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Henri Fallon <henri@videolan.org> - Original Author
* Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
* John Paul Lorenti <jpl31@columbia.edu> - Device selection
*
* 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 <errno.h> /* ENOMEM */
#include <string.h> /* strerror() */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <alsa/asoundlib.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * );
static int GetBufInfo ( aout_thread_t *, int );
static void Play ( aout_thread_t *, byte_t *, int );
static void HandleXrun ( aout_thread_t *);
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( N_("Device"), NULL );
add_string( "alsa-device", NULL, NULL, N_("Name"), NULL );
set_description( _("ALSA audio module") );
set_capability( "audio output", 50 );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* Preamble
*****************************************************************************/
typedef struct alsa_device_t
{
int i_num;
} alsa_device_t;
typedef struct alsa_card_t
{
int i_num;
} alsa_card_t;
/* here we store plugin dependant informations */
struct aout_sys_t
{
snd_pcm_t * p_alsa_handle;
unsigned long buffer_time;
unsigned long period_time;
unsigned long chunk_size;
unsigned long buffer_size;
unsigned long rate;
unsigned int bytes_per_sample;
unsigned int samples_per_frame;
unsigned int bytes_per_frame;
};
/*****************************************************************************
* Open: create a handle and open an alsa device
*****************************************************************************
* This function opens an alsa device, through the alsa API
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
/* Allows user to choose which ALSA device to use */
char psz_alsadev[128];
char *psz_device, *psz_userdev;
int i_ret;
/* Allocate structures */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return -1;
}
p_aout->pf_setformat = SetFormat;
p_aout->pf_getbufinfo = GetBufInfo;
p_aout->pf_play = Play;
/* Read in ALSA device preferences from configuration */
psz_userdev = config_GetPsz( p_aout, "alsa-device" );
if( psz_userdev )
{
psz_device = psz_userdev;
}
else
{
/* Use the internal logic to decide on the device name */
if( p_aout->i_format != AOUT_FMT_A52 )
{
psz_device = "default";
}
else
{
unsigned char s[4];
s[0] = IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO;
s[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER;
s[2] = 0;
s[3] = IEC958_AES3_CON_FS_48000;
sprintf( psz_alsadev,
"iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
s[0], s[1], s[2], s[3] );
psz_device = psz_alsadev;
}
}
/* Open device */
i_ret = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle),
psz_device, SND_PCM_STREAM_PLAYBACK, 0);
if( i_ret != 0 )
{
msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
psz_device, snd_strerror(i_ret) );
if( psz_userdev )
{
free( psz_userdev );
}
return -1;
}
if( psz_userdev )
{
free( psz_userdev );
}
return 0;
}
/*****************************************************************************
* SetFormat : sets the alsa output format
*****************************************************************************
* This function prepares the device, sets the rate, format, the mode
* ( "play as soon as you have data" ), and buffer information.
*****************************************************************************/
static int SetFormat( aout_thread_t *p_aout )
{
int i_rv;
int i_format;
snd_pcm_hw_params_t *p_hw;
snd_pcm_sw_params_t *p_sw;
snd_pcm_hw_params_alloca(&p_hw);
snd_pcm_sw_params_alloca(&p_sw);
/* default value for snd_pcm_hw_params_set_buffer_time_near() */
p_aout->p_sys->buffer_time = AOUT_BUFFER_DURATION;
switch (p_aout->i_format)
{
case AOUT_FMT_S16_LE:
i_format = SND_PCM_FORMAT_S16_LE;
p_aout->p_sys->bytes_per_sample = 2;
break;
case AOUT_FMT_A52:
i_format = SND_PCM_FORMAT_S16_LE;
p_aout->p_sys->bytes_per_sample = 2;
/* buffer_time must be 500000 to avoid a system crash */
p_aout->p_sys->buffer_time = 500000;
break;
default:
i_format = SND_PCM_FORMAT_S16_BE;
p_aout->p_sys->bytes_per_sample = 2;
break;
}
p_aout->p_sys->samples_per_frame = p_aout->i_channels;
p_aout->p_sys->bytes_per_frame = p_aout->p_sys->samples_per_frame *
p_aout->p_sys->bytes_per_sample;
i_rv = snd_pcm_hw_params_any( p_aout->p_sys->p_alsa_handle, p_hw );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to retrieve initial parameters" );
return -1;
}
i_rv = snd_pcm_hw_params_set_access( p_aout->p_sys->p_alsa_handle, p_hw,
SND_PCM_ACCESS_RW_INTERLEAVED );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set interleaved stream format" );
return -1;
}
i_rv = snd_pcm_hw_params_set_format( p_aout->p_sys->p_alsa_handle,
p_hw, i_format );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set stream sample size and word order" );
return -1;
}
i_rv = snd_pcm_hw_params_set_channels( p_aout->p_sys->p_alsa_handle, p_hw,
p_aout->i_channels );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set number of output channels" );
return -1;
}
i_rv = snd_pcm_hw_params_set_rate_near( p_aout->p_sys->p_alsa_handle, p_hw,
p_aout->i_rate, 0 );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set sample rate" );
return -1;
}
p_aout->p_sys->rate = i_rv;
i_rv = snd_pcm_hw_params_set_buffer_time_near( p_aout->p_sys->p_alsa_handle,
p_hw,
p_aout->p_sys->buffer_time,
0 );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set buffer time" );
return -1;
}
p_aout->p_sys->buffer_time = i_rv;
i_rv = snd_pcm_hw_params_set_period_time_near( p_aout->p_sys->p_alsa_handle,
p_hw, p_aout->p_sys->buffer_time / p_aout->p_sys->bytes_per_frame, 0 );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set period time" );
return -1;
}
p_aout->p_sys->period_time = i_rv;
i_rv = snd_pcm_hw_params(p_aout->p_sys->p_alsa_handle, p_hw);
if (i_rv < 0)
{
msg_Err( p_aout, "unable to set hardware configuration" );
return -1;
}
p_aout->p_sys->chunk_size = snd_pcm_hw_params_get_period_size( p_hw, 0 );
p_aout->p_sys->buffer_size = snd_pcm_hw_params_get_buffer_size( p_hw );
snd_pcm_sw_params_current( p_aout->p_sys->p_alsa_handle, p_sw );
i_rv = snd_pcm_sw_params_set_sleep_min( p_aout->p_sys->p_alsa_handle, p_sw,
0 );
i_rv = snd_pcm_sw_params_set_avail_min( p_aout->p_sys->p_alsa_handle, p_sw,
p_aout->p_sys->chunk_size );
/* Worked with the CVS version but not with 0.9beta3
i_rv = snd_pcm_sw_params_set_start_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size );
i_rv = snd_pcm_sw_params_set_stop_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size);
*/
i_rv = snd_pcm_sw_params( p_aout->p_sys->p_alsa_handle, p_sw );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to set software configuration" );
return -1;
}
return 0;
}
/*****************************************************************************
* HandleXrun : reprepare the output
*****************************************************************************
* When buffer gets empty, the driver goes in "Xrun" state, where it needs
* to be reprepared before playing again
*****************************************************************************/
static void HandleXrun(aout_thread_t *p_aout)
{
int i_rv;
msg_Err( p_aout, "resetting output after buffer underrun" );
// i_rv = snd_pcm_reset( p_aout->p_sys->p_alsa_handle );
i_rv = snd_pcm_prepare( p_aout->p_sys->p_alsa_handle );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to recover from buffer underrun (%s)",
snd_strerror( i_rv ) );
}
}
/*****************************************************************************
* BufInfo: buffer status query
*****************************************************************************
* This function returns the number of used byte in the queue.
* It also deals with errors : indeed if the device comes to run out
* of data to play, it switches to the "underrun" status. It has to
* be flushed and re-prepared
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
{
snd_pcm_status_t *p_status;
int i_alsa_get_status_returns;
snd_pcm_status_alloca( &p_status );
i_alsa_get_status_returns = snd_pcm_status( p_aout->p_sys->p_alsa_handle,
p_status );
if( i_alsa_get_status_returns )
{
msg_Err( p_aout, "failed getting alsa buffer info (%s)",
snd_strerror ( i_alsa_get_status_returns ) );
return ( -1 );
}
switch( snd_pcm_status_get_state( p_status ) )
{
case SND_PCM_STATE_XRUN :
HandleXrun( p_aout );
break;
case SND_PCM_STATE_OPEN:
case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_RUNNING:
break;
default:
msg_Err( p_aout, "unhandled condition %i",
snd_pcm_status_get_state( p_status ) );
break;
}
return snd_pcm_status_get_avail(p_status) * p_aout->p_sys->bytes_per_frame;
}
/*****************************************************************************
* Play : plays a sample
*****************************************************************************
* Plays a sample using the snd_pcm_writei function from the alsa API
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
snd_pcm_uframes_t tot_frames;
snd_pcm_uframes_t frames_left;
snd_pcm_uframes_t rv;
tot_frames = i_size / p_aout->p_sys->bytes_per_frame;
frames_left = tot_frames;
while( frames_left > 0 )
{
rv = snd_pcm_writei( p_aout->p_sys->p_alsa_handle, buffer +
(tot_frames - frames_left) *
p_aout->p_sys->bytes_per_frame, frames_left );
if( (signed int) rv < 0 )
{
msg_Err( p_aout, "failed writing to output (%s)",
snd_strerror( rv ) );
return;
}
frames_left -= rv;
}
}
/*****************************************************************************
* Close: close the Alsa device
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i_close_returns;
i_close_returns = snd_pcm_close( p_aout->p_sys->p_alsa_handle );
if( i_close_returns )
{
msg_Err( p_aout, "failed closing ALSA device (%s)",
snd_strerror( i_close_returns ) );
}
free( p_aout->p_sys );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
arts_SOURCES = arts.c

View File

@ -0,0 +1,150 @@
/*****************************************************************************
* arts.c : aRts module
*****************************************************************************
* Copyright (C) 2001 VideoLAN
*
* Authors: Emmanuel Blindauer <manu@agat.net>
*
* 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 <errno.h> /* ENOMEM */
#include <fcntl.h> /* open(), O_WRONLY */
#include <string.h> /* strerror() */
#include <unistd.h> /* write(), close() */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <artsc.h>
/*****************************************************************************
* aout_sys_t: arts audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes some arts specific variables.
*****************************************************************************/
struct aout_sys_t
{
arts_stream_t stream;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * );
static int GetBufInfo ( aout_thread_t *, int );
static void Play ( aout_thread_t *, byte_t *, int );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("aRts audio module") );
set_capability( "audio output", 50 );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* Open: initialize arts connection to server
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i_err = 0;
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return( 1 );
}
i_err = arts_init();
if (i_err < 0)
{
msg_Err( p_aout, "arts_init failed (%s)", arts_error_text(i_err) );
free( p_aout->p_sys );
return(-1);
}
p_aout->pf_setformat = SetFormat;
p_aout->pf_getbufinfo = GetBufInfo;
p_aout->pf_play = Play;
p_aout->p_sys->stream =
arts_play_stream( p_aout->i_rate, 16, p_aout->i_channels, "vlc" );
return( 0 );
}
/*****************************************************************************
* SetFormat: set the output format
*****************************************************************************/
static int SetFormat( aout_thread_t *p_aout )
{
/*Not ready*/
/* p_aout->i_latency = esd_get_latency(i_fd);*/
p_aout->i_latency = 0;
//msg_Dbg( p_aout, "aout_arts_latency: %d", p_aout->i_latency );
return( 0 );
}
/*****************************************************************************
* GetBufInfo: buffer status query
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
{
/* arbitrary value that should be changed */
return( i_buffer_limit );
}
/*****************************************************************************
* Play: play a sound samples buffer
*****************************************************************************
* This function writes a buffer of i_length bytes in the socket
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
int i_err = arts_write( p_aout->p_sys->stream, buffer, i_size );
if( i_err < 0 )
{
msg_Err( p_aout, "arts_write failed (%s)", arts_error_text(i_err) );
}
}
/*****************************************************************************
* Close: close the Esound socket
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
arts_close_stream( p_aout->p_sys->stream );
free( p_aout->p_sys );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
dsp_SOURCES = dsp.c

View File

@ -0,0 +1,247 @@
/*****************************************************************************
* dsp.c : OSS /dev/dsp module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: dsp.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Samuel Hocevar <sam@zoy.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 <errno.h> /* ENOMEM */
#include <fcntl.h> /* open(), O_WRONLY */
#include <sys/ioctl.h> /* ioctl() */
#include <string.h> /* strerror() */
#include <unistd.h> /* write(), close() */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
/* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
* SNDCTL_DSP_GETOSPACE */
#ifdef HAVE_SOUNDCARD_H
# include <soundcard.h>
#elif defined( HAVE_SYS_SOUNDCARD_H )
# include <sys/soundcard.h>
#elif defined( HAVE_MACHINE_SOUNDCARD_H )
# include <machine/soundcard.h>
#endif
/*****************************************************************************
* aout_sys_t: dsp audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the dsp specific properties of an audio device.
*****************************************************************************/
struct aout_sys_t
{
audio_buf_info audio_buf;
/* Path to the audio output device */
char * psz_device;
int i_fd;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * );
static int GetBufInfo ( aout_thread_t *, int );
static void Play ( aout_thread_t *, byte_t *, int );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( N_("Miscellaneous"), NULL );
add_file( "dspdev", "/dev/dsp", NULL, N_("OSS dsp device"), NULL );
set_description( _("Linux OSS /dev/dsp module") );
set_capability( "audio output", 100 );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* Open: opens the audio device (the digital sound processor)
*****************************************************************************
* This function opens the dsp as a usual non-blocking write-only file, and
* modifies the p_aout->p_sys->i_fd with the file's descriptor.
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return( 1 );
}
/* Initialize some variables */
if( !(p_aout->p_sys->psz_device = config_GetPsz( p_aout, "dspdev" )) )
{
msg_Err( p_aout, "don't know which audio device to open" );
free( p_aout->p_sys );
return( -1 );
}
p_aout->pf_setformat = SetFormat;
p_aout->pf_getbufinfo = GetBufInfo;
p_aout->pf_play = Play;
/* Open the sound device */
if( (p_aout->p_sys->i_fd = open( p_aout->p_sys->psz_device, O_WRONLY ))
< 0 )
{
msg_Err( p_aout, "cannot open audio device (%s)",
p_aout->p_sys->psz_device );
free( p_aout->p_sys->psz_device );
free( p_aout->p_sys );
return( -1 );
}
return( 0 );
}
/*****************************************************************************
* SetFormat: resets the dsp and sets its format
*****************************************************************************
* This functions resets the DSP device, tries to initialize the output
* format with the value contained in the dsp structure, and if this value
* could not be set, the default value returned by ioctl is set. It then
* does the same for the stereo mode, and for the output rate.
*****************************************************************************/
static int SetFormat( aout_thread_t *p_aout )
{
int i_format;
int i_rate;
vlc_bool_t b_stereo;
/* Reset the DSP device */
if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
{
msg_Err( p_aout, "cannot reset audio device (%s)",
p_aout->p_sys->psz_device );
return( -1 );
}
/* Set the output format */
i_format = p_aout->i_format;
if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
{
msg_Err( p_aout, "cannot set audio output format (%i)",
p_aout->i_format );
return( -1 );
}
if( i_format != p_aout->i_format )
{
msg_Warn( p_aout, "audio output format not supported (%i)",
p_aout->i_format );
p_aout->i_format = i_format;
}
/* Set the number of channels */
b_stereo = ( p_aout->i_channels >= 2 );
if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_STEREO, &b_stereo ) < 0 )
{
msg_Err( p_aout, "cannot set number of audio channels (%i)",
p_aout->i_channels );
return( -1 );
}
if( (1 + b_stereo) != p_aout->i_channels )
{
msg_Warn( p_aout, "%i audio channels not supported",
p_aout->i_channels );
p_aout->i_channels = 1 + b_stereo;
}
/* Set the output rate */
i_rate = p_aout->i_rate;
if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
{
msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->i_rate );
return( -1 );
}
if( i_rate != p_aout->i_rate )
{
msg_Warn( p_aout, "audio output rate not supported (%li)",
p_aout->i_rate );
p_aout->i_rate = i_rate;
}
return( 0 );
}
/*****************************************************************************
* GetBufInfo: buffer status query
*****************************************************************************
* This function fills in the audio_buf_info structure :
* - returns : number of available fragments (not partially used ones)
* - int fragstotal : total number of fragments allocated
* - int fragsize : size of a fragment in bytes
* - int bytes : available space in bytes (includes partially used fragments)
* Note! 'bytes' could be more than fragments*fragsize
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
{
ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_GETOSPACE,
&p_aout->p_sys->audio_buf );
/* returns the allocated space in bytes */
return ( (p_aout->p_sys->audio_buf.fragstotal
* p_aout->p_sys->audio_buf.fragsize)
- p_aout->p_sys->audio_buf.bytes );
}
/*****************************************************************************
* Play: plays a sound samples buffer
*****************************************************************************
* This function writes a buffer of i_length bytes in the dsp
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
int i_tmp;
i_tmp = write( p_aout->p_sys->i_fd, buffer, i_size );
if( i_tmp < 0 )
{
msg_Err( p_aout, "write failed (%s)", strerror(errno) );
}
}
/*****************************************************************************
* Close: closes the dsp audio device
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
close( p_aout->p_sys->i_fd );
free( p_aout->p_sys->psz_device );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
esd_SOURCES = esd.c

View File

@ -0,0 +1,194 @@
/*****************************************************************************
* esd.c : EsounD module
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
* $Id: esd.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.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 <errno.h> /* ENOMEM */
#include <fcntl.h> /* open(), O_WRONLY */
#include <string.h> /* strerror() */
#include <unistd.h> /* write(), close() */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <esd.h>
/*****************************************************************************
* aout_sys_t: esd audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes some esd specific variables.
*****************************************************************************/
struct aout_sys_t
{
esd_format_t esd_format;
int i_fd;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * );
static int GetBufInfo ( aout_thread_t *, int );
static void Play ( aout_thread_t *, byte_t *, int );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("EsounD audio module") );
set_capability( "audio output", 50 );
set_callbacks( Open, Close );
add_shortcut( "esound" );
vlc_module_end();
/*****************************************************************************
* Open: open an esd socket
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
/* mpg123 does it this way */
int i_bits = ESD_BITS16;
int i_mode = ESD_STREAM;
int i_func = ESD_PLAY;
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return( 1 );
}
/* Initialize some variables */
p_aout->i_rate = esd_audio_rate; /* We use actual esd rate value, not
* initial value */
i_bits = ESD_BITS16;
i_mode = ESD_STREAM;
i_func = ESD_PLAY;
p_aout->p_sys->esd_format = (i_bits | i_mode | i_func) & (~ESD_MASK_CHAN);
if( p_aout->i_channels == 1 )
{
p_aout->p_sys->esd_format |= ESD_MONO;
}
else
{
p_aout->p_sys->esd_format |= ESD_STEREO;
}
/* open a socket for playing a stream
* and try to open /dev/dsp if there's no EsounD */
if ( (p_aout->p_sys->i_fd
= esd_play_stream_fallback(p_aout->p_sys->esd_format,
p_aout->i_rate, NULL, "vlc")) < 0 )
{
msg_Err( p_aout, "cannot open esound socket (format 0x%08x at %ld Hz)",
p_aout->p_sys->esd_format, p_aout->i_rate );
return( -1 );
}
p_aout->pf_setformat = SetFormat;
p_aout->pf_getbufinfo = GetBufInfo;
p_aout->pf_play = Play;
return( 0 );
}
/*****************************************************************************
* SetFormat: set the output format
*****************************************************************************/
static int SetFormat( aout_thread_t *p_aout )
{
int i_fd;
i_fd = esd_open_sound(NULL);
p_aout->i_latency = esd_get_latency(i_fd);
msg_Dbg( p_aout, "aout_esd_latency: %d", p_aout->i_latency );
return( 0 );
}
/*****************************************************************************
* GetBufInfo: buffer status query
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
{
/* arbitrary value that should be changed */
return( i_buffer_limit );
}
/*****************************************************************************
* Play: play a sound samples buffer
*****************************************************************************
* This function writes a buffer of i_length bytes in the socket
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
int i_amount;
if (p_aout->p_sys->esd_format & ESD_STEREO)
{
if (p_aout->p_sys->esd_format & ESD_BITS16)
{
i_amount = (44100 * (ESD_BUF_SIZE + 64)) / p_aout->i_rate;
}
else
{
i_amount = (44100 * (ESD_BUF_SIZE + 128)) / p_aout->i_rate;
}
}
else
{
if (p_aout->p_sys->esd_format & ESD_BITS16)
{
i_amount = (2 * 44100 * (ESD_BUF_SIZE + 128)) / p_aout->i_rate;
}
else
{
i_amount = (2 * 44100 * (ESD_BUF_SIZE + 256)) / p_aout->i_rate;
}
}
write( p_aout->p_sys->i_fd, buffer, i_size );
}
/*****************************************************************************
* Close: close the Esound socket
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
close( p_aout->p_sys->i_fd );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
waveout_SOURCES = waveout.c

View File

@ -0,0 +1,286 @@
/*****************************************************************************
* waveout.c : Windows waveOut plugin for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: waveout.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.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
* 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 <errno.h> /* ENOMEM */
#include <fcntl.h> /* open(), O_WRONLY */
#include <string.h> /* strerror() */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <mmsystem.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * );
static int GetBufInfo ( aout_thread_t *, int );
static void Play ( aout_thread_t *, byte_t *, int );
/* local functions */
static int OpenWaveOutDevice( aout_thread_t *p_aout );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("Win32 waveOut extension module") );
set_capability( "audio output", 250 );
set_callbacks( Open, Close );
vlc_module_end();
/*****************************************************************************
* aout_sys_t: waveOut audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the waveOut specific properties of an audio device.
*****************************************************************************/
#define NUMBUF 3 /* We use triple buffering to be on the safe side */
struct aout_sys_t
{
HWAVEOUT h_waveout; /* handle to waveout instance */
WAVEFORMATEX waveformat; /* Audio format */
WAVEHDR waveheader[NUMBUF];
int i_current_buffer;
DWORD dw_counter; /* Number of bytes played since beginning */
};
/*****************************************************************************
* Open: open the audio device
*****************************************************************************
* This function opens and setups Win32 waveOut
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i;
/* Allocate structure */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return( 1 );
}
p_aout->pf_setformat = SetFormat;
p_aout->pf_getbufinfo = GetBufInfo;
p_aout->pf_play = Play;
/* Initialize some variables */
p_aout->p_sys->i_current_buffer = 0;
for( i=0; i<NUMBUF; i++)
p_aout->p_sys->waveheader[i].lpData = malloc( 1 );
return OpenWaveOutDevice( p_aout );
}
/*****************************************************************************
* SetFormat: reset the audio device and sets its format
*****************************************************************************
* This functions set a new audio format.
* For this we need to close the current device and create another
* one with the desired format.
*****************************************************************************/
static int SetFormat( aout_thread_t *p_aout )
{
msg_Dbg( p_aout, "SetFormat" );
/* Check if the format has changed */
if( (p_aout->p_sys->waveformat.nChannels != p_aout->i_channels) ||
(p_aout->p_sys->waveformat.nSamplesPerSec != p_aout->i_rate) )
{
/* Before calling waveOutClose we must reset the device */
waveOutReset( p_aout->p_sys->h_waveout );
if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutClose failed" );
}
return OpenWaveOutDevice( p_aout );
}
return 0;
}
/*****************************************************************************
* GetBufInfo: buffer status query
*****************************************************************************
* returns the number of bytes in the audio buffer that have not yet been
* sent to the sound device.
*****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
{
MMTIME mmtime;
mmtime.wType = TIME_BYTES;
if( (waveOutGetPosition(p_aout->p_sys->h_waveout, &mmtime, sizeof(MMTIME)))
!= MMSYSERR_NOERROR || (mmtime.wType != TIME_BYTES) )
{
msg_Warn( p_aout, "waveOutGetPosition failed" );
return i_buffer_limit;
}
#if 0
msg_Dbg( p_aout, "GetBufInfo: %i",
p_aout->p_sys->dw_counter - mmtime.u.cb );
#endif
return (p_aout->p_sys->dw_counter - mmtime.u.cb);
}
/*****************************************************************************
* Play: play a sound buffer
*****************************************************************************
* This function writes a buffer of i_length bytes
*****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
{
MMRESULT result;
int current_buffer = p_aout->p_sys->i_current_buffer;
p_aout->p_sys->i_current_buffer = (current_buffer + 1) % NUMBUF;
/* Unprepare the old buffer */
waveOutUnprepareHeader( p_aout->p_sys->h_waveout,
&p_aout->p_sys->waveheader[current_buffer],
sizeof(WAVEHDR) );
/* Prepare the buffer */
p_aout->p_sys->waveheader[current_buffer].lpData =
realloc( p_aout->p_sys->waveheader[current_buffer].lpData, i_size );
if( !p_aout->p_sys->waveheader[current_buffer].lpData )
{
msg_Err( p_aout, "could not allocate buffer" );
return;
}
p_aout->p_sys->waveheader[current_buffer].dwBufferLength = i_size;
p_aout->p_sys->waveheader[current_buffer].dwFlags = 0;
result = waveOutPrepareHeader( p_aout->p_sys->h_waveout,
&p_aout->p_sys->waveheader[current_buffer],
sizeof(WAVEHDR) );
if( result != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutPrepareHeader failed" );
return;
}
/* Send the buffer the waveOut queue */
p_aout->p_vlc->pf_memcpy( p_aout->p_sys->waveheader[current_buffer].lpData,
p_buffer, i_size );
result = waveOutWrite( p_aout->p_sys->h_waveout,
&p_aout->p_sys->waveheader[current_buffer],
sizeof(WAVEHDR) );
if( result != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutWrite failed" );
return;
}
/* keep track of number of bytes played */
p_aout->p_sys->dw_counter += i_size;
}
/*****************************************************************************
* Close: close the audio device
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i;
/* Before calling waveOutClose we must reset the device */
waveOutReset( p_aout->p_sys->h_waveout );
/* Close the device */
if( waveOutClose( p_aout->p_sys->h_waveout ) != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutClose failed" );
}
/* Deallocate memory */
for( i=0; i<NUMBUF; i++ )
free( p_aout->p_sys->waveheader[i].lpData );
if( p_aout->p_sys != NULL )
{
free( p_aout->p_sys );
p_aout->p_sys = NULL;
}
}
/*****************************************************************************
* OpenWaveOutDevice: open the sound device
****************************************************************************/
static int OpenWaveOutDevice( aout_thread_t *p_aout )
{
MMRESULT result;
/* initialize played bytes counter */
p_aout->p_sys->dw_counter = 0;
/* Set sound format */
p_aout->p_sys->waveformat.wFormatTag = WAVE_FORMAT_PCM;
p_aout->p_sys->waveformat.nChannels = p_aout->i_channels;
p_aout->p_sys->waveformat.nSamplesPerSec = p_aout->i_rate;
p_aout->p_sys->waveformat.wBitsPerSample = 16;
p_aout->p_sys->waveformat.nBlockAlign =
p_aout->p_sys->waveformat.wBitsPerSample / 8 * p_aout->i_channels;
p_aout->p_sys->waveformat.nAvgBytesPerSec =
p_aout->p_sys->waveformat.nSamplesPerSec *
p_aout->p_sys->waveformat.nBlockAlign;
/* Open the device */
result = waveOutOpen( &p_aout->p_sys->h_waveout, WAVE_MAPPER,
&p_aout->p_sys->waveformat,
0 /*callback*/, 0 /*callback data*/, CALLBACK_NULL );
if( result != MMSYSERR_NOERROR )
{
msg_Err( p_aout, "waveOutOpen failed" );
return( 1 );
}
return( 0 );
}

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
a52_SOURCES = a52.c

386
modules/codec/a52/a52.c Normal file
View File

@ -0,0 +1,386 @@
/*****************************************************************************
* a52.c: ATSC A/52 aka AC-3 decoder plugin for vlc.
* This plugin makes use of liba52 to decode A/52 audio
* (http://liba52.sf.net/).
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: a52.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.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
* 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 <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#ifdef HAVE_STDINT_H
# include <stdint.h> /* int16_t .. */
#elif HAVE_INTTYPES_H
# include <inttypes.h> /* int16_t .. */
#endif
#ifdef USE_A52DEC_TREE /* liba52 header file */
# include "include/a52.h"
#else
# include "a52dec/a52.h"
#endif
#include "a52.h"
#define A52DEC_FRAME_SIZE 1536
/*
* Global lock for accessing liba52 functions.
* Currently, liba52 isn't thread-safe. So to prevent two threads from
* using liba52 at the same time, we have to set up a global lock.
* I know static variables aren't a good idea in multi-threaded programs,
* but believe me, this is the way to go.
* --Meuuh 2002-07-19
*/
static vlc_mutex_t a52_lock;
static vlc_bool_t b_liba52_initialized = 0;
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
static int DecodeFrame ( a52_adec_thread_t * );
static int InitThread ( a52_adec_thread_t * );
static void EndThread ( a52_adec_thread_t * );
static void BitstreamCallback ( bit_stream_t *, vlc_bool_t );
static void float2s16_2 ( float *, int16_t * );
static inline int16_t convert ( int32_t );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define DYNRNG_TEXT N_("A/52 dynamic range compression")
#define DYNRNG_LONGTEXT N_( \
"Dynamic range compression makes the loud sounds softer, and the soft " \
"sounds louder, so you can more easily listen to the stream in a noisy " \
"environment without disturbing anyone. If you disable the dynamic range "\
"compression the playback will be more adapted to a movie theater or a " \
"listening room.")
vlc_module_begin();
add_category_hint( N_("Miscellaneous"), NULL );
add_bool( "a52-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT );
set_description( _("a52 ATSC A/52 aka AC-3 audio decoder module") );
set_capability( "decoder", 60 );
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to choose.
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ') )
{
return VLC_EGENERIC;
}
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
}
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static int RunDecoder( decoder_fifo_t *p_fifo )
{
a52_adec_thread_t *p_a52_adec;
/* Allocate the memory needed to store the thread's structure */
p_a52_adec = (a52_adec_thread_t *)malloc( sizeof(a52_adec_thread_t) );
if (p_a52_adec == NULL)
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
return( -1 );
}
/* FIXME */
p_a52_adec->i_channels = 2;
/*
* Initialize the thread properties
*/
p_a52_adec->p_aout_fifo = NULL;
p_a52_adec->p_fifo = p_fifo;
if( InitThread( p_a52_adec ) )
{
msg_Err( p_a52_adec->p_fifo, "could not initialize thread" );
DecoderError( p_fifo );
free( p_a52_adec );
return( -1 );
}
/* liba52 decoder thread's main loop */
while( !p_a52_adec->p_fifo->b_die && !p_a52_adec->p_fifo->b_error )
{
/* look for sync word - should be 0x0b77 */
RealignBits(&p_a52_adec->bit_stream);
while( (ShowBits( &p_a52_adec->bit_stream, 16 ) ) != 0x0b77 &&
(!p_a52_adec->p_fifo->b_die) && (!p_a52_adec->p_fifo->b_error))
{
RemoveBits( &p_a52_adec->bit_stream, 8 );
}
/* get a52 frame header */
GetChunk( &p_a52_adec->bit_stream, p_a52_adec->p_frame_buffer, 7 );
if( p_a52_adec->p_fifo->b_die ) break;
/* check if frame is valid and get frame info */
vlc_mutex_lock( &a52_lock );
p_a52_adec->frame_size = a52_syncinfo( p_a52_adec->p_frame_buffer,
&p_a52_adec->flags,
&p_a52_adec->sample_rate,
&p_a52_adec->bit_rate );
vlc_mutex_unlock( &a52_lock );
if( !p_a52_adec->frame_size )
{
msg_Warn( p_a52_adec->p_fifo, "a52_syncinfo failed" );
continue;
}
if( DecodeFrame( p_a52_adec ) && !p_a52_adec->p_fifo->b_die )
{
DecoderError( p_fifo );
free( p_a52_adec );
return( -1 );
}
}
/* If b_error is set, the decoder thread enters the error loop */
if( p_a52_adec->p_fifo->b_error )
{
DecoderError( p_a52_adec->p_fifo );
}
/* End of the liba52 decoder thread */
EndThread( p_a52_adec );
return( 0 );
}
/*****************************************************************************
* InitThread: initialize data before entering main loop
*****************************************************************************/
static int InitThread( a52_adec_thread_t * p_a52_adec )
{
/* Initialize the global lock */
vlc_mutex_lock( p_a52_adec->p_fifo->p_vlc->p_global_lock );
if ( !b_liba52_initialized )
{
vlc_mutex_init( p_a52_adec->p_fifo, &a52_lock );
b_liba52_initialized = 1;
}
vlc_mutex_unlock( p_a52_adec->p_fifo->p_vlc->p_global_lock );
/* Initialize liba52 */
vlc_mutex_lock( &a52_lock );
p_a52_adec->p_a52_state = a52_init( 0 );
vlc_mutex_unlock( &a52_lock );
if( p_a52_adec->p_a52_state == NULL )
{
msg_Err( p_a52_adec->p_fifo, "unable to initialize liba52" );
return -1;
}
p_a52_adec->b_dynrng = config_GetInt( p_a52_adec->p_fifo, "a52-dynrng" );
/* Init the BitStream */
InitBitstream( &p_a52_adec->bit_stream,
p_a52_adec->p_fifo,
BitstreamCallback, NULL );
return( 0 );
}
/*****************************************************************************
* DecodeFrame: decodes an ATSC A/52 frame.
*****************************************************************************/
static int DecodeFrame( a52_adec_thread_t * p_a52_adec )
{
sample_t sample_level = 1;
byte_t *p_buffer;
int i;
if( ( p_a52_adec->p_aout_fifo != NULL ) &&
( p_a52_adec->p_aout_fifo->i_rate != p_a52_adec->sample_rate ) )
{
/* Make sure the output thread leaves the NextFrame() function */
vlc_mutex_lock (&(p_a52_adec->p_aout_fifo->data_lock));
aout_DestroyFifo (p_a52_adec->p_aout_fifo);
vlc_cond_signal (&(p_a52_adec->p_aout_fifo->data_wait));
vlc_mutex_unlock (&(p_a52_adec->p_aout_fifo->data_lock));
p_a52_adec->p_aout_fifo = NULL;
}
/* Creating the audio output fifo if not created yet */
if( p_a52_adec->p_aout_fifo == NULL )
{
p_a52_adec->p_aout_fifo = aout_CreateFifo( p_a52_adec->p_fifo,
AOUT_FIFO_PCM, p_a52_adec->i_channels,
p_a52_adec->sample_rate,
A52DEC_FRAME_SIZE * p_a52_adec->i_channels,
NULL );
if ( p_a52_adec->p_aout_fifo == NULL )
{
return( -1 );
}
}
/* Set the Presentation Time Stamp */
CurrentPTS( &p_a52_adec->bit_stream,
&p_a52_adec->p_aout_fifo->date[
p_a52_adec->p_aout_fifo->i_end_frame],
NULL );
if( !p_a52_adec->p_aout_fifo->date[
p_a52_adec->p_aout_fifo->i_end_frame] )
{
p_a52_adec->p_aout_fifo->date[
p_a52_adec->p_aout_fifo->i_end_frame] = LAST_MDATE;
}
p_buffer = ((byte_t *)p_a52_adec->p_aout_fifo->buffer) +
( p_a52_adec->p_aout_fifo->i_end_frame * A52DEC_FRAME_SIZE *
p_a52_adec->i_channels * sizeof(s16) );
/* FIXME */
p_a52_adec->flags = A52_STEREO | A52_ADJUST_LEVEL;
/* Get the complete frame */
GetChunk( &p_a52_adec->bit_stream, p_a52_adec->p_frame_buffer + 7,
p_a52_adec->frame_size - 7 );
if( p_a52_adec->p_fifo->b_die ) return( -1 );
/* do the actual decoding now */
vlc_mutex_lock( &a52_lock );
a52_frame( p_a52_adec->p_a52_state, p_a52_adec->p_frame_buffer,
&p_a52_adec->flags, &sample_level, 384 );
if( !p_a52_adec->b_dynrng )
a52_dynrng( p_a52_adec->p_a52_state, NULL, NULL );
for( i = 0; i < 6; i++ )
{
if( a52_block( p_a52_adec->p_a52_state ) )
{
msg_Warn( p_a52_adec->p_fifo, "a52_block failed for block %i", i );
}
float2s16_2( a52_samples( p_a52_adec->p_a52_state ),
((int16_t *)p_buffer) + i * 256 * p_a52_adec->i_channels );
}
vlc_mutex_unlock( &a52_lock );
vlc_mutex_lock( &p_a52_adec->p_aout_fifo->data_lock );
p_a52_adec->p_aout_fifo->i_end_frame =
(p_a52_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
vlc_cond_signal (&p_a52_adec->p_aout_fifo->data_wait);
vlc_mutex_unlock (&p_a52_adec->p_aout_fifo->data_lock);
return 0;
}
/*****************************************************************************
* EndThread : liba52 decoder thread destruction
*****************************************************************************/
static void EndThread (a52_adec_thread_t *p_a52_adec)
{
/* If the audio output fifo was created, we destroy it */
if (p_a52_adec->p_aout_fifo != NULL)
{
aout_DestroyFifo (p_a52_adec->p_aout_fifo);
/* Make sure the output thread leaves the NextFrame() function */
vlc_mutex_lock (&(p_a52_adec->p_aout_fifo->data_lock));
vlc_cond_signal (&(p_a52_adec->p_aout_fifo->data_wait));
vlc_mutex_unlock (&(p_a52_adec->p_aout_fifo->data_lock));
}
vlc_mutex_lock( &a52_lock );
a52_free( p_a52_adec->p_a52_state );
vlc_mutex_unlock( &a52_lock );
free( p_a52_adec );
}
/*****************************************************************************
* float2s16_2 : converts floats to ints using a trick based on the IEEE
* floating-point format
*****************************************************************************/
static inline int16_t convert (int32_t i)
{
if (i > 0x43c07fff)
return 32767;
else if (i < 0x43bf8000)
return -32768;
else
return i - 0x43c00000;
}
static void float2s16_2 (float * _f, int16_t * s16)
{
int i;
int32_t * f = (int32_t *) _f;
for (i = 0; i < 256; i++) {
s16[2*i] = convert (f[i]);
s16[2*i+1] = convert (f[i+256]);
}
}
/*****************************************************************************
* BitstreamCallback: Import parameters from the new data/PES packet
*****************************************************************************
* This function is called by input's NextDataPacket.
*****************************************************************************/
static void BitstreamCallback ( bit_stream_t * p_bit_stream,
vlc_bool_t b_new_pes )
{
if( b_new_pes )
{
/* Drop special A52 header */
/* p_bit_stream->p_byte += 3; */
}
}

59
modules/codec/a52/a52.h Normal file
View File

@ -0,0 +1,59 @@
/*****************************************************************************
* a52.h: ATSC A/52 aka AC-3 decoder plugin for vlc.
* This plugin makes use of liba52 to decode A/52 audio
* (http://liba52.sf.net/).
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: a52.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.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
* 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.
*****************************************************************************/
/*****************************************************************************
* a52_adec_thread_t : a52 decoder thread descriptor
*****************************************************************************/
typedef struct a52_adec_thread_s
{
/*
* liba52 properties
*/
a52_state_t *p_a52_state;
int frame_size;
int flags;
int sample_rate;
int bit_rate;
vlc_bool_t b_dynrng;
/* The bit stream structure handles the PES stream at the bit level */
bit_stream_t bit_stream;
/*
* Input properties
*/
decoder_fifo_t *p_fifo; /* stores the PES stream data */
data_packet_t *p_data;
/*
* Output properties
*/
aout_fifo_t *p_aout_fifo; /* stores the decompressed audio frames */
int i_channels;
/* temporary buffer to store the raw frame to be decoded */
u8 p_frame_buffer[3840];
} a52_adec_thread_t;

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1 @@
a52old_SOURCES = a52old.c decoder.c parse.c exponent.c bit_allocate.c mantissa.c rematrix.c imdct.c

View File

@ -0,0 +1,384 @@
/*****************************************************************************
* a52old.c: A52 decoder module main file
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: a52old.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Lespinasse <walken@zoy.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> /* malloc(), free() */
#include <string.h> /* memset() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h> /* getpid() */
#endif
#include "imdct.h"
#include "downmix.h"
#include "adec.h"
#define A52DEC_FRAME_SIZE (2*1536)
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
static int InitThread ( a52dec_t * p_adec );
static void EndThread ( a52dec_t * p_adec );
static void BitstreamCallback ( bit_stream_t *p_bit_stream,
vlc_bool_t b_new_pes );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( N_("Miscellaneous"), NULL );
add_module ( "a52-downmix", "downmix", NULL, NULL,
N_("A52 downmix module"), NULL );
add_module ( "a52-imdct", "imdct", NULL, NULL,
N_("A52 IMDCT module"), NULL );
set_description( _("software A52 decoder") );
set_capability( "decoder", 50 );
set_callbacks( OpenDecoder, NULL );
add_shortcut( "a52" );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ') )
{
return VLC_EGENERIC;
}
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
}
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static int RunDecoder( decoder_fifo_t *p_fifo )
{
a52dec_t * p_a52dec;
void * p_orig; /* pointer before memalign */
vlc_bool_t b_sync = 0;
/* Allocate the memory needed to store the thread's structure */
p_a52dec = (a52dec_t *)vlc_memalign( &p_orig, 16, sizeof(a52dec_t) );
memset( p_a52dec, 0, sizeof( a52dec_t ) );
if( p_a52dec == NULL )
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
return( -1 );
}
/*
* Initialize the thread properties
*/
p_a52dec->p_fifo = p_fifo;
if( InitThread( p_a52dec ) )
{
msg_Err( p_fifo, "could not initialize thread" );
DecoderError( p_fifo );
free( p_orig );
return( -1 );
}
/* A52 decoder thread's main loop */
/* FIXME : do we have enough room to store the decoded frames ?? */
while ((!p_a52dec->p_fifo->b_die) && (!p_a52dec->p_fifo->b_error))
{
s16 * buffer;
sync_info_t sync_info;
if( !b_sync )
{
int i_sync_ptr;
#define p_bit_stream (&p_a52dec->bit_stream)
/* Go to the next PES packet and jump to sync_ptr */
do {
BitstreamNextDataPacket( p_bit_stream );
} while( !p_bit_stream->p_decoder_fifo->b_die
&& !p_bit_stream->p_decoder_fifo->b_error
&& p_bit_stream->p_data !=
p_bit_stream->p_decoder_fifo->p_first->p_first );
i_sync_ptr = *(p_bit_stream->p_byte - 2) << 8
| *(p_bit_stream->p_byte - 1);
p_bit_stream->p_byte += i_sync_ptr;
/* Empty the bit FIFO and realign the bit stream */
p_bit_stream->fifo.buffer = 0;
p_bit_stream->fifo.i_available = 0;
AlignWord( p_bit_stream );
b_sync = 1;
#undef p_bit_stream
}
if (sync_frame (p_a52dec, &sync_info))
{
b_sync = 0;
continue;
}
if( ( p_a52dec->p_aout_fifo != NULL ) &&
( p_a52dec->p_aout_fifo->i_rate != sync_info.sample_rate ) )
{
/* Make sure the output thread leaves the NextFrame() function */
vlc_mutex_lock (&(p_a52dec->p_aout_fifo->data_lock));
aout_DestroyFifo (p_a52dec->p_aout_fifo);
vlc_cond_signal (&(p_a52dec->p_aout_fifo->data_wait));
vlc_mutex_unlock (&(p_a52dec->p_aout_fifo->data_lock));
p_a52dec->p_aout_fifo = NULL;
}
/* Creating the audio output fifo if not created yet */
if (p_a52dec->p_aout_fifo == NULL ) {
p_a52dec->p_aout_fifo =
aout_CreateFifo( p_a52dec->p_fifo, AOUT_FIFO_PCM, 2,
sync_info.sample_rate, A52DEC_FRAME_SIZE, NULL );
if ( p_a52dec->p_aout_fifo == NULL )
{
p_a52dec->p_fifo->b_error = 1;
break;
}
}
CurrentPTS( &p_a52dec->bit_stream,
&p_a52dec->p_aout_fifo->date[p_a52dec->p_aout_fifo->i_end_frame],
NULL );
if( !p_a52dec->p_aout_fifo->date[p_a52dec->p_aout_fifo->i_end_frame] )
{
p_a52dec->p_aout_fifo->date[
p_a52dec->p_aout_fifo->i_end_frame] =
LAST_MDATE;
}
buffer = ((s16 *)p_a52dec->p_aout_fifo->buffer) +
(p_a52dec->p_aout_fifo->i_end_frame * A52DEC_FRAME_SIZE);
if (decode_frame (p_a52dec, buffer))
{
b_sync = 0;
continue;
}
vlc_mutex_lock (&p_a52dec->p_aout_fifo->data_lock);
p_a52dec->p_aout_fifo->i_end_frame =
(p_a52dec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
vlc_cond_signal (&p_a52dec->p_aout_fifo->data_wait);
vlc_mutex_unlock (&p_a52dec->p_aout_fifo->data_lock);
RealignBits(&p_a52dec->bit_stream);
}
/* If b_error is set, the A52 decoder thread enters the error loop */
if (p_a52dec->p_fifo->b_error)
{
DecoderError( p_a52dec->p_fifo );
}
/* End of the A52 decoder thread */
EndThread (p_a52dec);
free( p_orig );
return( 0 );
}
/*****************************************************************************
* InitThread: initialize data before entering main loop
*****************************************************************************/
static int InitThread( a52dec_t * p_a52dec )
{
char *psz_name;
/*
* Choose the best downmix module
*/
p_a52dec->p_downmix = vlc_object_create( p_a52dec->p_fifo,
sizeof( downmix_t ) );
p_a52dec->p_downmix->psz_object_name = "downmix";
psz_name = config_GetPsz( p_a52dec->p_downmix, "a52-downmix" );
p_a52dec->p_downmix->p_module =
module_Need( p_a52dec->p_downmix, "downmix", psz_name );
if( psz_name ) free( psz_name );
if( p_a52dec->p_downmix->p_module == NULL )
{
msg_Err( p_a52dec->p_fifo, "no suitable downmix module" );
vlc_object_destroy( p_a52dec->p_downmix );
return( -1 );
}
/*
* Choose the best IMDCT module
*/
p_a52dec->p_imdct = vlc_object_create( p_a52dec->p_fifo,
sizeof( imdct_t ) );
#define IMDCT p_a52dec->p_imdct
psz_name = config_GetPsz( p_a52dec->p_fifo, "a52-imdct" );
p_a52dec->p_imdct->p_module =
module_Need( p_a52dec->p_imdct, "imdct", psz_name );
if( psz_name ) free( psz_name );
if( p_a52dec->p_imdct->p_module == NULL )
{
msg_Err( p_a52dec->p_fifo, "no suitable IMDCT module" );
vlc_object_destroy( p_a52dec->p_imdct );
module_Unneed( p_a52dec->p_downmix, p_a52dec->p_downmix->p_module );
vlc_object_destroy( p_a52dec->p_downmix );
return( -1 );
}
/* Initialize the A52 decoder structures */
p_a52dec->samples = vlc_memalign( &p_a52dec->samples_orig,
16, 6 * 256 * sizeof(float) );
IMDCT->buf = vlc_memalign( &IMDCT->buf_orig,
16, N/4 * sizeof(complex_t) );
IMDCT->delay = vlc_memalign( &IMDCT->delay_orig,
16, 6 * 256 * sizeof(float) );
IMDCT->delay1 = vlc_memalign( &IMDCT->delay1_orig,
16, 6 * 256 * sizeof(float) );
IMDCT->xcos1 = vlc_memalign( &IMDCT->xcos1_orig,
16, N/4 * sizeof(float) );
IMDCT->xsin1 = vlc_memalign( &IMDCT->xsin1_orig,
16, N/4 * sizeof(float) );
IMDCT->xcos2 = vlc_memalign( &IMDCT->xcos2_orig,
16, N/8 * sizeof(float) );
IMDCT->xsin2 = vlc_memalign( &IMDCT->xsin2_orig,
16, N/8 * sizeof(float) );
IMDCT->xcos_sin_sse = vlc_memalign( &IMDCT->xcos_sin_sse_orig,
16, 128 * 4 * sizeof(float) );
IMDCT->w_1 = vlc_memalign( &IMDCT->w_1_orig,
16, 1 * sizeof(complex_t) );
IMDCT->w_2 = vlc_memalign( &IMDCT->w_2_orig,
16, 2 * sizeof(complex_t) );
IMDCT->w_4 = vlc_memalign( &IMDCT->w_4_orig,
16, 4 * sizeof(complex_t) );
IMDCT->w_8 = vlc_memalign( &IMDCT->w_8_orig,
16, 8 * sizeof(complex_t) );
IMDCT->w_16 = vlc_memalign( &IMDCT->w_16_orig,
16, 16 * sizeof(complex_t) );
IMDCT->w_32 = vlc_memalign( &IMDCT->w_32_orig,
16, 32 * sizeof(complex_t) );
IMDCT->w_64 = vlc_memalign( &IMDCT->w_64_orig,
16, 64 * sizeof(complex_t) );
#undef IMDCT
E_( a52_init )( p_a52dec );
/*
* Initialize the output properties
*/
p_a52dec->p_aout_fifo = NULL;
/*
* Bit stream
*/
InitBitstream( &p_a52dec->bit_stream, p_a52dec->p_fifo,
BitstreamCallback, (void *) p_a52dec );
return( 0 );
}
/*****************************************************************************
* EndThread : A52 decoder thread destruction
*****************************************************************************/
static void EndThread (a52dec_t * p_a52dec)
{
/* If the audio output fifo was created, we destroy it */
if (p_a52dec->p_aout_fifo != NULL)
{
aout_DestroyFifo (p_a52dec->p_aout_fifo);
/* Make sure the output thread leaves the NextFrame() function */
vlc_mutex_lock (&(p_a52dec->p_aout_fifo->data_lock));
vlc_cond_signal (&(p_a52dec->p_aout_fifo->data_wait));
vlc_mutex_unlock (&(p_a52dec->p_aout_fifo->data_lock));
}
/* Free allocated structures */
#define IMDCT p_a52dec->p_imdct
free( IMDCT->w_1_orig );
free( IMDCT->w_64_orig );
free( IMDCT->w_32_orig );
free( IMDCT->w_16_orig );
free( IMDCT->w_8_orig );
free( IMDCT->w_4_orig );
free( IMDCT->w_2_orig );
free( IMDCT->xcos_sin_sse_orig );
free( IMDCT->xsin2_orig );
free( IMDCT->xcos2_orig );
free( IMDCT->xsin1_orig );
free( IMDCT->xcos1_orig );
free( IMDCT->delay1_orig );
free( IMDCT->delay_orig );
free( IMDCT->buf_orig );
#undef IMDCT
free( p_a52dec->samples_orig );
/* Unlock the modules */
module_Unneed( p_a52dec->p_downmix, p_a52dec->p_downmix->p_module );
vlc_object_destroy( p_a52dec->p_downmix );
module_Unneed( p_a52dec->p_imdct, p_a52dec->p_imdct->p_module );
vlc_object_destroy( p_a52dec->p_imdct );
/* Free what's left of the decoder */
free( p_a52dec->imdct_orig );
}
/*****************************************************************************
* BitstreamCallback: Import parameters from the new data/PES packet
*****************************************************************************
* This function is called by input's NextDataPacket.
*****************************************************************************/
static void BitstreamCallback ( bit_stream_t * p_bit_stream,
vlc_bool_t b_new_pes )
{
if( b_new_pes )
{
/* Drop special A52 header */
/* p_bit_stream->p_byte += 3; */
}
}

409
modules/codec/a52old/adec.h Normal file
View File

@ -0,0 +1,409 @@
/*****************************************************************************
* adec.h : A52 decoder interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: adec.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@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.
*****************************************************************************/
/*****************************************************************************
* Prototypes
*****************************************************************************/
vlc_thread_t a52dec_CreateThread( decoder_fifo_t * p_fifo );
/**** A52 decoder API - public A52 decoder structures */
typedef struct a52dec_s a52dec_t;
typedef struct sync_info_s {
int sample_rate; /* sample rate in Hz */
int frame_size; /* frame size in bytes */
int bit_rate; /* nominal bit rate in kbps */
} sync_info_t;
/**** A52 decoder API - functions publically provided by the A52 decoder ****/
int E_( a52_init )(a52dec_t * p_a52dec);
int sync_frame (a52dec_t * p_a52dec, sync_info_t * p_sync_info);
int decode_frame (a52dec_t * p_a52dec, s16 * buffer);
/**** EVERYTHING AFTER THIS POINT IS PRIVATE ! DO NOT USE DIRECTLY ****/
/**** A52 decoder internal structures ****/
/* The following structures are filled in by their corresponding parse_*
* functions. See http://www.atsc.org/Standards/A52/a_52.pdf for
* full details on each field. Indented fields are used to denote
* conditional fields.
*/
typedef struct syncinfo_s {
/* Sync word == 0x0B77 */
/* u16 syncword; */
/* crc for the first 5/8 of the sync block */
/* u16 crc1; */
/* Stream Sampling Rate (kHz) 0 = 48, 1 = 44.1, 2 = 32, 3 = reserved */
u16 fscod;
/* Frame size code */
u16 frmsizecod;
/* Information not in the AC-3 bitstream, but derived */
/* Frame size in 16 bit words */
u16 frame_size;
/* Bit rate in kilobits */
//u16 bit_rate;
} syncinfo_t;
typedef struct bsi_s {
/* Bit stream identification == 0x8 */
u16 bsid;
/* Bit stream mode */
u16 bsmod;
/* Audio coding mode */
u16 acmod;
/* If we're using the centre channel then */
/* centre mix level */
u16 cmixlev;
/* If we're using the surround channel then */
/* surround mix level */
u16 surmixlev;
/* If we're in 2/0 mode then */
/* Dolby surround mix level - NOT USED - */
u16 dsurmod;
/* Low frequency effects on */
u16 lfeon;
/* Dialogue Normalization level */
u16 dialnorm;
/* Compression exists */
u16 compre;
/* Compression level */
u16 compr;
/* Language code exists */
u16 langcode;
/* Language code */
u16 langcod;
/* Audio production info exists*/
u16 audprodie;
u16 mixlevel;
u16 roomtyp;
/* If we're in dual mono mode (acmod == 0) then extra stuff */
u16 dialnorm2;
u16 compr2e;
u16 compr2;
u16 langcod2e;
u16 langcod2;
u16 audprodi2e;
u16 mixlevel2;
u16 roomtyp2;
/* Copyright bit */
u16 copyrightb;
/* Original bit */
u16 origbs;
/* Timecode 1 exists */
u16 timecod1e;
/* Timecode 1 */
u16 timecod1;
/* Timecode 2 exists */
u16 timecod2e;
/* Timecode 2 */
u16 timecod2;
/* Additional bit stream info exists */
u16 addbsie;
/* Additional bit stream length - 1 (in bytes) */
u16 addbsil;
/* Additional bit stream information (max 64 bytes) */
u8 addbsi[64];
/* Information not in the AC-3 bitstream, but derived */
/* Number of channels (excluding LFE)
* Derived from acmod */
u16 nfchans;
} bsi_t;
/* more pain */
typedef struct audblk_s {
/* block switch bit indexed by channel num */
u16 blksw[5];
/* dither enable bit indexed by channel num */
u16 dithflag[5];
/* dynamic range gain exists */
u16 dynrnge;
/* dynamic range gain */
u16 dynrng;
/* if acmod==0 then */
/* dynamic range 2 gain exists */
u16 dynrng2e;
/* dynamic range 2 gain */
u16 dynrng2;
/* coupling strategy exists */
u16 cplstre;
/* coupling in use */
u16 cplinu;
/* channel coupled */
u16 chincpl[5];
/* if acmod==2 then */
/* Phase flags in use */
u16 phsflginu;
/* coupling begin frequency code */
u16 cplbegf;
/* coupling end frequency code */
u16 cplendf;
/* coupling band structure bits */
u16 cplbndstrc[18];
/* Do coupling co-ords exist for this channel? */
u16 cplcoe[5];
/* Master coupling co-ordinate */
u16 mstrcplco[5];
/* Per coupling band coupling co-ordinates */
u16 cplcoexp[5][18];
u16 cplcomant[5][18];
/* Phase flags for dual mono */
u16 phsflg[18];
/* Is there a rematrixing strategy */
u16 rematstr;
/* Rematrixing bits */
u16 rematflg[4];
/* Coupling exponent strategy */
u16 cplexpstr;
/* Exponent strategy for full bandwidth channels */
u16 chexpstr[5];
/* Exponent strategy for lfe channel */
u16 lfeexpstr;
/* Channel bandwidth for independent channels */
u16 chbwcod[5];
/* The absolute coupling exponent */
u16 cplabsexp;
/* Coupling channel exponents (D15 mode gives 18 * 12 /3 encoded exponents */
u16 cplexps[18 * 12 / 3];
/* Sanity checking constant */
u32 magic2;
/* fbw channel exponents */
u16 exps[5][252 / 3];
/* channel gain range */
u16 gainrng[5];
/* low frequency exponents */
u16 lfeexps[3];
/* Bit allocation info */
u16 baie;
/* Slow decay code */
u16 sdcycod;
/* Fast decay code */
u16 fdcycod;
/* Slow gain code */
u16 sgaincod;
/* dB per bit code */
u16 dbpbcod;
/* masking floor code */
u16 floorcod;
/* SNR offset info */
u16 snroffste;
/* coarse SNR offset */
u16 csnroffst;
/* coupling fine SNR offset */
u16 cplfsnroffst;
/* coupling fast gain code */
u16 cplfgaincod;
/* fbw fine SNR offset */
u16 fsnroffst[5];
/* fbw fast gain code */
u16 fgaincod[5];
/* lfe fine SNR offset */
u16 lfefsnroffst;
/* lfe fast gain code */
u16 lfefgaincod;
/* Coupling leak info */
u16 cplleake;
/* coupling fast leak initialization */
u16 cplfleak;
/* coupling slow leak initialization */
u16 cplsleak;
/* delta bit allocation info */
u16 deltbaie;
/* coupling delta bit allocation exists */
u16 cpldeltbae;
/* fbw delta bit allocation exists */
u16 deltbae[5];
/* number of cpl delta bit segments */
u16 cpldeltnseg;
/* coupling delta bit allocation offset */
u16 cpldeltoffst[8];
/* coupling delta bit allocation length */
u16 cpldeltlen[8];
/* coupling delta bit allocation length */
u16 cpldeltba[8];
/* number of delta bit segments */
u16 deltnseg[5];
/* fbw delta bit allocation offset */
u16 deltoffst[5][8];
/* fbw delta bit allocation length */
u16 deltlen[5][8];
/* fbw delta bit allocation length */
u16 deltba[5][8];
/* skip length exists */
u16 skiple;
/* skip length */
u16 skipl;
/* channel mantissas */
// u16 chmant[5][256];
/* coupling mantissas */
float cpl_flt[ 256 ];
// u16 cplmant[256];
/* coupling mantissas */
// u16 lfemant[7];
/* -- Information not in the bitstream, but derived thereof -- */
/* Number of coupling sub-bands */
u16 ncplsubnd;
/* Number of combined coupling sub-bands
* Derived from ncplsubnd and cplbndstrc */
u16 ncplbnd;
/* Number of exponent groups by channel
* Derived from strmant, endmant */
u16 nchgrps[5];
/* Number of coupling exponent groups
* Derived from cplbegf, cplendf, cplexpstr */
u16 ncplgrps;
/* End mantissa numbers of fbw channels */
u16 endmant[5];
/* Start and end mantissa numbers for the coupling channel */
u16 cplstrtmant;
u16 cplendmant;
/* Decoded exponent info */
u16 fbw_exp[5][256];
u16 cpl_exp[256];
u16 lfe_exp[7];
/* Bit allocation pointer results */
u16 fbw_bap[5][256];
/* FIXME?? figure out exactly how many entries there should be (253-37?) */
u16 cpl_bap[256];
u16 lfe_bap[7];
} audblk_t;
/* Everything you wanted to know about band structure */
/*
* The entire frequency domain is represented by 256 real
* floating point fourier coefficients. Only the lower 253
* coefficients are actually utilized however. We use arrays
* of 256 to be efficient in some cases.
*
* The 5 full bandwidth channels (fbw) can have their higher
* frequencies coupled together. These coupled channels then
* share their high frequency components.
*
* This coupling band is broken up into 18 sub-bands starting
* at mantissa number 37. Each sub-band is 12 bins wide.
*
* There are 50 bit allocation sub-bands which cover the entire
* frequency range. The sub-bands are of non-uniform width, and
* approximate a 1/6 octave scale.
*/
typedef struct bit_allocate_s
{
s16 psd[256];
s16 bndpsd[256];
s16 excite[256];
s16 mask[256];
s16 sdecay;
s16 fdecay;
s16 sgain;
s16 dbknee;
s16 floor;
} bit_allocate_t;
/* These store the persistent state of the packed mantissas */
typedef struct mantissa_s
{
float q_1[2];
float q_2[2];
float q_4[1];
s32 q_1_pointer;
s32 q_2_pointer;
s32 q_4_pointer;
u16 lfsr_state;
} mantissa_t;
/*****************************************************************************
* a52dec_t : A52 decoder thread descriptor
*****************************************************************************/
struct a52dec_s
{
/*
* Decoder properties
*/
void * decoder_orig; /* pointer before memalign */
/*
* Thread properties
*/
vlc_thread_t thread_id; /* id for thread functions */
/*
* Input properties
*/
decoder_fifo_t * p_fifo; /* stores the PES stream data */
/* The bit stream structure handles the PES stream at the bit level */
bit_stream_t bit_stream;
int i_available;
unsigned int total_bits_read; /* temporary */
/*
* Decoder properties
*/
syncinfo_t syncinfo;
bsi_t bsi;
audblk_t audblk;
dm_par_t dm_par;
bit_allocate_t bit_allocate;
mantissa_t mantissa;
downmix_t * p_downmix;
/*
* Output properties
*/
aout_fifo_t * p_aout_fifo; /* stores the decompressed audio frames */
float * samples;
void * samples_orig; /* pointer before memalign */
imdct_t * p_imdct;
void * imdct_orig; /* pointer before memalign */
};

View File

@ -0,0 +1,452 @@
/*****************************************************************************
* bit_allocate.c: A52 allocation tables
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: bit_allocate.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Aaron Holtzman <aholtzma@engr.uvic.ca>
* Renaud Dartus <reno@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 <string.h> /* memcpy() */
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include "imdct.h"
#include "downmix.h"
#include "adec.h"
#include "internal.h" /* DELTA_BIT_REUSE */
static void ba_compute_psd (bit_allocate_t * p_bit, s16 start, s16 end, s16 exps[]);
static void ba_compute_excitation (bit_allocate_t * p_bit, s16 start, s16 end, s16 fgain,
s16 fastleak, s16 slowleak, s16 is_lfe);
static void ba_compute_mask (bit_allocate_t * p_bit, s16 start, s16 end, u16 fscod,
u16 deltbae, u16 deltnseg, u16 deltoffst[],
u16 deltba[], u16 deltlen[]);
static void ba_compute_bap (bit_allocate_t * p_bit, s16 start, s16 end,
s16 snroffset, s16 bap[]);
/* Misc LUTs for bit allocation process */
static const s16 slowdec[] = { 0x0f, 0x11, 0x13, 0x15 };
static const s16 fastdec[] = { 0x3f, 0x53, 0x67, 0x7b };
static const s16 slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 };
static const s16 dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 };
static const u16 floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 };
static const s16 fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 };
static const s16 bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 31,
34, 37, 40, 43, 46, 49, 55, 61, 67, 73,
79, 85, 97, 109, 121, 133, 157, 181, 205, 229 };
static const s16 bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 3, 3,
3, 3, 3, 3, 3, 6, 6, 6, 6, 6,
6, 12, 12, 12, 12, 24, 24, 24, 24, 24 };
static const s16 masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 28, 29,
29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34,
34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37,
37, 37, 37, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40,
40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43,
43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44,
44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, 0 };
static const s16 latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039,
0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032,
0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c,
0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026,
0x0025, 0x0024, 0x0024, 0x0023, 0x0023, 0x0022, 0x0021, 0x0021,
0x0020, 0x0020, 0x001f, 0x001e, 0x001e, 0x001d, 0x001d, 0x001c,
0x001c, 0x001b, 0x001b, 0x001a, 0x001a, 0x0019, 0x0019, 0x0018,
0x0018, 0x0017, 0x0017, 0x0016, 0x0016, 0x0015, 0x0015, 0x0015,
0x0014, 0x0014, 0x0013, 0x0013, 0x0013, 0x0012, 0x0012, 0x0012,
0x0011, 0x0011, 0x0011, 0x0010, 0x0010, 0x0010, 0x000f, 0x000f,
0x000f, 0x000e, 0x000e, 0x000e, 0x000d, 0x000d, 0x000d, 0x000d,
0x000c, 0x000c, 0x000c, 0x000c, 0x000b, 0x000b, 0x000b, 0x000b,
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0009, 0x0009, 0x0009,
0x0009, 0x0009, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008,
0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0006, 0x0006,
0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0005, 0x0005,
0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004,
0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004,
0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003,
0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002,
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000};
static const s16 hth[][50] = {{ 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0,
0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390,
0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350,
0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0,
0x02f0, 0x02f0, 0x0300, 0x0310, 0x0340, 0x0390, 0x03e0, 0x0420,
0x0460, 0x0490, 0x04a0, 0x0460, 0x0440, 0x0440, 0x0520, 0x0800,
0x0840, 0x0840 },
{ 0x04f0, 0x04f0, 0x0460, 0x0410, 0x03e0, 0x03d0, 0x03c0, 0x03b0,
0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390,
0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360,
0x0350, 0x0350, 0x0340, 0x0340, 0x0320, 0x0310, 0x0300, 0x02f0,
0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0320, 0x0350, 0x0390, 0x03e0,
0x0420, 0x0450, 0x04a0, 0x0490, 0x0460, 0x0440, 0x0480, 0x0630,
0x0840, 0x0840 },
{ 0x0580, 0x0580, 0x04b0, 0x0450, 0x0420, 0x03f0, 0x03e0, 0x03d0,
0x03c0, 0x03b0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0,
0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0390,
0x0380, 0x0380, 0x0380, 0x0370, 0x0360, 0x0350, 0x0340, 0x0330,
0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0310,
0x0330, 0x0350, 0x03c0, 0x0410, 0x0470, 0x04a0, 0x0460, 0x0440,
0x0450, 0x04e0 }};
static const s16 baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6,
6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10,
10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14,
14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 };
static inline u16 max_value (s16 a, s16 b)
{
return (a > b ? a : b);
}
static inline u16 min_value (s16 a, s16 b)
{
return (a < b ? a : b);
}
static inline s16 logadd (s16 a, s16 b)
{
s16 c;
if ((c = a - b) >= 0) {
return (a + latab[min_value(((c) >> 1), 255)]);
} else {
return (b + latab[min_value(((-c) >> 1), 255)]);
}
}
static inline s16 calc_lowcomp (s16 a, s16 b0, s16 b1, s16 bin)
{
if (bin < 7) {
if ((b0 + 256) == b1)
a = 384;
else if (b0 > b1)
a = max_value(0, a - 64);
} else if (bin < 20) {
if ((b0 + 256) == b1)
a = 320;
else if (b0 > b1)
a = max_value(0, a - 64) ;
} else
a = max_value(0, a - 128);
return a;
}
void bit_allocate (a52dec_t * p_a52dec)
{
u16 i;
s16 fgain;
s16 snroffset;
s16 start;
s16 end;
s16 fastleak;
s16 slowleak;
/* Only perform bit_allocation if the exponents have changed or we
* have new sideband information */
if (p_a52dec->audblk.chexpstr[0] == 0 && p_a52dec->audblk.chexpstr[1] == 0 &&
p_a52dec->audblk.chexpstr[2] == 0 && p_a52dec->audblk.chexpstr[3] == 0 &&
p_a52dec->audblk.chexpstr[4] == 0 && p_a52dec->audblk.cplexpstr == 0 &&
p_a52dec->audblk.lfeexpstr == 0 && p_a52dec->audblk.baie == 0 &&
p_a52dec->audblk.snroffste == 0 && p_a52dec->audblk.deltbaie == 0)
return;
/* Do some setup before we do the bit alloc */
p_a52dec->bit_allocate.sdecay = slowdec[p_a52dec->audblk.sdcycod];
p_a52dec->bit_allocate.fdecay = fastdec[p_a52dec->audblk.fdcycod];
p_a52dec->bit_allocate.sgain = slowgain[p_a52dec->audblk.sgaincod];
p_a52dec->bit_allocate.dbknee = dbpbtab[p_a52dec->audblk.dbpbcod];
p_a52dec->bit_allocate.floor = floortab[p_a52dec->audblk.floorcod];
/* if all the SNR offset constants are zero then the whole block is zero */
if (!p_a52dec->audblk.csnroffst && !p_a52dec->audblk.fsnroffst[0] &&
!p_a52dec->audblk.fsnroffst[1] && !p_a52dec->audblk.fsnroffst[2] &&
!p_a52dec->audblk.fsnroffst[3] && !p_a52dec->audblk.fsnroffst[4] &&
!p_a52dec->audblk.cplfsnroffst && !p_a52dec->audblk.lfefsnroffst) {
memset(p_a52dec->audblk.fbw_bap,0,sizeof(u16) * 256 * 5);
memset(p_a52dec->audblk.cpl_bap,0,sizeof(u16) * 256);
memset(p_a52dec->audblk.lfe_bap,0,sizeof(u16) * 7);
return;
}
for (i = 0; i < p_a52dec->bsi.nfchans; i++) {
start = 0;
end = p_a52dec->audblk.endmant[i] ;
fgain = fastgain[p_a52dec->audblk.fgaincod[i]];
snroffset = (((p_a52dec->audblk.csnroffst - 15) << 4) + p_a52dec->audblk.fsnroffst[i]) << 2;
fastleak = 0;
slowleak = 0;
ba_compute_psd (&p_a52dec->bit_allocate, start, end, p_a52dec->audblk.fbw_exp[i]);
ba_compute_excitation (&p_a52dec->bit_allocate, start, end , fgain, fastleak, slowleak, 0);
ba_compute_mask (&p_a52dec->bit_allocate, start, end, p_a52dec->syncinfo.fscod,
p_a52dec->audblk.deltbae[i],
p_a52dec->audblk.deltnseg[i],
p_a52dec->audblk.deltoffst[i],
p_a52dec->audblk.deltba[i],
p_a52dec->audblk.deltlen[i]);
ba_compute_bap (&p_a52dec->bit_allocate, start, end, snroffset, p_a52dec->audblk.fbw_bap[i]);
}
if (p_a52dec->audblk.cplinu) {
start = p_a52dec->audblk.cplstrtmant;
end = p_a52dec->audblk.cplendmant;
fgain = fastgain[p_a52dec->audblk.cplfgaincod];
snroffset = (((p_a52dec->audblk.csnroffst - 15) << 4) + p_a52dec->audblk.cplfsnroffst) << 2 ;
fastleak = (p_a52dec->audblk.cplfleak << 8) + 768;
slowleak = (p_a52dec->audblk.cplsleak << 8) + 768;
ba_compute_psd (&p_a52dec->bit_allocate, start, end, p_a52dec->audblk.cpl_exp);
ba_compute_excitation (&p_a52dec->bit_allocate, start, end , fgain, fastleak, slowleak, 0);
ba_compute_mask (&p_a52dec->bit_allocate, start, end, p_a52dec->syncinfo.fscod,
p_a52dec->audblk.cpldeltbae,
p_a52dec->audblk.cpldeltnseg,
p_a52dec->audblk.cpldeltoffst,
p_a52dec->audblk.cpldeltba,
p_a52dec->audblk.cpldeltlen);
ba_compute_bap (&p_a52dec->bit_allocate, start, end, snroffset, p_a52dec->audblk.cpl_bap);
}
if (p_a52dec->bsi.lfeon) {
start = 0;
end = 7;
fgain = fastgain[p_a52dec->audblk.lfefgaincod];
snroffset = (((p_a52dec->audblk.csnroffst - 15) << 4) + p_a52dec->audblk.lfefsnroffst) << 2 ;
fastleak = 0;
slowleak = 0;
ba_compute_psd (&p_a52dec->bit_allocate, start, end, p_a52dec->audblk.lfe_exp);
ba_compute_excitation (&p_a52dec->bit_allocate, start, end , fgain, fastleak, slowleak, 1);
ba_compute_mask (&p_a52dec->bit_allocate, start, end, p_a52dec->syncinfo.fscod, 2, 0, 0, 0, 0);
ba_compute_bap (&p_a52dec->bit_allocate, start, end, snroffset, p_a52dec->audblk.lfe_bap);
}
}
static void ba_compute_psd (bit_allocate_t * p_bit, s16 start, s16 end, s16 exps[])
{
int bin,j,k;
s16 lastbin = 0;
/* Map the exponents into dBs */
for (bin=start; bin<end; bin++) {
p_bit->psd[bin] = (3072 - (exps[bin] << 7));
}
/* Integrate the psd function over each bit allocation band */
j = start;
k = masktab[start];
do {
lastbin = min_value(bndtab[k] + bndsz[k], end);
p_bit->bndpsd[k] = p_bit->psd[j];
j++;
for (; j < lastbin; j++) {
p_bit->bndpsd[k] = logadd(p_bit->bndpsd[k],p_bit->psd[j]);
}
k++;
} while (end > lastbin);
}
static void ba_compute_excitation (bit_allocate_t * p_bit, s16 start, s16 end,
s16 fgain, s16 fastleak, s16 slowleak, s16 is_lfe)
{
int bin;
s16 bndstrt;
s16 bndend;
s16 lowcomp = 0;
s16 begin = 0;
/* Compute excitation function */
bndstrt = masktab[start];
bndend = masktab[end - 1] + 1;
if (bndstrt == 0) { /* For fbw and lfe channels */
lowcomp = calc_lowcomp(lowcomp, p_bit->bndpsd[0], p_bit->bndpsd[1], 0);
p_bit->excite[0] = p_bit->bndpsd[0] - fgain - lowcomp;
lowcomp = calc_lowcomp(lowcomp, p_bit->bndpsd[1], p_bit->bndpsd[2], 1);
p_bit->excite[1] = p_bit->bndpsd[1] - fgain - lowcomp;
begin = 7 ;
/* Note: Do not call calc_lowcomp() for the last band of the lfe channel, (bin = 6) */
for (bin = 2; bin < 7; bin++) {
if (!(is_lfe && (bin == 6)))
lowcomp = calc_lowcomp (lowcomp, p_bit->bndpsd[bin], p_bit->bndpsd[bin+1], bin);
fastleak = p_bit->bndpsd[bin] - fgain;
slowleak = p_bit->bndpsd[bin] - p_bit->sgain;
p_bit->excite[bin] = fastleak - lowcomp;
if (!(is_lfe && (bin == 6))) {
if (p_bit->bndpsd[bin] <=
p_bit->bndpsd[bin+1])
{
begin = bin + 1 ;
break;
}
}
}
for (bin = begin; bin < min_value(bndend, 22); bin++) {
if (!(is_lfe && (bin == 6)))
lowcomp = calc_lowcomp (lowcomp, p_bit->bndpsd[bin],
p_bit->bndpsd[bin+1], bin);
fastleak -= p_bit->fdecay ;
fastleak = max_value(fastleak, p_bit->bndpsd[bin] - fgain);
slowleak -= p_bit->sdecay ;
slowleak = max_value(slowleak, p_bit->bndpsd[bin] - p_bit->sgain);
p_bit->excite[bin] = max_value(fastleak - lowcomp, slowleak);
}
begin = 22;
} else { /* For coupling channel */
begin = bndstrt;
}
for (bin = begin; bin < bndend; bin++) {
fastleak -= p_bit->fdecay;
fastleak = max_value(fastleak, p_bit->bndpsd[bin] - fgain);
slowleak -= p_bit->sdecay;
slowleak = max_value(slowleak, p_bit->bndpsd[bin] - p_bit->sgain);
p_bit->excite[bin] = max_value(fastleak, slowleak) ;
}
}
static void ba_compute_mask (bit_allocate_t * p_bit, s16 start, s16 end, u16 fscod,
u16 deltbae, u16 deltnseg, u16 deltoffst[],
u16 deltba[], u16 deltlen[])
{
int bin,k;
s16 bndstrt;
s16 bndend;
s16 delta;
bndstrt = masktab[start];
bndend = masktab[end - 1] + 1;
/* Compute the masking curve */
for (bin = bndstrt; bin < bndend; bin++) {
if (p_bit->bndpsd[bin] < p_bit->dbknee) {
p_bit->excite[bin] += ((p_bit->dbknee - p_bit->bndpsd[bin]) >> 2);
}
p_bit->mask[bin] = max_value(p_bit->excite[bin], hth[fscod][bin]);
}
/* Perform delta bit modulation if necessary */
if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) {
s16 band = 0;
s16 seg = 0;
for (seg = 0; seg < deltnseg+1; seg++) {
band += deltoffst[seg];
if (deltba[seg] >= 4) {
delta = (deltba[seg] - 3) << 7;
} else {
delta = (deltba[seg] - 4) << 7;
}
for (k = 0; k < deltlen[seg]; k++) {
p_bit->mask[band] += delta;
band++;
}
}
}
}
static void ba_compute_bap (bit_allocate_t * p_bit, s16 start, s16 end, s16 snroffset,
s16 bap[])
{
int i,j,k;
s16 lastbin = 0;
s16 address = 0;
/* Compute the bit allocation pointer for each bin */
i = start;
j = masktab[start];
do {
lastbin = min_value(bndtab[j] + bndsz[j], end);
p_bit->mask[j] -= snroffset;
p_bit->mask[j] -= p_bit->floor;
if (p_bit->mask[j] < 0)
p_bit->mask[j] = 0;
p_bit->mask[j] &= 0x1fe0;
p_bit->mask[j] += p_bit->floor;
for (k = i; k < lastbin; k++) {
address = (p_bit->psd[i] - p_bit->mask[j]) >> 5;
address = min_value(63, max_value(0, address));
bap[i] = baptab[address];
i++;
}
j++;
} while (end > lastbin);
}

View File

@ -0,0 +1,129 @@
/*****************************************************************************
* decoder.c: core A52 decoder
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: decoder.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Michel Lespinasse <walken@zoy.org>
* Aaron Holtzman <aholtzma@engr.uvic.ca>
*
* 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 <string.h> /* memcpy() */
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include "imdct.h"
#include "downmix.h"
#include "adec.h" /* a52dec_thread_t */
#include "internal.h"
static const float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 };
static const float smixlev_lut[4] = { 0.707, 0.500, 0.0 , 0.500 };
int E_( a52_init )(a52dec_t * p_a52dec)
{
p_a52dec->mantissa.lfsr_state = 1; /* dither_gen initialization */
E_( imdct_init )(p_a52dec->p_imdct) ;
return 0;
}
int decode_frame (a52dec_t * p_a52dec, s16 * buffer)
{
int i;
if (parse_bsi (p_a52dec))
{
msg_Warn( p_a52dec->p_fifo, "parse error" );
parse_auxdata (p_a52dec);
return 1;
}
/* compute downmix parameters
* downmix to tow channels for now */
p_a52dec->dm_par.clev = 0.0;
p_a52dec->dm_par.slev = 0.0;
p_a52dec->dm_par.unit = 1.0;
if (p_a52dec->bsi.acmod & 0x1) /* have center */
p_a52dec->dm_par.clev = cmixlev_lut[p_a52dec->bsi.cmixlev];
if (p_a52dec->bsi.acmod & 0x4) /* have surround channels */
p_a52dec->dm_par.slev = smixlev_lut[p_a52dec->bsi.surmixlev];
p_a52dec->dm_par.unit /= 1.0 + p_a52dec->dm_par.clev + p_a52dec->dm_par.slev;
p_a52dec->dm_par.clev *= p_a52dec->dm_par.unit;
p_a52dec->dm_par.slev *= p_a52dec->dm_par.unit;
for (i = 0; i < 6; i++) {
/* Initialize freq/time sample storage */
memset(p_a52dec->samples, 0, sizeof(float) * 256 *
(p_a52dec->bsi.nfchans + p_a52dec->bsi.lfeon));
if( p_a52dec->p_fifo->b_die || p_a52dec->p_fifo->b_error )
{
return 1;
}
if( parse_audblk( p_a52dec, i ) )
{
msg_Warn( p_a52dec->p_fifo, "audioblock error" );
parse_auxdata( p_a52dec );
return 1;
}
if( p_a52dec->p_fifo->b_die || p_a52dec->p_fifo->b_error )
{
return 1;
}
if( exponent_unpack( p_a52dec ) )
{
msg_Warn( p_a52dec->p_fifo, "unpack error" );
parse_auxdata( p_a52dec );
return 1;
}
bit_allocate (p_a52dec);
mantissa_unpack (p_a52dec);
if( p_a52dec->p_fifo->b_die || p_a52dec->p_fifo->b_error )
{
return 1;
}
if (p_a52dec->bsi.acmod == 0x2)
{
rematrix (p_a52dec);
}
imdct (p_a52dec, buffer);
buffer += 2 * 256;
}
parse_auxdata (p_a52dec);
return 0;
}

View File

@ -0,0 +1,385 @@
/*****************************************************************************
* decoder.h : A52 decoder interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: decoder.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@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.
*****************************************************************************/
/**** A52 decoder API - public A52 decoder structures */
typedef struct a52dec_s a52dec_t;
typedef struct sync_info_s {
int sample_rate; /* sample rate in Hz */
int frame_size; /* frame size in bytes */
int bit_rate; /* nominal bit rate in kbps */
} sync_info_t;
/**** A52 decoder API - functions publically provided by the A52 decoder ****/
int E_( a52_init )(a52dec_t * p_a52dec);
int sync_frame (a52dec_t * p_a52dec, sync_info_t * p_sync_info);
int decode_frame (a52dec_t * p_a52dec, s16 * buffer);
/**** EVERYTHING AFTER THIS POINT IS PRIVATE ! DO NOT USE DIRECTLY ****/
/**** A52 decoder internal structures ****/
/* The following structures are filled in by their corresponding parse_*
* functions. See http://www.atsc.org/Standards/A52/a_52.pdf for
* full details on each field. Indented fields are used to denote
* conditional fields.
*/
typedef struct syncinfo_s {
/* Sync word == 0x0B77 */
/* u16 syncword; */
/* crc for the first 5/8 of the sync block */
/* u16 crc1; */
/* Stream Sampling Rate (kHz) 0 = 48, 1 = 44.1, 2 = 32, 3 = reserved */
u16 fscod;
/* Frame size code */
u16 frmsizecod;
/* Information not in the AC-3 bitstream, but derived */
/* Frame size in 16 bit words */
u16 frame_size;
/* Bit rate in kilobits */
//u16 bit_rate;
} syncinfo_t;
typedef struct bsi_s {
/* Bit stream identification == 0x8 */
u16 bsid;
/* Bit stream mode */
u16 bsmod;
/* Audio coding mode */
u16 acmod;
/* If we're using the centre channel then */
/* centre mix level */
u16 cmixlev;
/* If we're using the surround channel then */
/* surround mix level */
u16 surmixlev;
/* If we're in 2/0 mode then */
/* Dolby surround mix level - NOT USED - */
u16 dsurmod;
/* Low frequency effects on */
u16 lfeon;
/* Dialogue Normalization level */
u16 dialnorm;
/* Compression exists */
u16 compre;
/* Compression level */
u16 compr;
/* Language code exists */
u16 langcode;
/* Language code */
u16 langcod;
/* Audio production info exists*/
u16 audprodie;
u16 mixlevel;
u16 roomtyp;
/* If we're in dual mono mode (acmod == 0) then extra stuff */
u16 dialnorm2;
u16 compr2e;
u16 compr2;
u16 langcod2e;
u16 langcod2;
u16 audprodi2e;
u16 mixlevel2;
u16 roomtyp2;
/* Copyright bit */
u16 copyrightb;
/* Original bit */
u16 origbs;
/* Timecode 1 exists */
u16 timecod1e;
/* Timecode 1 */
u16 timecod1;
/* Timecode 2 exists */
u16 timecod2e;
/* Timecode 2 */
u16 timecod2;
/* Additional bit stream info exists */
u16 addbsie;
/* Additional bit stream length - 1 (in bytes) */
u16 addbsil;
/* Additional bit stream information (max 64 bytes) */
u8 addbsi[64];
/* Information not in the AC-3 bitstream, but derived */
/* Number of channels (excluding LFE)
* Derived from acmod */
u16 nfchans;
} bsi_t;
/* more pain */
typedef struct audblk_s {
/* block switch bit indexed by channel num */
u16 blksw[5];
/* dither enable bit indexed by channel num */
u16 dithflag[5];
/* dynamic range gain exists */
u16 dynrnge;
/* dynamic range gain */
u16 dynrng;
/* if acmod==0 then */
/* dynamic range 2 gain exists */
u16 dynrng2e;
/* dynamic range 2 gain */
u16 dynrng2;
/* coupling strategy exists */
u16 cplstre;
/* coupling in use */
u16 cplinu;
/* channel coupled */
u16 chincpl[5];
/* if acmod==2 then */
/* Phase flags in use */
u16 phsflginu;
/* coupling begin frequency code */
u16 cplbegf;
/* coupling end frequency code */
u16 cplendf;
/* coupling band structure bits */
u16 cplbndstrc[18];
/* Do coupling co-ords exist for this channel? */
u16 cplcoe[5];
/* Master coupling co-ordinate */
u16 mstrcplco[5];
/* Per coupling band coupling co-ordinates */
u16 cplcoexp[5][18];
u16 cplcomant[5][18];
/* Phase flags for dual mono */
u16 phsflg[18];
/* Is there a rematrixing strategy */
u16 rematstr;
/* Rematrixing bits */
u16 rematflg[4];
/* Coupling exponent strategy */
u16 cplexpstr;
/* Exponent strategy for full bandwidth channels */
u16 chexpstr[5];
/* Exponent strategy for lfe channel */
u16 lfeexpstr;
/* Channel bandwidth for independent channels */
u16 chbwcod[5];
/* The absolute coupling exponent */
u16 cplabsexp;
/* Coupling channel exponents (D15 mode gives 18 * 12 /3 encoded exponents */
u16 cplexps[18 * 12 / 3];
/* Sanity checking constant */
u32 magic2;
/* fbw channel exponents */
u16 exps[5][252 / 3];
/* channel gain range */
u16 gainrng[5];
/* low frequency exponents */
u16 lfeexps[3];
/* Bit allocation info */
u16 baie;
/* Slow decay code */
u16 sdcycod;
/* Fast decay code */
u16 fdcycod;
/* Slow gain code */
u16 sgaincod;
/* dB per bit code */
u16 dbpbcod;
/* masking floor code */
u16 floorcod;
/* SNR offset info */
u16 snroffste;
/* coarse SNR offset */
u16 csnroffst;
/* coupling fine SNR offset */
u16 cplfsnroffst;
/* coupling fast gain code */
u16 cplfgaincod;
/* fbw fine SNR offset */
u16 fsnroffst[5];
/* fbw fast gain code */
u16 fgaincod[5];
/* lfe fine SNR offset */
u16 lfefsnroffst;
/* lfe fast gain code */
u16 lfefgaincod;
/* Coupling leak info */
u16 cplleake;
/* coupling fast leak initialization */
u16 cplfleak;
/* coupling slow leak initialization */
u16 cplsleak;
/* delta bit allocation info */
u16 deltbaie;
/* coupling delta bit allocation exists */
u16 cpldeltbae;
/* fbw delta bit allocation exists */
u16 deltbae[5];
/* number of cpl delta bit segments */
u16 cpldeltnseg;
/* coupling delta bit allocation offset */
u16 cpldeltoffst[8];
/* coupling delta bit allocation length */
u16 cpldeltlen[8];
/* coupling delta bit allocation length */
u16 cpldeltba[8];
/* number of delta bit segments */
u16 deltnseg[5];
/* fbw delta bit allocation offset */
u16 deltoffst[5][8];
/* fbw delta bit allocation length */
u16 deltlen[5][8];
/* fbw delta bit allocation length */
u16 deltba[5][8];
/* skip length exists */
u16 skiple;
/* skip length */
u16 skipl;
/* channel mantissas */
// u16 chmant[5][256];
/* coupling mantissas */
float cpl_flt[ 256 ];
// u16 cplmant[256];
/* coupling mantissas */
// u16 lfemant[7];
/* -- Information not in the bitstream, but derived thereof -- */
/* Number of coupling sub-bands */
u16 ncplsubnd;
/* Number of combined coupling sub-bands
* Derived from ncplsubnd and cplbndstrc */
u16 ncplbnd;
/* Number of exponent groups by channel
* Derived from strmant, endmant */
u16 nchgrps[5];
/* Number of coupling exponent groups
* Derived from cplbegf, cplendf, cplexpstr */
u16 ncplgrps;
/* End mantissa numbers of fbw channels */
u16 endmant[5];
/* Start and end mantissa numbers for the coupling channel */
u16 cplstrtmant;
u16 cplendmant;
/* Decoded exponent info */
u16 fbw_exp[5][256];
u16 cpl_exp[256];
u16 lfe_exp[7];
/* Bit allocation pointer results */
u16 fbw_bap[5][256];
/* FIXME?? figure out exactly how many entries there should be (253-37?) */
u16 cpl_bap[256];
u16 lfe_bap[7];
} audblk_t;
/* Everything you wanted to know about band structure */
/*
* The entire frequency domain is represented by 256 real
* floating point fourier coefficients. Only the lower 253
* coefficients are actually utilized however. We use arrays
* of 256 to be efficient in some cases.
*
* The 5 full bandwidth channels (fbw) can have their higher
* frequencies coupled together. These coupled channels then
* share their high frequency components.
*
* This coupling band is broken up into 18 sub-bands starting
* at mantissa number 37. Each sub-band is 12 bins wide.
*
* There are 50 bit allocation sub-bands which cover the entire
* frequency range. The sub-bands are of non-uniform width, and
* approximate a 1/6 octave scale.
*/
typedef struct bit_allocate_s
{
s16 psd[256];
s16 bndpsd[256];
s16 excite[256];
s16 mask[256];
s16 sdecay;
s16 fdecay;
s16 sgain;
s16 dbknee;
s16 floor;
} bit_allocate_t;
/* These store the persistent state of the packed mantissas */
typedef struct mantissa_s
{
float q_1[2];
float q_2[2];
float q_4[1];
s32 q_1_pointer;
s32 q_2_pointer;
s32 q_4_pointer;
u16 lfsr_state;
} mantissa_t;
struct a52dec_s
{
float * samples;
void * samples_orig; /* pointer before memalign */
imdct_t * imdct;
void * imdct_orig; /* pointer before memalign */
/*
* Input properties
*/
/* The bit stream structure handles the PES stream at the bit level */
bit_stream_t bit_stream;
int i_available;
unsigned int total_bits_read; /* temporary */
/*
* Decoder properties
*/
syncinfo_t syncinfo;
bsi_t bsi;
audblk_t audblk;
dm_par_t dm_par;
bit_allocate_t bit_allocate;
mantissa_t mantissa;
downmix_t downmix;
};

View File

@ -1,8 +1,8 @@
/*****************************************************************************
* ac3_downmix.h : AC3 downmix types
* downmix.h : A52 downmix types
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: ac3_downmix.h,v 1.6 2002/07/31 20:56:50 sam Exp $
* $Id: downmix.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Renaud Dartus <reno@videolan.org>

View File

@ -0,0 +1,4 @@
.dep
*.lo
*.o.*
*.lo.*

View File

@ -0,0 +1,3 @@
downmix_SOURCES = downmix.c downmix_c.c
downmixsse_SOURCES = downmix.c downmix_sse.c
downmix3dn_SOURCES = downmix.c downmix_3dn.c

View File

@ -0,0 +1,73 @@
/*****************************************************************************
* downmix.c : A52 downmix module
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: downmix.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Renaud Dartus <reno@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include "../downmix.h"
#include "downmix_common.h"
/*****************************************************************************
* Module initializer
*****************************************************************************/
static int Open ( vlc_object_t *p_this )
{
downmix_t *p_downmix = (downmix_t *)p_this;
p_downmix->pf_downmix_3f_2r_to_2ch = E_( downmix_3f_2r_to_2ch );
p_downmix->pf_downmix_3f_1r_to_2ch = E_( downmix_3f_1r_to_2ch );
p_downmix->pf_downmix_2f_2r_to_2ch = E_( downmix_2f_2r_to_2ch );
p_downmix->pf_downmix_2f_1r_to_2ch = E_( downmix_2f_1r_to_2ch );
p_downmix->pf_downmix_3f_0r_to_2ch = E_( downmix_3f_0r_to_2ch );
p_downmix->pf_stream_sample_2ch_to_s16 = E_( stream_sample_2ch_to_s16 );
p_downmix->pf_stream_sample_1ch_to_s16 = E_( stream_sample_1ch_to_s16 );
return VLC_SUCCESS;
}
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
#ifdef MODULE_NAME_IS_downmix
set_description( _("A52 downmix module") );
set_capability( "downmix", 50 );
add_shortcut( "c" );
#elif defined( MODULE_NAME_IS_downmixsse )
set_description( _("SSE A52 downmix module") );
set_capability( "downmix", 200 );
add_shortcut( "sse" );
#elif defined( MODULE_NAME_IS_downmix3dn )
set_description( _("3D Now! A52 downmix module") );
set_capability( "downmix", 200 );
add_shortcut( "3dn" );
add_shortcut( "3dnow" );
#endif
set_callbacks( Open, NULL );
vlc_module_end();

View File

@ -0,0 +1,307 @@
/*****************************************************************************
* downmix_3dn.c: accelerated 3D Now! A52 downmix functions
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
* $Id: downmix_3dn.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Renaud Dartus <reno@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 <vlc/vlc.h>
#include "../downmix.h"
static const float sqrt2_3dn __asm__ ("sqrt2_3dn") = 0.7071068;
void E_( downmix_3f_2r_to_2ch ) (float * samples, dm_par_t * dm_par)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n" /* loop counter */
"movd (%%ecx), %%mm5\n" /* unit */
"punpckldq %%mm5, %%mm5\n" /* unit | unit */
"movd 4(%%ecx), %%mm6\n" /* clev */
"punpckldq %%mm6, %%mm6\n" /* clev | clev */
"movd 8(%%ecx), %%mm7\n" /* slev */
"punpckldq %%mm7, %%mm7\n" /* slev | slev */
".align 16\n"
".loop:\n"
"movq (%%eax), %%mm0\n" /* left */
"movq 2048(%%eax), %%mm1\n" /* right */
"movq 1024(%%eax), %%mm2\n" /* center */
"movq 3072(%%eax), %%mm3\n" /* leftsur */
"movq 4096(%%eax), %%mm4\n" /* rightsur */
"pfmul %%mm5, %%mm0\n"
"pfmul %%mm5, %%mm1\n"
"pfmul %%mm6, %%mm2\n"
"pfadd %%mm2, %%mm0\n"
"pfadd %%mm2, %%mm1\n"
"pfmul %%mm7, %%mm3\n"
"pfmul %%mm7, %%mm4\n"
"pfadd %%mm3, %%mm0\n"
"pfadd %%mm4, %%mm1\n"
"movq %%mm0, (%%eax)\n"
"movq %%mm1, 1024(%%eax)\n"
"addl $8, %%eax\n"
"decl %%ebx\n"
"jnz .loop\n"
"popl %%ebx\n"
"femms\n"
: "=a" (samples)
: "a" (samples), "c" (dm_par));
}
void E_( downmix_2f_2r_to_2ch ) (float *samples, dm_par_t * dm_par)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n" /* loop counter */
"movd (%%ecx), %%mm5\n" /* unit */
"punpckldq %%mm5, %%mm5\n" /* unit | unit */
"movd 8(%%ecx), %%mm7\n" /* slev */
"punpckldq %%mm7, %%mm7\n" /* slev | slev */
".align 16\n"
".loop3:\n"
"movq (%%eax), %%mm0\n" /* left */
"movq 1024(%%eax), %%mm1\n" /* right */
"movq 2048(%%eax), %%mm3\n" /* leftsur */
"movq 3072(%%eax), %%mm4\n" /* rightsur */
"pfmul %%mm5, %%mm0\n"
"pfmul %%mm5, %%mm1\n"
"pfmul %%mm7, %%mm3\n"
"pfmul %%mm7, %%mm4\n"
"pfadd %%mm3, %%mm0\n"
"pfadd %%mm4, %%mm1\n"
"movq %%mm0, (%%eax)\n"
"movq %%mm1, 1024(%%eax)\n"
"addl $8, %%eax\n"
"decl %%ebx\n"
"jnz .loop3\n"
"popl %%ebx\n"
"femms\n"
: "=a" (samples)
: "a" (samples), "c" (dm_par));
}
void E_( downmix_3f_1r_to_2ch ) (float *samples, dm_par_t * dm_par)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n" /* loop counter */
"movd (%%ecx), %%mm5\n" /* unit */
"punpckldq %%mm5, %%mm5\n" /* unit | unit */
"movd 4(%%ecx), %%mm6\n" /* clev */
"punpckldq %%mm6, %%mm6\n" /* clev | clev */
"movd 8(%%ecx), %%mm7\n" /* slev */
"punpckldq %%mm7, %%mm7\n" /* slev | slev */
".align 16\n"
".loop4:\n"
"movq (%%eax), %%mm0\n" /* left */
"movq 2048(%%eax), %%mm1\n" /* right */
"movq 1024(%%eax), %%mm2\n" /* center */
"movq 3072(%%eax), %%mm3\n" /* sur */
"pfmul %%mm5, %%mm0\n"
"pfmul %%mm5, %%mm1\n"
"pfmul %%mm6, %%mm2\n"
"pfadd %%mm2, %%mm0\n"
"pfmul %%mm7, %%mm3\n"
"pfadd %%mm2, %%mm1\n"
"pfsub %%mm3, %%mm0\n"
"pfadd %%mm3, %%mm1\n"
"movq %%mm0, (%%eax)\n"
"movq %%mm1, 1024(%%eax)\n"
"addl $8, %%eax\n"
"decl %%ebx\n"
"jnz .loop4\n"
"popl %%ebx\n"
"femms\n"
: "=a" (samples)
: "a" (samples), "c" (dm_par));
}
void E_( downmix_2f_1r_to_2ch ) (float *samples, dm_par_t * dm_par)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n" /* loop counter */
"movd (%%ecx), %%mm5\n" /* unit */
"punpckldq %%mm5, %%mm5\n" /* unit | unit */
"movd 8(%%ecx), %%mm7\n" /* slev */
"punpckldq %%mm7, %%mm7\n" /* slev | slev */
".align 16\n"
".loop5:\n"
"movq (%%eax), %%mm0\n" /* left */
"movq 1024(%%eax), %%mm1\n" /* right */
"movq 2048(%%eax), %%mm3\n" /* sur */
"pfmul %%mm5, %%mm0\n"
"pfmul %%mm5, %%mm1\n"
"pfmul %%mm7, %%mm3\n"
"pfsub %%mm3, %%mm0\n"
"pfadd %%mm3, %%mm1\n"
"movq %%mm0, (%%eax)\n"
"movq %%mm1, 1024(%%eax)\n"
"addl $8, %%eax\n"
"decl %%ebx\n"
"jnz .loop5\n"
"popl %%ebx\n"
"femms\n"
: "=a" (samples)
: "a" (samples), "c" (dm_par));
}
void E_( downmix_3f_0r_to_2ch ) (float *samples, dm_par_t * dm_par)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n" /* loop counter */
"movd (%%ecx), %%mm5\n" /* unit */
"punpckldq %%mm5, %%mm5\n" /* unit | unit */
"movd 4(%%ecx), %%mm6\n" /* clev */
"punpckldq %%mm6, %%mm6\n" /* clev | clev */
".align 16\n"
".loop6:\n"
"movq (%%eax), %%mm0\n" /*left */
"movq 2048(%%eax), %%mm1\n" /* right */
"movq 1024(%%eax), %%mm2\n" /* center */
"pfmul %%mm5, %%mm0\n"
"pfmul %%mm5, %%mm1\n"
"pfmul %%mm6, %%mm2\n"
"pfadd %%mm2, %%mm0\n"
"pfadd %%mm2, %%mm1\n"
"movq %%mm0, (%%eax)\n"
"movq %%mm1, 1024(%%eax)\n"
"addl $8, %%eax\n"
"decl %%ebx\n"
"jnz .loop6\n"
"popl %%ebx\n"
"femms\n"
: "=a" (samples)
: "a" (samples), "c" (dm_par));
}
void E_( stream_sample_1ch_to_s16 ) (s16 *s16_samples, float *left)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"pushl %%edx\n"
"movl $sqrt2_3dn, %%edx\n"
"movd (%%edx), %%mm7\n"
"punpckldq %%mm7, %%mm7\n" /* sqrt2 | sqrt2 */
"movl $128, %%ebx\n"
".align 16\n"
".loop2:\n"
"movq (%%ecx), %%mm0\n" /* c1 | c0 */
"pfmul %%mm7, %%mm0\n"
"pf2id %%mm0, %%mm0\n" /* c1 c0 --> mm0, int_32 */
"packssdw %%mm0, %%mm0\n" /* c1 c1 c0 c0 --> mm0, int_16 */
"movq %%mm0, (%%eax)\n"
"addl $8, %%eax\n"
"addl $8, %%ecx\n"
"decl %%ebx\n"
"jnz .loop2\n"
"popl %%edx\n"
"popl %%ebx\n"
"femms\n"
: "=a" (s16_samples), "=c" (left)
: "a" (s16_samples), "c" (left));
}
void E_( stream_sample_2ch_to_s16 ) (s16 *s16_samples, float *left, float *right)
{
__asm__ __volatile__ (
".align 16\n"
"pushl %%ebx\n"
"movl $128, %%ebx\n"
".align 16\n"
".loop1:\n"
"movq (%%ecx), %%mm0\n" /* l1 | l0 */
"movq (%%edx), %%mm1\n" /* r1 | r0 */
"movq %%mm0, %%mm2\n" /* l1 | l0 */
"punpckldq %%mm1, %%mm0\n" /* r0 | l0 */
"punpckhdq %%mm1, %%mm2\n" /* r1 | l1 */
"pf2id %%mm0, %%mm0\n" /* r0 l0 --> mm0, int_32 */
"pf2id %%mm2, %%mm2\n" /* r0 l0 --> mm0, int_32 */
"packssdw %%mm2, %%mm0\n" /* r1 l1 r0 l0 --> mm0, int_16 */
"movq %%mm0, (%%eax)\n"
"movq %%mm2, 8(%%eax)\n"
"addl $8, %%eax\n"
"addl $8, %%ecx\n"
"addl $8, %%edx\n"
"decl %%ebx\n"
"jnz .loop1\n"
"popl %%ebx\n"
"femms\n"
: "=a" (s16_samples), "=c" (left), "=d" (right)
: "a" (s16_samples), "c" (left), "d" (right));
}

View File

@ -0,0 +1,151 @@
/*****************************************************************************
* downmix_c.c: A52 downmix functions in C
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
* $Id: downmix_c.c,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Renaud Dartus <reno@videolan.org>
* Aaron Holtzman <aholtzma@engr.uvic.ca>
*
* 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 <string.h> /* memcpy() */
#include <vlc/vlc.h>
#include "../downmix.h"
void E_( downmix_3f_2r_to_2ch ) (float *samples, dm_par_t *dm_par)
{
int i;
float *left, *right, *center, *left_sur, *right_sur;
float left_tmp, right_tmp;
left = samples;
center = samples + 256;
right = samples + 256*2;
left_sur = samples + 256*3;
right_sur = samples + 256*4;
for (i=0; i < 256; i++) {
left_tmp = dm_par->unit * *left + dm_par->clev * *center + dm_par->slev * *left_sur++;
right_tmp = dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++;
*left++ = left_tmp;
*center++ = right_tmp;
}
}
void E_( downmix_2f_2r_to_2ch ) (float *samples, dm_par_t *dm_par)
{
int i;
float *left, *right, *left_sur, *right_sur;
float left_tmp, right_tmp;
left = &samples[0];
right = &samples[256];
left_sur = &samples[512];
right_sur = &samples[768];
for (i = 0; i < 256; i++) {
left_tmp = dm_par->unit * *left + dm_par->slev * *left_sur++;
right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++;
*left++ = left_tmp;
*right++ = right_tmp;
}
}
void E_( downmix_3f_1r_to_2ch ) (float *samples, dm_par_t *dm_par)
{
int i;
float *left, *right, *center, *right_sur;
float left_tmp, right_tmp;
left = &samples[0];
right = &samples[512];
center = &samples[256];
right_sur = &samples[768];
for (i = 0; i < 256; i++) {
left_tmp = dm_par->unit * *left + dm_par->clev * *center - dm_par->slev * *right_sur;
right_tmp= dm_par->unit * *right++ + dm_par->clev * *center + dm_par->slev * *right_sur++;
*left++ = left_tmp;
*center++ = right_tmp;
}
}
void E_( downmix_2f_1r_to_2ch ) (float *samples, dm_par_t *dm_par)
{
int i;
float *left, *right, *right_sur;
float left_tmp, right_tmp;
left = &samples[0];
right = &samples[256];
right_sur = &samples[512];
for (i = 0; i < 256; i++) {
left_tmp = dm_par->unit * *left - dm_par->slev * *right_sur;
right_tmp= dm_par->unit * *right + dm_par->slev * *right_sur++;
*left++ = left_tmp;
*right++ = right_tmp;
}
}
void E_( downmix_3f_0r_to_2ch ) (float *samples, dm_par_t *dm_par)
{
int i;
float *left, *right, *center;
float left_tmp, right_tmp;
left = &samples[0];
center = &samples[256];
right = &samples[512];
for (i = 0; i < 256; i++) {
left_tmp = dm_par->unit * *left + dm_par->clev * *center;
right_tmp= dm_par->unit * *right++ + dm_par->clev * *center;
*left++ = left_tmp;
*center++ = right_tmp;
}
}
void E_( stream_sample_2ch_to_s16 ) (s16 *out_buf, float *left, float *right)
{
int i;
for (i=0; i < 256; i++) {
*out_buf++ = (s16) (*left++);
*out_buf++ = (s16) (*right++);
}
}
void E_( stream_sample_1ch_to_s16 ) (s16 *out_buf, float *center)
{
int i;
float tmp;
for (i=0; i < 256; i++) {
*out_buf++ = tmp = (s16) (0.7071f * *center++);
*out_buf++ = tmp;
}
}

View File

@ -0,0 +1,32 @@
/*****************************************************************************
* downmix_common.h: A52 downmix functions headers
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
* $Id: downmix_common.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Authors: Renaud Dartus <reno@videolan.org>
* Aaron Holtzman <aholtzma@engr.uvic.ca>
*
* 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.
*****************************************************************************/
void E_( downmix_3f_2r_to_2ch ) ( float *, dm_par_t * );
void E_( downmix_2f_2r_to_2ch ) ( float *, dm_par_t * );
void E_( downmix_3f_1r_to_2ch ) ( float *, dm_par_t * );
void E_( downmix_2f_1r_to_2ch ) ( float *, dm_par_t * );
void E_( downmix_3f_0r_to_2ch ) ( float *, dm_par_t * );
void E_( stream_sample_2ch_to_s16 ) ( s16 *, float *, float * );
void E_( stream_sample_1ch_to_s16 ) ( s16 *, float * );

Some files were not shown because too many files have changed in this diff Show More