mirror of https://code.videolan.org/videolan/vlc
* ./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:
parent
e5a6cfeafb
commit
19ea8feb6d
215
Makefile
215
Makefile
|
@ -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
|
||||
|
|
|
@ -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) $@
|
||||
|
|
|
@ -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
|
||||
|
|
149
configure.in
149
configure.in
|
@ -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)
|
||||
|
|
|
@ -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.)
|
||||
|
||||
|
||||
|
||||
|
|
@ -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.
|
|
@ -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.
|
||||
|
||||
|
|
@ -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])
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1,3 @@
|
|||
file_SOURCES = file.c
|
||||
udp_SOURCES = udp.c
|
||||
http_SOURCES = http.c
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
dvd_SOURCES = dvd.c access.c demux.c seek.c es.c ifo.c udf.c summary.c
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 );
|
||||
|
||||
|
|
@ -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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 * );
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 * );
|
||||
|
|
@ -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
|
|
@ -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 );
|
||||
|
|
@ -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
|
|
@ -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 );
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 * );
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
dvdplay_SOURCES = dvd.c access.c demux.c intf.c es.c tools.c
|
|
@ -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;
|
||||
}
|
|
@ -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 * );
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 * );
|
|
@ -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();
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
@ -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 * );
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 );
|
|
@ -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;
|
||||
}
|
|
@ -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* );
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
dvdread_SOURCES = dvdread.c input.c
|
|
@ -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
|
@ -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;
|
||||
|
|
@ -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();
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
satellite_SOURCES = satellite.c access.c dvb.c
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
|
@ -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();
|
||||
|
|
@ -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 );
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
vcd_SOURCES = vcd.c cdrom.c
|
|
@ -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
|
|
@ -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 * );
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
alsa_SOURCES = alsa.c
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
arts_SOURCES = arts.c
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
dsp_SOURCES = dsp.c
|
|
@ -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 );
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
esd_SOURCES = esd.c
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
waveout_SOURCES = waveout.c
|
|
@ -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 );
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
a52_SOURCES = a52.c
|
|
@ -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; */
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -0,0 +1 @@
|
|||
a52old_SOURCES = a52old.c decoder.c parse.c exponent.c bit_allocate.c mantissa.c rematrix.c imdct.c
|
|
@ -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; */
|
||||
}
|
||||
}
|
||||
|
|
@ -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 */
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
@ -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>
|
|
@ -0,0 +1,4 @@
|
|||
.dep
|
||||
*.lo
|
||||
*.o.*
|
||||
*.lo.*
|
|
@ -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
|
|
@ -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();
|
||||
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue