Commit 19ea8feb authored by Sam Hocevar's avatar Sam Hocevar

* ./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.
parent e5a6cfea
...@@ -13,165 +13,6 @@ endif ...@@ -13,165 +13,6 @@ endif
# Objects and files # 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 # C Objects
# #
...@@ -238,10 +79,10 @@ CPP_DEP := $(CPP_OBJ:%.o=.dep/%.dpp) ...@@ -238,10 +79,10 @@ CPP_DEP := $(CPP_OBJ:%.o=.dep/%.dpp)
# Translate plugin names # Translate plugin names
# #
ifneq (,$(PLUGINS)) 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 endif
ifneq (,$(BUILTINS)) 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 endif
# #
...@@ -295,9 +136,9 @@ po-clean: ...@@ -295,9 +136,9 @@ po-clean:
plugins-clean: plugins-clean:
for dir in $(PLUGINS_DIR) ; do \ for dir in $(PLUGINS_DIR) ; do \
( cd plugins/$${dir} \ ( cd modules/$${dir} \
&& $(MAKE) -f ../../Makefile.modules clean ) ; done && $(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: vlc-clean:
rm -f $(C_OBJ) $(CPP_OBJ) rm -f $(C_OBJ) $(CPP_OBJ)
...@@ -348,7 +189,7 @@ endif ...@@ -348,7 +189,7 @@ endif
plugins-install: plugins-install:
mkdir -p $(DESTDIR)$(libdir)/vlc mkdir -p $(DESTDIR)$(libdir)/vlc
ifneq (,$(PLUGINS)) ifneq (,$(PLUGINS))
$(INSTALL) $(PLUGINS:%=plugins/%.so) $(DESTDIR)$(libdir)/vlc $(INSTALL) $(PLUGINS:%=modules/%.so) $(DESTDIR)$(libdir)/vlc
endif endif
plugins-uninstall: plugins-uninstall:
...@@ -357,7 +198,7 @@ plugins-uninstall: ...@@ -357,7 +198,7 @@ plugins-uninstall:
builtins-install: builtins-install:
mkdir -p $(DESTDIR)$(libdir)/vlc mkdir -p $(DESTDIR)$(libdir)/vlc
ifneq (,$(BUILTINS)) ifneq (,$(BUILTINS))
$(INSTALL) -m 644 $(BUILTINS:%=plugins/%.a) $(DESTDIR)$(libdir)/vlc $(INSTALL) -m 644 $(BUILTINS:%=modules/%.a) $(DESTDIR)$(libdir)/vlc
endif endif
builtins-uninstall: builtins-uninstall:
...@@ -410,13 +251,13 @@ dist: ...@@ -410,13 +251,13 @@ dist:
find debian -mindepth 1 -maxdepth 1 -type d | \ find debian -mindepth 1 -maxdepth 1 -type d | \
while read i ; do rm -Rf tmp/vlc/$$i ; done while read i ; do rm -Rf tmp/vlc/$$i ; done
# Copy .c .h .in .cpp .m and .glade files # 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 do cp $$i tmp/vlc/$$i ; done
# Grmbl... special case... # Grmbl... special case...
for i in API BUGS DESIGN TODO ; \ 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 # 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 do cp $$i tmp/vlc/$$i ; done
# Copy extra programs and documentation # Copy extra programs and documentation
cp -a extras/* tmp/vlc/extras cp -a extras/* tmp/vlc/extras
...@@ -472,12 +313,12 @@ package-win32: ...@@ -472,12 +313,12 @@ package-win32:
for file in AUTHORS COPYING ChangeLog README FAQ TODO ; \ for file in AUTHORS COPYING ChangeLog README FAQ TODO ; \
do cp $$file tmp/$${file}.txt ; \ do cp $$file tmp/$${file}.txt ; \
unix2dos tmp/$${file}.txt ; done unix2dos tmp/$${file}.txt ; done
mkdir tmp/plugins mkdir tmp/modules
cp $(PLUGINS:%=plugins/%.so) tmp/plugins/ cp $(PLUGINS:%=modules/%.so) tmp/modules/
# don't include these two # 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)) 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 endif
mkdir tmp/share mkdir tmp/share
for file in default8x16.psf default8x9.psf ; \ for file in default8x16.psf default8x9.psf ; \
...@@ -504,9 +345,9 @@ package-beos: ...@@ -504,9 +345,9 @@ package-beos:
cp AUTHORS COPYING ChangeLog README FAQ TODO tmp/vlc/ cp AUTHORS COPYING ChangeLog README FAQ TODO tmp/vlc/
for file in default8x16.psf default8x9.psf ; \ for file in default8x16.psf default8x9.psf ; \
do cp share/$$file tmp/vlc/share/ ; done do cp share/$$file tmp/vlc/share/ ; done
mkdir tmp/vlc/plugins mkdir tmp/vlc/modules
cp $(PLUGINS:%=plugins/%.so) tmp/vlc/plugins/ cp $(PLUGINS:%=modules/%.so) tmp/vlc/modules/
strip $(PLUGINS:%=tmp/vlc/plugins/%.so) strip $(PLUGINS:%=tmp/vlc/modules/%.so)
# Create package # Create package
mv tmp/vlc tmp/vlc-${VERSION} mv tmp/vlc tmp/vlc-${VERSION}
(cd tmp ; find vlc-${VERSION} | \ (cd tmp ; find vlc-${VERSION} | \
...@@ -546,10 +387,10 @@ ifneq (,$(findstring darwin,$(SYS))) ...@@ -546,10 +387,10 @@ ifneq (,$(findstring darwin,$(SYS)))
cd extras/MacOSX ; pbxbuild | grep -v '^ ' | grep -v '^\t' | grep -v "^$$" cd extras/MacOSX ; pbxbuild | grep -v '^ ' | grep -v '^\t' | grep -v "^$$"
cp -r extras/MacOSX/build/vlc.bundle ./vlc.app cp -r extras/MacOSX/build/vlc.bundle ./vlc.app
$(INSTALL) -d vlc.app/Contents/MacOS/share $(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/ $(INSTALL) vlc vlc.app/Contents/MacOS/
ifneq (,$(PLUGINS)) ifneq (,$(PLUGINS))
$(INSTALL) $(PLUGINS:%=plugins/%.so) vlc.app/Contents/MacOS/plugins $(INSTALL) $(PLUGINS:%=modules/%.so) vlc.app/Contents/MacOS/modules
endif endif
$(INSTALL) -m 644 share/*.psf vlc.app/Contents/MacOS/share $(INSTALL) -m 644 share/*.psf vlc.app/Contents/MacOS/share
endif endif
...@@ -564,7 +405,7 @@ src/misc/modules_builtin.h: Makefile.opts Makefile Makefile.config ...@@ -564,7 +405,7 @@ src/misc/modules_builtin.h: Makefile.opts Makefile Makefile.config
@rm -f $@ && cp $@.in $@ @rm -f $@ && cp $@.in $@
ifneq (,$(BUILTINS)) ifneq (,$(BUILTINS))
@for i in $(BUILTINS) ; do \ @for i in $(BUILTINS) ; do \
echo "int vlc_entry__"$$i"( module_t* );" >>$@; \ echo "int vlc_entry__"`basename $$i`"( module_t* );" >>$@; \
done done
@echo "" >> $@ ; @echo "" >> $@ ;
endif endif
...@@ -573,7 +414,7 @@ endif ...@@ -573,7 +414,7 @@ endif
@echo " { \\" >> $@ ; @echo " { \\" >> $@ ;
ifneq (,$(BUILTINS)) ifneq (,$(BUILTINS))
@for i in $(BUILTINS) ; do \ @for i in $(BUILTINS) ; do \
echo " ALLOCATE_BUILTIN("$$i"); \\" >> $@ ; \ echo " ALLOCATE_BUILTIN("`basename $$i`"); \\" >> $@ ; \
done done
endif endif
@echo " } while( 0 );" >> $@ ; @echo " } while( 0 );" >> $@ ;
...@@ -634,19 +475,11 @@ lib/libvlc.a: Makefile.opts Makefile.dep Makefile $(LIBVLC_OBJ) ...@@ -634,19 +475,11 @@ lib/libvlc.a: Makefile.opts Makefile.dep Makefile $(LIBVLC_OBJ)
#lib/libvlc.so: 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 $@ # $(CC) -shared $(LIBVLC_OBJ) $(LDFLAGS) $(vlc_LDFLAGS) -o $@
# builtins: Makefile.modules Makefile.opts Makefile.dep Makefile $(BUILTIN_OBJ)
# Plugins target
#
plugins: Makefile.modules Makefile.opts Makefile.dep Makefile $(PLUGIN_OBJ) 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/%=../%)
# modules/%.a modules/%.so: $(H_OBJ) FORCE
# Built-in modules target @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@')
#
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/%=../%)
# #
# Mozilla plugin target # Mozilla plugin target
......
...@@ -13,7 +13,7 @@ include Makefile ...@@ -13,7 +13,7 @@ include Makefile
# #
# Analyze the target we are asked to build # 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) suff := $(shell echo $(MAKECMDGOALS) | sed 's@.*\.@@' | tr so/a lo/o)
# #
...@@ -23,6 +23,9 @@ SRC_C := $(filter %.c,$($(module_name)_SOURCES)) ...@@ -23,6 +23,9 @@ SRC_C := $(filter %.c,$($(module_name)_SOURCES))
SRC_CPP := $(filter %.cpp,$($(module_name)_SOURCES)) SRC_CPP := $(filter %.cpp,$($(module_name)_SOURCES))
SRC_M := $(filter %.m,$($(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)) ifeq (lo,$(suff))
extra_CFLAGS := $(plugins_CFLAGS) $($(module_name)_CFLAGS) \ extra_CFLAGS := $(plugins_CFLAGS) $($(module_name)_CFLAGS) \
-DMODULE_NAME=$(module_name) -DMODULE_NAME_IS_$(module_name) \ -DMODULE_NAME=$(module_name) -DMODULE_NAME_IS_$(module_name) \
...@@ -57,17 +60,17 @@ clean: ...@@ -57,17 +60,17 @@ clean:
FORCE: FORCE:
$(OBJ_ALL): ../../Makefile.modules ../../Makefile.dep ../../Makefile ../../Makefile.opts Makefile $(OBJ_ALL): $(PARENT)/Makefile.modules $(PARENT)/Makefile.dep $(PARENT)/Makefile $(PARENT)/Makefile.opts Makefile
$(OBJ_ALL): $(H_DEP:%=../../include/%) $(OBJ_ALL): $(H_DEP:%=$(PARENT)/include/%)
$(C_DEP): %.d: FORCE $(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 $(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 $(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): .dep/%.d
$(SRC_C:%.c=%.$(suff).$(module_name)): %.$(suff).$(module_name): %.c $(SRC_C:%.c=%.$(suff).$(module_name)): %.$(suff).$(module_name): %.c
...@@ -83,10 +86,10 @@ $(SRC_M:%.m=%.$(suff).$(module_name)): %.$(suff).$(module_name): %.m ...@@ -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 # foo_CUSTOM lets us override all target rules for foo.so and foo.a
ifeq (,$($(module_name)_CUSTOM)) 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 $@ $(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 $@ rm -f $@
ar rc $@ $(OBJ_ALL) ar rc $@ $(OBJ_ALL)
$(RANLIB) $@ $(RANLIB) $@
......
...@@ -60,7 +60,7 @@ mozilla_CFLAGS = @mozilla_CFLAGS@ ...@@ -60,7 +60,7 @@ mozilla_CFLAGS = @mozilla_CFLAGS@
a52_CFLAGS = @a52_CFLAGS@ a52_CFLAGS = @a52_CFLAGS@
arts_CFLAGS = @arts_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@ directx_CFLAGS = @directx_CFLAGS@
dvd_CFLAGS = @dvd_CFLAGS@ dvd_CFLAGS = @dvd_CFLAGS@
dvdread_CFLAGS = @dvdread_CFLAGS@ dvdread_CFLAGS = @dvdread_CFLAGS@
...@@ -76,7 +76,7 @@ kde_CFLAGS = @kde_CFLAGS@ ...@@ -76,7 +76,7 @@ kde_CFLAGS = @kde_CFLAGS@
mad_CFLAGS = @mad_CFLAGS@ mad_CFLAGS = @mad_CFLAGS@
memcpyaltivec_CFLAGS = @memcpyaltivec_CFLAGS@ memcpyaltivec_CFLAGS = @memcpyaltivec_CFLAGS@
motionaltivec_CFLAGS = @motionaltivec_CFLAGS@ motionaltivec_CFLAGS = @motionaltivec_CFLAGS@
mpeg_ts_dvbpsi_CFLAGS = @mpeg_ts_dvbpsi_CFLAGS@ ts_dvbpsi_CFLAGS = @ts_dvbpsi_CFLAGS@
qt_CFLAGS = @qt_CFLAGS@ qt_CFLAGS = @qt_CFLAGS@
sdl_CFLAGS = @sdl_CFLAGS@ sdl_CFLAGS = @sdl_CFLAGS@
x11_CFLAGS = @x11_CFLAGS@ x11_CFLAGS = @x11_CFLAGS@
...@@ -95,7 +95,7 @@ aa_LDFLAGS = @aa_LDFLAGS@ ...@@ -95,7 +95,7 @@ aa_LDFLAGS = @aa_LDFLAGS@
alsa_LDFLAGS = @alsa_LDFLAGS@ alsa_LDFLAGS = @alsa_LDFLAGS@
arts_LDFLAGS = @arts_LDFLAGS@ arts_LDFLAGS = @arts_LDFLAGS@
beos_LDFLAGS = @beos_LDFLAGS@ beos_LDFLAGS = @beos_LDFLAGS@
chroma_i420_rgb_LDFLAGS = @chroma_i420_rgb_LDFLAGS@ i420_rgb_LDFLAGS = @i420_rgb_LDFLAGS@
directx_LDFLAGS = @directx_LDFLAGS@ directx_LDFLAGS = @directx_LDFLAGS@
dsp_LDFLAGS = @dsp_LDFLAGS@ dsp_LDFLAGS = @dsp_LDFLAGS@
dvd_LDFLAGS = @dvd_LDFLAGS@ dvd_LDFLAGS = @dvd_LDFLAGS@
...@@ -103,7 +103,7 @@ dvdread_LDFLAGS = @dvdread_LDFLAGS@ ...@@ -103,7 +103,7 @@ dvdread_LDFLAGS = @dvdread_LDFLAGS@
dvdplay_LDFLAGS = @dvdplay_LDFLAGS@ dvdplay_LDFLAGS = @dvdplay_LDFLAGS@
esd_LDFLAGS = @esd_LDFLAGS@ esd_LDFLAGS = @esd_LDFLAGS@
familiar_LDFLAGS = @familiar_LDFLAGS@ familiar_LDFLAGS = @familiar_LDFLAGS@
filter_distort_LDFLAGS = @filter_distort_LDFLAGS@ distort_LDFLAGS = @distort_LDFLAGS@
ffmpeg_LDFLAGS = @ffmpeg_LDFLAGS@ ffmpeg_LDFLAGS = @ffmpeg_LDFLAGS@
mp4_LDFLAGS = @mp4_LDFLAGS@ mp4_LDFLAGS = @mp4_LDFLAGS@
ggi_LDFLAGS = @ggi_LDFLAGS@ ggi_LDFLAGS = @ggi_LDFLAGS@
...@@ -123,7 +123,7 @@ macosx_LDFLAGS = @macosx_LDFLAGS@ ...@@ -123,7 +123,7 @@ macosx_LDFLAGS = @macosx_LDFLAGS@
mad_LDFLAGS = @mad_LDFLAGS@ mad_LDFLAGS = @mad_LDFLAGS@
memcpyaltivec_LDFLAGS = @memcpyaltivec_LDFLAGS@ memcpyaltivec_LDFLAGS = @memcpyaltivec_LDFLAGS@
motionaltivec_LDFLAGS = @motionaltivec_LDFLAGS@ motionaltivec_LDFLAGS = @motionaltivec_LDFLAGS@
mpeg_ts_dvbpsi_LDFLAGS = @mpeg_ts_dvbpsi_LDFLAGS@ ts_dvbpsi_LDFLAGS = @ts_dvbpsi_LDFLAGS@
ncurses_LDFLAGS = @ncurses_LDFLAGS@ ncurses_LDFLAGS = @ncurses_LDFLAGS@
qnx_LDFLAGS = @qnx_LDFLAGS@ qnx_LDFLAGS = @qnx_LDFLAGS@
qt_LDFLAGS = @qt_LDFLAGS@ qt_LDFLAGS = @qt_LDFLAGS@
...@@ -250,16 +250,10 @@ endif ...@@ -250,16 +250,10 @@ endif
endif 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 # 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 # Debugging and profiling support
......
This diff is collapsed.
This diff is collapsed.
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.)
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.
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.
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])
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.
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 @@ ...@@ -2,7 +2,7 @@
* audio_output.h : audio output thread interface * audio_output.h : audio output thread interface
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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> * Authors: Michel Kaempf <maxx@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr> * Cyril Deguet <asmax@via.ecp.fr>
...@@ -163,7 +163,7 @@ struct aout_thread_t ...@@ -163,7 +163,7 @@ struct aout_thread_t
#define AOUT_FMT_S8 0x00000040 #define AOUT_FMT_S8 0x00000040
#define AOUT_FMT_U16_LE 0x00000080 /* Little endian U16 */ #define AOUT_FMT_U16_LE 0x00000080 /* Little endian U16 */
#define AOUT_FMT_U16_BE 0x00000100 /* Big 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 #ifdef WORDS_BIGENDIAN
#define AOUT_FMT_S16_NE AOUT_FMT_S16_BE #define AOUT_FMT_S16_NE AOUT_FMT_S16_BE
...@@ -171,8 +171,8 @@ struct aout_thread_t ...@@ -171,8 +171,8 @@ struct aout_thread_t
#define AOUT_FMT_S16_NE AOUT_FMT_S16_LE #define AOUT_FMT_S16_NE AOUT_FMT_S16_LE
#endif #endif
/* Number of samples in an AC3 frame */ /* Number of samples in an A52 frame */
#define AC3_FRAME_SIZE 1536 #define A52_FRAME_SIZE 1536
/* Size of a frame for spdif output */ /* Size of a frame for spdif output */
#define SPDIF_FRAME_SIZE 6144 #define SPDIF_FRAME_SIZE 6144
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* input_ext-dec.h: structures exported to the VideoLAN decoders * input_ext-dec.h: structures exported to the VideoLAN decoders
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * 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> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Michel Kaempf <maxx@via.ecp.fr> * Michel Kaempf <maxx@via.ecp.fr>
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#define MPEG2_VIDEO_ES 0x02 #define MPEG2_VIDEO_ES 0x02
#define MPEG1_AUDIO_ES 0x03 #define MPEG1_AUDIO_ES 0x03
#define MPEG2_AUDIO_ES 0x04 #define MPEG2_AUDIO_ES 0x04
#define AC3_AUDIO_ES 0x81 #define A52_AUDIO_ES 0x81
/* These ones might violate the norm : */ /* These ones might violate the norm : */
#define DVD_SPU_ES 0x82 #define DVD_SPU_ES 0x82
#define LPCM_AUDIO_ES 0x83 #define LPCM_AUDIO_ES 0x83
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* control the pace of reading. * control the pace of reading.
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* *
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
*/ */
/* FIXME ! */ /* FIXME ! */
#define REQUESTED_MPEG 1 #define REQUESTED_MPEG 1
#define REQUESTED_AC3 2 #define REQUESTED_A52 2
#define REQUESTED_LPCM 3 #define REQUESTED_LPCM 3
#define REQUESTED_NOAUDIO 255 #define REQUESTED_NOAUDIO 255
......
.dep
*.lo
*.o.*
*.lo.*
file_SOURCES = file.c
udp_SOURCES = udp.c
http_SOURCES = http.c
.dep
*.lo
*.o.*
*.lo.*
dvd_SOURCES = dvd.c access.c demux.c seek.c es.c ifo.c udf.c summary.c
This diff is collapsed.
/* 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: Stphane 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;
}
This diff is collapsed.
/*****************************************************************************
* 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;
/*****************************************************************************
* 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 );
This diff is collapsed.
/* 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 * );
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* 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: Stphane 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 );
This diff is collapsed.
/*****************************************************************************
* 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 );
This diff is collapsed.
/*****************************************************************************
* 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 * );
dvdplay_SOURCES = dvd.c access.c demux.c intf.c es.c tools.c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
dvdread_SOURCES = dvdread.c input.c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
satellite_SOURCES = satellite.c access.c dvb.c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
vcd_SOURCES = vcd.c cdrom.c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment