From: Sam Hocevar Date: Sun, 4 Aug 2002 17:23:44 +0000 (+0000) Subject: * ./modules/*: moved plugins to the new tree. Yet untested builds include X-Git-Tag: 0.5.0~1153 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=19ea8feb6db01c1deafb19f35ecee8eff81aeb02;p=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. --- diff --git a/Makefile b/Makefile index ea4b1f7a85..4798c7dbb5 100644 --- a/Makefile +++ b/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 -# +builtins: Makefile.modules Makefile.opts Makefile.dep Makefile $(BUILTIN_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/%=../%) -# -# 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/%=../%) +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 diff --git a/Makefile.modules b/Makefile.modules index 5a04c8df2b..3d9f603ec7 100644 --- a/Makefile.modules +++ b/Makefile.modules @@ -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) $@ diff --git a/Makefile.opts.in b/Makefile.opts.in index f9d6de878c..768ed80be8 100644 --- a/Makefile.opts.in +++ b/Makefile.opts.in @@ -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 diff --git a/configure b/configure index 782b5c1680..d3ee7331b2 100755 --- a/configure +++ b/configure @@ -5386,7 +5386,7 @@ echo "$ac_t""$ac_cv_c_omit_frame_pointer" 1>&6 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 echo $ac_n "checking if \$CC accepts -bundle -undefined error -lcc_dynamic""... $ac_c" 1>&6 @@ -5532,29 +5532,35 @@ case "x${target_cpu}" in esac 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" - -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" +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" + +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" echo $ac_n "checking if \$CC groks MMX inline assembly""... $ac_c" 1>&6 -echo "configure:5545: checking if \$CC groks MMX inline assembly" >&5 +echo "configure:5551: checking if \$CC groks MMX inline assembly" >&5 if eval "test \"`echo '$''{'ac_cv_mmx_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS}" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5564: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mmx_inline=yes else @@ -5572,20 +5578,20 @@ if test "x${ac_cv_mmx_inline}" != "xno"; then fi echo $ac_n "checking if \$CC groks MMX EXT inline assembly""... $ac_c" 1>&6 -echo "configure:5576: checking if \$CC groks MMX EXT inline assembly" >&5 +echo "configure:5582: checking if \$CC groks MMX EXT inline assembly" >&5 if eval "test \"`echo '$''{'ac_cv_mmxext_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS}" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5595: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mmxext_inline=yes else @@ -5603,20 +5609,20 @@ if test "x${ac_cv_mmxext_inline}" != "xno"; then fi echo $ac_n "checking if \$CC groks 3D Now! inline assembly""... $ac_c" 1>&6 -echo "configure:5607: checking if \$CC groks 3D Now! inline assembly" >&5 +echo "configure:5613: checking if \$CC groks 3D Now! inline assembly" >&5 if eval "test \"`echo '$''{'ac_cv_3dnow_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS}" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5626: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_3dnow_inline=yes else @@ -5638,20 +5644,20 @@ EOF fi echo $ac_n "checking if \$CC groks SSE inline assembly""... $ac_c" 1>&6 -echo "configure:5642: checking if \$CC groks SSE inline assembly" >&5 +echo "configure:5648: checking if \$CC groks SSE inline assembly" >&5 if eval "test \"`echo '$''{'ac_cv_sse_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS}" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5661: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_sse_inline=yes else @@ -5676,20 +5682,20 @@ fi # we should be able to remove this test with future versions of mingw32 if test "x${SYS}" != "xmingw32"; then echo $ac_n "checking if \$CC groks AltiVec inline assembly""... $ac_c" 1>&6 -echo "configure:5680: checking if \$CC groks AltiVec inline assembly" >&5 +echo "configure:5686: checking if \$CC groks AltiVec inline assembly" >&5 if eval "test \"`echo '$''{'ac_cv_altivec_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS}" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5699: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_altivec_inline=yes else @@ -5698,14 +5704,14 @@ else rm -rf conftest* CFLAGS="${save_CFLAGS} -Wa,-m7400" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_altivec_inline="-Wa,-m7400" else @@ -5736,21 +5742,21 @@ EOF fi echo $ac_n "checking if \$CC groks AltiVec C extensions""... $ac_c" 1>&6 -echo "configure:5740: checking if \$CC groks AltiVec C extensions" >&5 +echo "configure:5746: checking if \$CC groks AltiVec C extensions" >&5 if eval "test \"`echo '$''{'ac_cv_c_altivec'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else CFLAGS="${save_CFLAGS} -faltivec" # Darwin test cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5760: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_altivec=-faltivec else @@ -5761,14 +5767,14 @@ else # Linux/PPC test CFLAGS="${save_CFLAGS} ${idctaltivec_CFLAGS} -fvec" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:5778: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_altivec="-fvec" else @@ -5798,20 +5804,20 @@ EOF fi echo $ac_n "checking if linker needs -framework vecLib""... $ac_c" 1>&6 -echo "configure:5802: checking if linker needs -framework vecLib" >&5 +echo "configure:5808: checking if linker needs -framework vecLib" >&5 if eval "test \"`echo '$''{'ac_cv_ld_altivec'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else LDFLAGS="${vlc_LDFLAGS} -framework vecLib" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:5821: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_ld_altivec=yes else @@ -5943,17 +5949,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:5947: checking for $ac_hdr" >&5 +echo "configure:5953: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:5957: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:5963: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5973,7 +5979,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then cat >> confdefs.h <&6 @@ -5984,7 +5990,7 @@ done else echo $ac_n "checking for libdvdcss.a in ${with_dvdcss_tree}""... $ac_c" 1>&6 -echo "configure:5988: checking for libdvdcss.a in ${with_dvdcss_tree}" >&5 +echo "configure:5994: checking for libdvdcss.a in ${with_dvdcss_tree}" >&5 real_dvdcss_tree="`cd ${with_dvdcss_tree} 2>/dev/null && pwd`" if test "x${real_dvdcss_tree}" = "x" then @@ -5994,7 +6000,7 @@ echo "configure:5988: checking for libdvdcss.a in ${with_dvdcss_tree}" >&5 if test -f "${real_dvdcss_tree}/src/.libs/libdvdcss.a" then echo "$ac_t""${real_dvdcss_tree}/src/.libs/libdvdcss.a" 1>&6 - 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 @@ -6004,17 +6010,17 @@ echo "configure:5988: checking for libdvdcss.a in ${with_dvdcss_tree}" >&5 fi ;; xno) - PLUGINS="${PLUGINS} dvd" + PLUGINS="${PLUGINS} access/dvd/dvd" dvd_CFLAGS="${dvd_CFLAGS} -DGOD_DAMN_DMCA" dvd_LDFLAGS="${dvd_LDFLAGS} -ldl" ;; *) echo $ac_n "checking for dvdcss headers in ${with_dvdcss}""... $ac_c" 1>&6 -echo "configure:6014: checking for dvdcss headers in ${with_dvdcss}" >&5 +echo "configure:6020: checking for dvdcss headers in ${with_dvdcss}" >&5 if test -f ${with_dvdcss}/include/dvdcss/dvdcss.h then echo "$ac_t""yes" 1>&6 - 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 @@ -6052,17 +6058,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6056: checking for $ac_hdr" >&5 +echo "configure:6062: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6066: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6072: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6084,17 +6090,17 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then EOF cat > conftest.$ac_ext < int main() { void foo() { int i=DVD_VIDEO_LB_LEN; } ; return 0; } EOF -if { (eval echo configure:6095: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:6101: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* - PLUGINS="${PLUGINS} dvdread" + PLUGINS="${PLUGINS} access/dvdread/dvdread" dvdread_LDFLAGS="${dvdread_LDFLAGS} ${test_LDFLAGS} -ldvdread" dvdread_CFLAGS="${dvdread_CFLAGS} ${test_CFLAGS}" @@ -6156,17 +6162,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6160: checking for $ac_hdr" >&5 +echo "configure:6166: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6170: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6187,7 +6193,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - PLUGINS="${PLUGINS} dvdplay" + PLUGINS="${PLUGINS} access/dvdplay/dvdplay" dvdplay_LDFLAGS="${dvdplay_LDFLAGS} ${test_LDFLAGS} -ldvdplay -ldvdread" dvdplay_CFLAGS="${dvdplay_CFLAGS} ${test_CFLAGS}" @@ -6238,17 +6244,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6242: checking for $ac_hdr" >&5 +echo "configure:6248: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6252: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6258: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6268,8 +6274,8 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then cat >> confdefs.h <&6 fi @@ -6277,7 +6283,7 @@ done else echo $ac_n "checking for libdvbpsi.a in ${with_dvbpsi_tree}""... $ac_c" 1>&6 -echo "configure:6281: checking for libdvbpsi.a in ${with_dvbpsi_tree}" >&5 +echo "configure:6287: checking for libdvbpsi.a in ${with_dvbpsi_tree}" >&5 real_dvbpsi_tree="`cd ${with_dvbpsi_tree} 2>/dev/null && pwd`" if test "x${real_dvbpsi_tree}" = "x" then @@ -6287,9 +6293,9 @@ echo "configure:6281: checking for libdvbpsi.a in ${with_dvbpsi_tree}" >&5 if test -f "${real_dvbpsi_tree}/src/.libs/libdvbpsi.a" then echo "$ac_t""${real_dvbpsi_tree}/src/.libs/libdvbpsi.a" 1>&6 - 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 echo "$ac_t""no" 1>&6 { echo "configure: error: cannot find ${real_dvbpsi_tree}/src/.libs/libdvbpsi.a, make sure you compiled libdvbpsi in ${with_dvbpsi_tree}" 1>&2; exit 1; } @@ -6300,7 +6306,7 @@ echo "configure:6281: checking for libdvbpsi.a in ${with_dvbpsi_tree}" >&5 ;; *) echo $ac_n "checking for dvbpsi headers in ${with_dvbpsi}""... $ac_c" 1>&6 -echo "configure:6304: checking for dvbpsi headers in ${with_dvbpsi}" >&5 +echo "configure:6310: checking for dvbpsi headers in ${with_dvbpsi}" >&5 if test "x${with_dvbpsi}" = "x" then test_LDFLAGS="" @@ -6312,17 +6318,17 @@ echo "configure:6304: checking for dvbpsi headers in ${with_dvbpsi}" >&5 CPPFLAGS="${save_CPPFLAGS} ${test_CFLAGS}" ac_safe=`echo "dvbpsi/dr.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for dvbpsi/dr.h""... $ac_c" 1>&6 -echo "configure:6316: checking for dvbpsi/dr.h" >&5 +echo "configure:6322: checking for dvbpsi/dr.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6326: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6332: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6339,9 +6345,9 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 - 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}" else echo "$ac_t""no" 1>&6 @@ -6368,7 +6374,7 @@ fi if test "x${enable_vcd}" != "xno" then cat > conftest.$ac_ext < EOF @@ -6376,14 +6382,14 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "cdrom_msf0" >/dev/null 2>&1; then rm -rf conftest* - PLUGINS="${PLUGINS} vcd" + PLUGINS="${PLUGINS} access/vcd/vcd" fi rm -f conftest* cat > conftest.$ac_ext < EOF @@ -6391,7 +6397,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "ioc_toc_header " >/dev/null 2>&1; then rm -rf conftest* - PLUGINS="${PLUGINS} vcd" + PLUGINS="${PLUGINS} access/vcd/vcd" cat >> confdefs.h <<\EOF #define HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H 1 EOF @@ -6403,7 +6409,7 @@ rm -f conftest* if test "x${SYS}" = "xbsdi" then - PLUGINS="${PLUGINS} vcd" + PLUGINS="${PLUGINS} access/vcd/vcd" fi if test "x${SYS}" = "xdarwin" @@ -6418,7 +6424,7 @@ if test "${enable_satellite+set}" = set; then enableval="$enable_satellite" if test "x${enable_satellite}" = "xyes" then - PLUGINS="${PLUGINS} satellite" + PLUGINS="${PLUGINS} access/satellite/satellite" fi fi @@ -6427,12 +6433,12 @@ if test "x${SYS}" != "xnto" && test "x${SYS}" != "xmingw32" then have_ipv6=0 echo $ac_n "checking for inet_pton""... $ac_c" 1>&6 -echo "configure:6431: checking for inet_pton" >&5 +echo "configure:6437: checking for inet_pton" >&5 if eval "test \"`echo '$''{'ac_cv_func_inet_pton'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6465: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_inet_pton=yes" else @@ -6474,7 +6480,7 @@ else echo "$ac_t""no" 1>&6 echo $ac_n "checking for inet_pton in -lresolv""... $ac_c" 1>&6 -echo "configure:6478: checking for inet_pton in -lresolv" >&5 +echo "configure:6484: checking for inet_pton in -lresolv" >&5 ac_lib_var=`echo resolv'_'inet_pton | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6482,7 +6488,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lresolv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6518,9 +6524,9 @@ fi fi echo $ac_n "checking for sockaddr_in6 in netinet/in.h""... $ac_c" 1>&6 -echo "configure:6522: checking for sockaddr_in6 in netinet/in.h" >&5 +echo "configure:6528: checking for sockaddr_in6 in netinet/in.h" >&5 cat > conftest.$ac_ext < EOF @@ -6535,15 +6541,15 @@ fi rm -f conftest* if test x$have_ipv6 = x1; then - PLUGINS="${PLUGINS} ipv6" + PLUGINS="${PLUGINS} misc/network/ipv6" fi fi if test "x${SYS}" = "xmingw32" then echo $ac_n "checking for getaddrinfo in ws2tcpip.h""... $ac_c" 1>&6 -echo "configure:6545: checking for getaddrinfo in ws2tcpip.h" >&5 +echo "configure:6551: checking for getaddrinfo in ws2tcpip.h" >&5 cat > conftest.$ac_ext < EOF @@ -6551,7 +6557,7 @@ if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "addrinfo" >/dev/null 2>&1; then rm -rf conftest* echo "$ac_t""yes" 1>&6 - PLUGINS="${PLUGINS} ipv6" + PLUGINS="${PLUGINS} misc/network/ipv6" else rm -rf conftest* echo "$ac_t""no" 1>&6 @@ -6568,7 +6574,7 @@ fi if test "x${enable_avi}" != "xno" then - PLUGINS="${PLUGINS} avi" + PLUGINS="${PLUGINS} demux/avi/avi" fi @@ -6614,7 +6620,7 @@ fi { echo "configure: error: ${with_mad_tree} directory doesn't exist" 1>&2; exit 1; } fi echo $ac_n "checking for mad.h in ${real_mad_tree}/libmad""... $ac_c" 1>&6 -echo "configure:6618: checking for mad.h in ${real_mad_tree}/libmad" >&5 +echo "configure:6624: checking for mad.h in ${real_mad_tree}/libmad" >&5 if test -f ${real_mad_tree}/libmad/mad.h then echo "$ac_t""yes" 1>&6 @@ -6622,7 +6628,7 @@ echo "configure:6618: checking for mad.h in ${real_mad_tree}/libmad" >&5 mad_LDFLAGS="${mad_LDFLAGS} -L${real_mad_tree}/libmad/.libs" LDFLAGS="${save_LDFLAGS} ${mad_LDFLAGS}" echo $ac_n "checking for mad_bit_init in -lmad""... $ac_c" 1>&6 -echo "configure:6626: checking for mad_bit_init in -lmad" >&5 +echo "configure:6632: checking for mad_bit_init in -lmad" >&5 ac_lib_var=`echo mad'_'mad_bit_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6630,7 +6636,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lmad $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6651: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6657,7 +6663,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - BUILTINS="${BUILTINS} mad" + BUILTINS="${BUILTINS} codec/mad/mad" mad_LDFLAGS="${mad_LDFLAGS} -lmad" else @@ -6678,17 +6684,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:6682: checking for $ac_hdr" >&5 +echo "configure:6688: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6692: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6698: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6716,7 +6722,7 @@ fi done echo $ac_n "checking for mad_bit_init in -lmad""... $ac_c" 1>&6 -echo "configure:6720: checking for mad_bit_init in -lmad" >&5 +echo "configure:6726: checking for mad_bit_init in -lmad" >&5 ac_lib_var=`echo mad'_'mad_bit_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6724,7 +6730,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lmad $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6745: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6751,7 +6757,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - PLUGINS="${PLUGINS} mad" + PLUGINS="${PLUGINS} codec/mad/mad" mad_LDFLAGS="${mad_LDFLAGS} -lmad" else echo "$ac_t""no" 1>&6 @@ -6792,7 +6798,7 @@ fi if test "x${with_ffmpeg_tree}" != "x" then echo $ac_n "checking for libavcodec.a in ${with_ffmpeg_tree}""... $ac_c" 1>&6 -echo "configure:6796: checking for libavcodec.a in ${with_ffmpeg_tree}" >&5 +echo "configure:6802: checking for libavcodec.a in ${with_ffmpeg_tree}" >&5 real_ffmpeg_tree="`cd ${with_ffmpeg_tree} 2>/dev/null && pwd`" if test "x${real_ffmpeg_tree}" = x then @@ -6802,7 +6808,7 @@ echo "configure:6796: checking for libavcodec.a in ${with_ffmpeg_tree}" >&5 if test -f "${real_ffmpeg_tree}/libavcodec/libavcodec.a" then echo "$ac_t""${real_ffmpeg_tree}/libavcodec/libavcodec.a" 1>&6 - 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 @@ -6813,7 +6819,7 @@ echo "configure:6796: checking for libavcodec.a in ${with_ffmpeg_tree}" >&5 CFLAGS="${save_CFLAGS} ${ffmpeg_CFLAGS}" LDFLAGS="${save_LDFLAGS} ${ffmpeg_LDFLAGS} -lm" echo $ac_n "checking for avcodec_init in -lavcodec""... $ac_c" 1>&6 -echo "configure:6817: checking for avcodec_init in -lavcodec" >&5 +echo "configure:6823: checking for avcodec_init in -lavcodec" >&5 ac_lib_var=`echo avcodec'_'avcodec_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6821,7 +6827,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lavcodec $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6842: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6848,7 +6854,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - BUILTINS="${BUILTINS} ffmpeg" + BUILTINS="${BUILTINS} codec/ffmpeg/ffmpeg" ffmpeg_LDFLAGS="${ffmpeg_LDFLAGS} -lavcodec -lm" else echo "$ac_t""no" 1>&6 @@ -6870,17 +6876,17 @@ if test "x${enable_mp4}" = "xyes" then ac_safe=`echo "zlib.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for zlib.h""... $ac_c" 1>&6 -echo "configure:6874: checking for zlib.h" >&5 +echo "configure:6880: checking for zlib.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6884: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6890: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -6897,7 +6903,7 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for inflateEnd in -lz""... $ac_c" 1>&6 -echo "configure:6901: checking for inflateEnd in -lz" >&5 +echo "configure:6907: checking for inflateEnd in -lz" >&5 ac_lib_var=`echo z'_'inflateEnd | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6905,7 +6911,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lz $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6926: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -6931,7 +6937,7 @@ LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - PLUGINS="${PLUGINS} mp4" + PLUGINS="${PLUGINS} demux/mp4/mp4" mp4_LDFLAGS="${mp4_LDFLAGS} -lz" else echo "$ac_t""no" 1>&6 @@ -6947,7 +6953,7 @@ fi if test "x${SYS}" = "xbeos" then - PLUGINS="${PLUGINS} beos" + PLUGINS="${PLUGINS} gui/beos/beos" fi # Check whether --enable-a52 or --disable-a52 was given. @@ -6973,7 +6979,7 @@ fi { echo "configure: error: ${with_a52_tree} directory doesn't exist" 1>&2; exit 1; } fi echo $ac_n "checking for a52.h in ${real_a52_tree}/include""... $ac_c" 1>&6 -echo "configure:6977: checking for a52.h in ${real_a52_tree}/include" >&5 +echo "configure:6983: checking for a52.h in ${real_a52_tree}/include" >&5 if test -f ${real_a52_tree}/include/a52.h then echo "$ac_t""yes" 1>&6 @@ -6981,7 +6987,7 @@ echo "configure:6977: checking for a52.h in ${real_a52_tree}/include" >&5 a52_LDFLAGS="${a52_LDFLAGS} -L${real_a52_tree}/liba52/.libs" LDFLAGS="${save_LDFLAGS} ${a52_LDFLAGS}" echo $ac_n "checking for a52_free in -la52""... $ac_c" 1>&6 -echo "configure:6985: checking for a52_free in -la52" >&5 +echo "configure:6991: checking for a52_free in -la52" >&5 ac_lib_var=`echo a52'_'a52_free | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -6989,7 +6995,7 @@ else ac_save_LIBS="$LIBS" LIBS="-la52 -lm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7010: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7016,7 +7022,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - BUILTINS="${BUILTINS} a52" + BUILTINS="${BUILTINS} codec/a52/a52" a52_LDFLAGS="${a52_LDFLAGS} -la52 -lm" a52_CFLAGS="${a52_CFLAGS} -DUSE_A52DEC_TREE" @@ -7041,17 +7047,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7045: checking for $ac_hdr" >&5 +echo "configure:7051: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7055: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7061: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7073,7 +7079,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then EOF echo $ac_n "checking for a52_free in -la52""... $ac_c" 1>&6 -echo "configure:7077: checking for a52_free in -la52" >&5 +echo "configure:7083: checking for a52_free in -la52" >&5 ac_lib_var=`echo a52'_'a52_free | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -7081,7 +7087,7 @@ else ac_save_LIBS="$LIBS" LIBS="-la52 -lm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7102: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7108,7 +7114,7 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 - BUILTINS="${BUILTINS} a52" + BUILTINS="${BUILTINS} codec/a52/a52" a52_LDFLAGS="${a52_LDFLAGS} -la52 -lm" a52_CFLAGS="${a52_CFLAGS}" @@ -7133,7 +7139,7 @@ fi if test "x${enable_cinepak}" != "xno" then - PLUGINS="${PLUGINS} cinepak" + PLUGINS="${PLUGINS} codec/cinepak/cinepak" fi # Check whether --enable-vorbis or --disable-vorbis was given. @@ -7148,17 +7154,17 @@ then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7152: checking for $ac_hdr" >&5 +echo "configure:7158: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7162: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7179,7 +7185,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - #PLUGINS="${PLUGINS} vorbis" + #PLUGINS="${PLUGINS} demux/ogg/ogg codec/vorbis/vorbis" vorbis_LDFLAGS="${vorbis_LDFLAGS} -lvorbis" else @@ -7210,17 +7216,17 @@ if test "x${enable_x11}" != "xno" && do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7214: checking for $ac_hdr" >&5 +echo "configure:7220: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7224: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7230: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7241,7 +7247,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - 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}" @@ -7266,17 +7272,17 @@ if test "x${enable_xvideo}" != "xno" && do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7270: checking for $ac_hdr" >&5 +echo "configure:7276: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7286: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7299,7 +7305,7 @@ EOF CFLAGS="${save_CFLAGS} -L${x_libraries} -lX11 -lXext" echo $ac_n "checking for XvPutImage in -lXv_pic""... $ac_c" 1>&6 -echo "configure:7303: checking for XvPutImage in -lXv_pic" >&5 +echo "configure:7309: checking for XvPutImage in -lXv_pic" >&5 ac_lib_var=`echo Xv_pic'_'XvPutImage | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -7307,7 +7313,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lXv_pic $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7334,13 +7340,13 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 # 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}" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for XvPutImage in -lXv""... $ac_c" 1>&6 -echo "configure:7344: checking for XvPutImage in -lXv" >&5 +echo "configure:7350: checking for XvPutImage in -lXv" >&5 ac_lib_var=`echo Xv'_'XvPutImage | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -7348,7 +7354,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lXv $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7375,12 +7381,13 @@ fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 # 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}" else echo "$ac_t""no" 1>&6 # Otherwise... well, do nothing. + : fi @@ -7418,7 +7425,7 @@ fi # Extract the first word of "sdl12-config", so it can be a program name with args. set dummy sdl12-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7422: checking for $ac_word" >&5 +echo "configure:7429: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_SDL12_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7458,7 +7465,7 @@ fi # Extract the first word of "sdl11-config", so it can be a program name with args. set dummy sdl11-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7462: checking for $ac_word" >&5 +echo "configure:7469: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_SDL11_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7499,7 +7506,7 @@ fi # Extract the first word of "sdl-config", so it can be a program name with args. set dummy sdl-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7503: checking for $ac_word" >&5 +echo "configure:7510: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_SDL_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7536,7 +7543,7 @@ fi 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}" @@ -7544,17 +7551,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7548: checking for $ac_hdr" >&5 +echo "configure:7555: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7558: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7565: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7624,17 +7631,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7628: checking for $ac_hdr" >&5 +echo "configure:7635: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7638: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7645: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7654,7 +7661,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then cat >> confdefs.h <&6 @@ -7663,10 +7670,10 @@ done else echo $ac_n "checking for directX headers in ${with_directx}""... $ac_c" 1>&6 -echo "configure:7667: checking for directX headers in ${with_directx}" >&5 +echo "configure:7674: checking for directX headers in ${with_directx}" >&5 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}" echo "$ac_t""yes" 1>&6 @@ -7690,17 +7697,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7694: checking for $ac_hdr" >&5 +echo "configure:7701: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7704: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7711: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7721,7 +7728,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - PLUGINS="${PLUGINS} fb" + PLUGINS="${PLUGINS} video_output/fb/fb" else echo "$ac_t""no" 1>&6 @@ -7735,7 +7742,7 @@ if test "${enable_mga+set}" = set; then enableval="$enable_mga" if test "x${enable_mga}" = "xyes" then - PLUGINS="${PLUGINS} mga xmga" + PLUGINS="${PLUGINS} video_output/mga/mga video_output/mga/xmga" fi fi @@ -7748,7 +7755,7 @@ fi if test "x${enable_ggi}" = "xyes" then - PLUGINS="${PLUGINS} ggi" + PLUGINS="${PLUGINS} video_output/ggi/ggi" ggi_LDFLAGS="${ggi_LDFLAGS} -lggi" # Check whether --with-ggi or --without-ggi was given. if test "${with_ggi+set}" = set; then @@ -7770,7 +7777,7 @@ fi 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" # Check whether --with-glide or --without-glide was given. @@ -7795,17 +7802,17 @@ if test "x${enable_aa}" = "xyes" then ac_safe=`echo "aalib.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for aalib.h""... $ac_c" 1>&6 -echo "configure:7799: checking for aalib.h" >&5 +echo "configure:7806: checking for aalib.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7809: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7816: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7829,7 +7836,7 @@ fi if test "x${have_aa}" = "xtrue" then - PLUGINS="${PLUGINS} aa" + PLUGINS="${PLUGINS} video_output/aa/aa" aa_LDFLAGS="${aa_LDFLAGS} -laa" fi fi @@ -7856,17 +7863,17 @@ then do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:7860: checking for $ac_hdr" >&5 +echo "configure:7867: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:7870: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:7877: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -7887,9 +7894,9 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - PLUGINS="${PLUGINS} dsp" + PLUGINS="${PLUGINS} audio_output/dsp/dsp" echo $ac_n "checking for main in -lossaudio""... $ac_c" 1>&6 -echo "configure:7893: checking for main in -lossaudio" >&5 +echo "configure:7900: checking for main in -lossaudio" >&5 ac_lib_var=`echo ossaudio'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -7897,14 +7904,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lossaudio $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:7915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -7940,7 +7947,7 @@ if test "${enable_esd+set}" = set; then # Extract the first word of "esd-config", so it can be a program name with args. set dummy esd-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7944: checking for $ac_word" >&5 +echo "configure:7951: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_ESD_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -7975,7 +7982,7 @@ fi 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 @@ -7991,7 +7998,7 @@ if test "${enable_arts+set}" = set; then # Extract the first word of "artsc-config", so it can be a program name with args. set dummy artsc-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:7995: checking for $ac_word" >&5 +echo "configure:8002: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_ARTS_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8026,7 +8033,7 @@ fi 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 @@ -8041,17 +8048,17 @@ if test "${enable_alsa+set}" = set; then then ac_safe=`echo "alsa/asoundlib.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for alsa/asoundlib.h""... $ac_c" 1>&6 -echo "configure:8045: checking for alsa/asoundlib.h" >&5 +echo "configure:8052: checking for alsa/asoundlib.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8055: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8068,7 +8075,7 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for main in -lasound""... $ac_c" 1>&6 -echo "configure:8072: checking for main in -lasound" >&5 +echo "configure:8079: checking for main in -lasound" >&5 ac_lib_var=`echo asound'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8076,14 +8083,14 @@ else ac_save_LIBS="$LIBS" LIBS="-lasound $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8094: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8111,7 +8118,7 @@ fi 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 @@ -8126,7 +8133,7 @@ fi if test "x${enable_waveout}" != "xno" -a "x${SYS}" = "xmingw32" then - PLUGINS="${PLUGINS} waveout" + PLUGINS="${PLUGINS} audio_output/waveout/waveout" waveout_LDFLAGS="-lwinmm" fi @@ -8160,7 +8167,7 @@ fi # Extract the first word of "gtk12-config", so it can be a program name with args. set dummy gtk12-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:8164: checking for $ac_word" >&5 +echo "configure:8171: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GTK12_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8199,7 +8206,7 @@ fi # Extract the first word of "gtk-config", so it can be a program name with args. set dummy gtk-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:8203: checking for $ac_word" >&5 +echo "configure:8210: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8248,17 +8255,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8252: checking for $ac_hdr" >&5 +echo "configure:8259: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8262: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8269: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8289,7 +8296,7 @@ done if test "x${ac_cv_gtk_headers}" = "xyes" then - PLUGINS="${PLUGINS} gtk" + PLUGINS="${PLUGINS} gui/gtk/gtk" ALIASES="${ALIASES} gvlc" fi CPPFLAGS="${save_CPPFLAGS}" @@ -8318,7 +8325,7 @@ fi # Extract the first word of "gtk12-config", so it can be a program name with args. set dummy gtk12-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:8322: checking for $ac_word" >&5 +echo "configure:8329: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GTK12_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8357,7 +8364,7 @@ fi # Extract the first word of "gtk-config", so it can be a program name with args. set dummy gtk-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:8361: checking for $ac_word" >&5 +echo "configure:8368: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8406,17 +8413,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8410: checking for $ac_hdr" >&5 +echo "configure:8417: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8420: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8427: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8447,7 +8454,7 @@ done if test "x${ac_cv_gtk_headers}" = "xyes" then - PLUGINS="${PLUGINS} familiar" + PLUGINS="${PLUGINS} gui/familiar/familiar" fi CPPFLAGS="${save_CPPFLAGS}" fi @@ -8461,7 +8468,7 @@ if test "${enable_gnome+set}" = set; then # Extract the first word of "gnome-config", so it can be a program name with args. set dummy gnome-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:8465: checking for $ac_word" >&5 +echo "configure:8472: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_GNOME_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8505,17 +8512,17 @@ fi do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8509: checking for $ac_hdr" >&5 +echo "configure:8516: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8519: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8526: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8536,7 +8543,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - PLUGINS="${PLUGINS} gnome" + PLUGINS="${PLUGINS} gui/gtk/gnome" ALIASES="${ALIASES} gnome-vlc" else @@ -8556,7 +8563,7 @@ fi if test "${enable_qt+set}" = set; then enableval="$enable_qt" 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" @@ -8574,7 +8581,7 @@ fi if test "${enable_kde+set}" = set; then enableval="$enable_kde" 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" @@ -8594,7 +8601,7 @@ if test "${enable_macosx+set}" = set; then enableval="$enable_macosx" 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 else @@ -8602,17 +8609,17 @@ else do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:8606: checking for $ac_hdr" >&5 +echo "configure:8613: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8616: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8623: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8632,7 +8639,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then cat >> confdefs.h <&6 -echo "configure:8659: checking for $ac_hdr" >&5 +echo "configure:8666: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8669: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8676: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8686,7 +8693,7 @@ if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then #define $ac_tr_hdr 1 EOF - PLUGINS="${PLUGINS} qnx" + PLUGINS="${PLUGINS} gui/qnx/qnx" qnx_LDFLAGS="${qnx_LDFLAGS} -lasound -lph" else @@ -8711,7 +8718,7 @@ fi then BCBUILDER="${with_bcbuilder}" fi - PLUGINS="${PLUGINS} intfwin" + PLUGINS="${PLUGINS} gui/win32/win32" fi fi @@ -8720,7 +8727,7 @@ fi if test "${enable_ncurses+set}" = set; then enableval="$enable_ncurses" if test "x${enable_ncurses}" = "xyes"; then - PLUGINS="${PLUGINS} ncurses" + PLUGINS="${PLUGINS} gui/ncurses/ncurses" ncurses_LDFLAGS="${ncurses_LDFLAGS} -lncurses" fi fi @@ -8736,17 +8743,17 @@ if test "x${enable_xosd}" = "xyes" then ac_safe=`echo "xosd.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for xosd.h""... $ac_c" 1>&6 -echo "configure:8740: checking for xosd.h" >&5 +echo "configure:8747: checking for xosd.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8750: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8757: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8770,7 +8777,7 @@ fi if test "x${have_xosd}" = "xtrue" then - PLUGINS="${PLUGINS} xosd" + PLUGINS="${PLUGINS} visualization/xosd/xosd" xosd_LDFLAGS="${xosd_LDFLAGS} -lxosd" fi fi @@ -8785,17 +8792,17 @@ if test "x${enable_lirc}" = "xyes" then ac_safe=`echo "lirc/lirc_client.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for lirc/lirc_client.h""... $ac_c" 1>&6 -echo "configure:8789: checking for lirc/lirc_client.h" >&5 +echo "configure:8796: checking for lirc/lirc_client.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:8799: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:8806: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -8812,7 +8819,7 @@ fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for lirc_init in -llirc_client""... $ac_c" 1>&6 -echo "configure:8816: checking for lirc_init in -llirc_client" >&5 +echo "configure:8823: checking for lirc_init in -llirc_client" >&5 ac_lib_var=`echo lirc_client'_'lirc_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8820,7 +8827,7 @@ else ac_save_LIBS="$LIBS" LIBS="-llirc_client $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8842: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -8859,7 +8866,7 @@ fi if test "x${have_lirc}" = "xtrue" then - PLUGINS="${PLUGINS} lirc" + PLUGINS="${PLUGINS} control/lirc/lirc" lirc_LDFLAGS="${lirc_LDFLAGS} -llirc_client" fi fi @@ -8886,7 +8893,7 @@ fi ;; *) echo $ac_n "checking whether the byte order is big-endian""... $ac_c" 1>&6 -echo "configure:8890: checking whether the byte order is big-endian" >&5 +echo "configure:8897: checking whether the byte order is big-endian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -8968,7 +8975,7 @@ if test "${enable_pth+set}" = set; then enableval="$enable_pth" if test "x${enable_pth}" = "xyes"; then echo $ac_n "checking for pth_init in -lpth""... $ac_c" 1>&6 -echo "configure:8972: checking for pth_init in -lpth" >&5 +echo "configure:8979: checking for pth_init in -lpth" >&5 ac_lib_var=`echo pth'_'pth_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -8976,7 +8983,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lpth $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:8998: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9015,7 +9022,7 @@ else fi cat > conftest.$ac_ext < EOF @@ -9041,7 +9048,7 @@ if test "${enable_st+set}" = set; then enableval="$enable_st" if test "x${enable_st}" = "xyes"; then echo $ac_n "checking for st_init in -lst""... $ac_c" 1>&6 -echo "configure:9045: checking for st_init in -lst" >&5 +echo "configure:9052: checking for st_init in -lst" >&5 ac_lib_var=`echo st'_'st_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9049,7 +9056,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lst $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9088,7 +9095,7 @@ else fi cat > conftest.$ac_ext < EOF @@ -9124,7 +9131,7 @@ then # Extract the first word of "mozilla-config", so it can be a program name with args. set dummy mozilla-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:9128: checking for $ac_word" >&5 +echo "configure:9135: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_MOZILLA_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -9162,7 +9169,7 @@ fi if test "x${SYS}" != "xmingw32"; then LDFLAGS="${save_LDFLAGS} -L${x_libraries}" echo $ac_n "checking for XtStrings in -lXt""... $ac_c" 1>&6 -echo "configure:9166: checking for XtStrings in -lXt" >&5 +echo "configure:9173: checking for XtStrings in -lXt" >&5 ac_lib_var=`echo Xt'_'XtStrings | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -9170,7 +9177,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lXt $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:9192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -9589,11 +9596,11 @@ s%@builtins_CFLAGS@%$builtins_CFLAGS%g s%@mozilla_CFLAGS@%$mozilla_CFLAGS%g s%@a52_CFLAGS@%$a52_CFLAGS%g s%@arts_CFLAGS@%$arts_CFLAGS%g -s%@chroma_i420_yuy2_mmx_CFLAGS@%$chroma_i420_yuy2_mmx_CFLAGS%g +s%@i420_yuy2_mmx_CFLAGS@%$i420_yuy2_mmx_CFLAGS%g s%@dvd_CFLAGS@%$dvd_CFLAGS%g s%@dvdread_CFLAGS@%$dvdread_CFLAGS%g s%@dvdplay_CFLAGS@%$dvdplay_CFLAGS%g -s%@mpeg_ts_dvbpsi_CFLAGS@%$mpeg_ts_dvbpsi_CFLAGS%g +s%@ts_dvbpsi_CFLAGS@%$ts_dvbpsi_CFLAGS%g s%@directx_CFLAGS@%$directx_CFLAGS%g s%@esd_CFLAGS@%$esd_CFLAGS%g s%@familiar_CFLAGS@%$familiar_CFLAGS%g @@ -9620,16 +9627,16 @@ s%@aa_LDFLAGS@%$aa_LDFLAGS%g s%@alsa_LDFLAGS@%$alsa_LDFLAGS%g s%@arts_LDFLAGS@%$arts_LDFLAGS%g s%@beos_LDFLAGS@%$beos_LDFLAGS%g -s%@chroma_i420_rgb_LDFLAGS@%$chroma_i420_rgb_LDFLAGS%g +s%@i420_rgb_LDFLAGS@%$i420_rgb_LDFLAGS%g s%@directx_LDFLAGS@%$directx_LDFLAGS%g s%@dsp_LDFLAGS@%$dsp_LDFLAGS%g s%@dvd_LDFLAGS@%$dvd_LDFLAGS%g s%@dvdread_LDFLAGS@%$dvdread_LDFLAGS%g s%@dvdplay_LDFLAGS@%$dvdplay_LDFLAGS%g -s%@mpeg_ts_dvbpsi_LDFLAGS@%$mpeg_ts_dvbpsi_LDFLAGS%g +s%@ts_dvbpsi_LDFLAGS@%$ts_dvbpsi_LDFLAGS%g s%@esd_LDFLAGS@%$esd_LDFLAGS%g s%@familiar_LDFLAGS@%$familiar_LDFLAGS%g -s%@filter_distort_LDFLAGS@%$filter_distort_LDFLAGS%g +s%@distort_LDFLAGS@%$distort_LDFLAGS%g s%@ffmpeg_LDFLAGS@%$ffmpeg_LDFLAGS%g s%@mp4_LDFLAGS@%$mp4_LDFLAGS%g s%@ggi_LDFLAGS@%$ggi_LDFLAGS%g diff --git a/configure.in b/configure.in index 88ee20577b..817f09bad6 100644 --- a/configure.in +++ b/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= for dynamic linking (recommended under Unix) or --with-dvdcss-tree= 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 ], [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) diff --git a/doc/mad/API b/doc/mad/API new file mode 100644 index 0000000000..83a8731cf5 --- /dev/null +++ b/doc/mad/API @@ -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.) + + + + diff --git a/doc/mad/BUGS b/doc/mad/BUGS new file mode 100644 index 0000000000..96c3931199 --- /dev/null +++ b/doc/mad/BUGS @@ -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. diff --git a/doc/mad/DESIGN b/doc/mad/DESIGN new file mode 100644 index 0000000000..12035ba312 --- /dev/null +++ b/doc/mad/DESIGN @@ -0,0 +1,63 @@ +File: Plugin mad for vlc is based upon libmad from the mad distribution. +Author: Jean-Paul Saman + +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. + + --------------- + | | + | libmad | + --------------- + ^ + | + --------------- + | | + | mad | + _______________ + ^ + | + ________________________ + | | + | 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. + + diff --git a/doc/mad/TODO b/doc/mad/TODO new file mode 100644 index 0000000000..b19be0af03 --- /dev/null +++ b/doc/mad/TODO @@ -0,0 +1,40 @@ +TODO: (Jean-Paul Saman ) + +[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]) + diff --git a/doc/mad/joe_drew.txt b/doc/mad/joe_drew.txt new file mode 100644 index 0000000000..97dbab90d0 --- /dev/null +++ b/doc/mad/joe_drew.txt @@ -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 + +Please encrypt email sent to me. diff --git a/doc/mad/rob_leslie.txt b/doc/mad/rob_leslie.txt new file mode 100644 index 0000000000..fbe49e4848 --- /dev/null +++ b/doc/mad/rob_leslie.txt @@ -0,0 +1,124 @@ +From - Mon Nov 5 09:19:09 2001 +Return-Path: +Received: from smtp01.wxs.nl ([195.121.5.15]) by po05.wxs.nl + (Netscape Messaging Server 4.15) with ESMTP id GLLMFJ00.3DF for + ; 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 ; 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 ; 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 +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: +List-Post: +List-Subscribe: , + +List-Id: MAD developer's mailing list +List-Unsubscribe: , + +List-Archive: +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 diff --git a/include/audio_output.h b/include/audio_output.h index 690053a7ac..6257e4f16e 100644 --- a/include/audio_output.h +++ b/include/audio_output.h @@ -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 * Cyril Deguet @@ -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 diff --git a/include/input_ext-dec.h b/include/input_ext-dec.h index f5cdcd025f..ff32291369 100644 --- a/include/input_ext-dec.h +++ b/include/input_ext-dec.h @@ -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 * Michel Kaempf @@ -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 diff --git a/include/input_ext-intf.h b/include/input_ext-intf.h index f2d5b87f83..4b107b8719 100644 --- a/include/input_ext-intf.h +++ b/include/input_ext-intf.h @@ -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 * @@ -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 diff --git a/modules/access/.cvsignore b/modules/access/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/Makefile b/modules/access/Makefile new file mode 100644 index 0000000000..fda8268a3e --- /dev/null +++ b/modules/access/Makefile @@ -0,0 +1,3 @@ +file_SOURCES = file.c +udp_SOURCES = udp.c +http_SOURCES = http.c diff --git a/modules/access/dvd/.cvsignore b/modules/access/dvd/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/dvd/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/dvd/Makefile b/modules/access/dvd/Makefile new file mode 100644 index 0000000000..1a9f155565 --- /dev/null +++ b/modules/access/dvd/Makefile @@ -0,0 +1 @@ +dvd_SOURCES = dvd.c access.c demux.c seek.c es.c ifo.c udf.c summary.c diff --git a/modules/access/dvd/access.c b/modules/access/dvd/access.c new file mode 100644 index 0000000000..267feba06f --- /dev/null +++ b/modules/access/dvd/access.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 + * + * 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 +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#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; +} diff --git a/modules/access/dvd/demux.c b/modules/access/dvd/demux.c new file mode 100644 index 0000000000..b2c7bdce7e --- /dev/null +++ b/modules/access/dvd/demux.c @@ -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 + * + * 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 +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#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; +} diff --git a/modules/access/dvd/dvd.c b/modules/access/dvd/dvd.c new file mode 100644 index 0000000000..c229f70b0d --- /dev/null +++ b/modules/access/dvd/dvd.c @@ -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 + * + * 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 /* malloc(), free() */ +#include /* strdup() */ + +#include + +#ifdef GOD_DAMN_DMCA +# include +# include +# include +# include +# include +# include /* struct iovec */ +# include +# include +# include +# include + +# 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 + diff --git a/modules/access/dvd/dvd.h b/modules/access/dvd/dvd.h new file mode 100644 index 0000000000..edd7efd080 --- /dev/null +++ b/modules/access/dvd/dvd.h @@ -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 + * + * 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; + diff --git a/modules/access/dvd/dvdcss.h b/modules/access/dvd/dvdcss.h new file mode 100644 index 0000000000..3a27482e8f --- /dev/null +++ b/modules/access/dvd/dvdcss.h @@ -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 + * + * 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 ); + + diff --git a/modules/access/dvd/es.c b/modules/access/dvd/es.c new file mode 100644 index 0000000000..baf7df9132 --- /dev/null +++ b/modules/access/dvd/es.c @@ -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 + * + * 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 +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#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] ); + } + } + } +} diff --git a/modules/access/dvd/es.h b/modules/access/dvd/es.h new file mode 100644 index 0000000000..f908b0a196 --- /dev/null +++ b/modules/access/dvd/es.h @@ -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 + * + * 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 * ); + diff --git a/modules/access/dvd/ifo.c b/modules/access/dvd/ifo.c new file mode 100644 index 0000000000..9eea56efd3 --- /dev/null +++ b/modules/access/dvd/ifo.c @@ -0,0 +1,2183 @@ +/***************************************************************************** + * ifo.c: Functions for ifo parsing + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: ifo.c,v 1.1 2002/08/04 17:23:41 sam Exp $ + * + * Authors: Stéphane Borel + * German Tischler + * + * based on: + * - libifo by Thomas Mirlacher + * - 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. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#include +#include + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#endif + +#include "dvd.h" +#include "ifo.h" +#include "udf.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +void CommandRead ( command_desc_t ); +static int ReadTitle ( ifo_t * , title_t *, int, int ); +static int FreeTitle ( title_t * ); +static int ReadUnitInf ( ifo_t * , unit_inf_t *, int, int ); +static int FreeUnitInf ( unit_inf_t * ); +static int ReadTitleUnit ( ifo_t * , title_unit_t *, int ); +static int FreeTitleUnit ( title_unit_t * ); +static int ReadVobuMap ( ifo_t * , vobu_map_t *, int ); +static int FreeVobuMap ( vobu_map_t * ); +static int ReadCellInf ( ifo_t * , cell_inf_t *, int ); +static int FreeCellInf ( cell_inf_t * ); +static int FreeTitleSet ( vts_t * ); + +static u8* FillBuffer ( ifo_t *, u8 *, int ); +static u8 ReadByte ( ifo_t *, u8 *, u8 ** ); +static void ReadBytes ( ifo_t *, u8 *, u8 **, u8 *, int ); +static void DumpBytes ( ifo_t *, u8 *, u8 **, int ); +static u16 ReadWord ( ifo_t *, u8 *, u8 ** ); +static u32 ReadDouble ( ifo_t *, u8 *, u8 ** ); +static u64 ReadQuad ( ifo_t *, u8 *, u8 ** ); + +/* + * IFO Management. + */ + +/***************************************************************************** + * IfoCreate : Creates an ifo structure and prepares for parsing directly + * on DVD device + *****************************************************************************/ +int IfoCreate( thread_dvd_data_t * p_dvd ) +{ + p_dvd->p_ifo = malloc( sizeof(ifo_t) ); + if( p_dvd->p_ifo == NULL ) + { +//X intf_Err( p_input, "unable to allocate memory. aborting" ); + return -1; + } + + /* if we are here the dvd device has already been opened */ + p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle; + + return 0; +} + +/***************************************************************************** + * IfoInit : Reads information from the management table. + *****************************************************************************/ +int IfoInit( ifo_t * p_ifo ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8* p_tmp; + u64 i_temp; + int i, j, k; + int i_start; + + /* find the start sector of video information on the dvd */ + p_ifo->i_start = DVDUDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" ); + if( !p_ifo->i_start ) return -1; + + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start ); + //i_start = p_ifo->i_pos; + + /* + * read the video manager information table + */ +#define MGINF p_ifo->vmg.manager_inf + //fprintf( stderr, "VMGI\n" ); + + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 ); + MGINF.psz_id[12] = '\0'; + MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 12 ); + MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp ); + MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp ); + MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 19 ); + MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 ); + MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 24 ); + MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 56 ); + MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 32 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb ); + + for( i = 0 ; i < MGINF.i_spu_nb ; i++ ) + { + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + /* FIXME : take care of endianness */ + } + + /* + * read first play title. + */ + //fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff ); + if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start + + OFF2LB( MGINF.i_first_play_title_start_byte ), + MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 ) + { + return -1; + } + + /* + * fills the title information structure. + */ +#define TITINF p_ifo->vmg.title_inf + if( MGINF.i_title_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, + p_ifo->i_start + MGINF.i_title_inf_start_sector ); + //fprintf( stderr, "title inf %d\n", p_ifo->i_pos ); + + TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + /* parsing of title attributes */ + TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) ); + if( TITINF.p_attr == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) + { + TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp ); + TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title_inf: %d %d %d\n", TITINF.p_attr[i].i_chapter_nb, TITINF.p_attr[i].i_title_set_num, TITINF.p_attr[i].i_title_num ); + } + } + else + { + TITINF.p_attr = NULL; + } +#undef TITINF + + /* + * fills the title unit structure. + */ + if( MGINF.i_title_unit_start_sector ) + { + if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start + + MGINF.i_title_unit_start_sector ) < 0 ) + { + return -1; + } + } + + /* + * fills the structure about parental information. + */ +#define PARINF p_ifo->vmg.parental_inf + if( MGINF.i_parental_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start + + MGINF.i_parental_inf_start_sector ); + i_start = p_ifo->i_pos; + + //fprintf( stderr, "PTL\n" ); + + PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + PARINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + PARINF.p_parental_desc = malloc( PARINF.i_country_nb + * sizeof(parental_desc_t) ); + if( PARINF.p_parental_desc == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < PARINF.i_country_nb ; i++ ) + { + ReadBytes( p_ifo, p_buf, &p_tmp, + PARINF.p_parental_desc[i].ps_country_code, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + PARINF.p_parental_desc[i].i_parental_mask_start_byte = + ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + } + + PARINF.p_parental_mask = malloc( PARINF.i_country_nb + * sizeof(parental_mask_t) ); + if( PARINF.p_parental_mask == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < PARINF.i_country_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB( + PARINF.p_parental_desc[i].i_parental_mask_start_byte ) ) + + (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff); + + for( j = 0 ; j < 8 ; j++ ) + { + PARINF.p_parental_mask[i].ppi_mask[j] = + malloc( ( PARINF.i_vts_nb + 1 ) * sizeof(u16) ); + + if( PARINF.p_parental_mask[i].ppi_mask[j] == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( k = 0 ; k < PARINF.i_vts_nb + 1 ; k++ ) + { + PARINF.p_parental_mask[i].ppi_mask[j][k] = + ReadWord( p_ifo, p_buf, &p_tmp ); + } + } + } + } +#undef PARINF + + /* + * information and attributes about for each vts. + */ +#define VTSINF p_ifo->vmg.vts_inf + if( MGINF.i_vts_inf_start_sector ) + { + u64 i_temp; + + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start + + MGINF.i_vts_inf_start_sector ); + i_start = p_ifo->i_pos; + + //fprintf( stderr, "VTS ATTR\n" ); + + VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );; + //fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + VTSINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + VTSINF.pi_vts_attr_start_byte = + malloc( VTSINF.i_vts_nb * sizeof(u32) ); + if( VTSINF.pi_vts_attr_start_byte == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < VTSINF.i_vts_nb ; i++ ) + { + VTSINF.pi_vts_attr_start_byte[i] = + ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) ); + if( VTSINF.p_vts_attr == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoInit" ); + return -1; + } + + for( i = 0 ; i < VTSINF.i_vts_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) ) + + ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff ); + + VTSINF.p_vts_attr[i].i_last_byte = + ReadDouble( p_ifo, p_buf, &p_tmp ); + VTSINF.p_vts_attr[i].i_cat_app_type = + ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + VTSINF.p_vts_attr[i].i_vts_menu_audio_nb = + ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb ); + + for( j = 0 ; j < 8 ; j++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + VTSINF.p_vts_attr[i].i_vts_menu_spu_nb = + ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "m subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_spu_nb ); + + for( j = 0 ; j < 28 ; j++ ) + { + /* FIXME : Fix endianness issue here */ + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + VTSINF.p_vts_attr[i].i_vts_title_audio_nb = + ReadDouble( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "tt audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_audio_nb ); + + for( j = 0 ; j < 8 ; j++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );; + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + VTSINF.p_vts_attr[i].i_vts_title_spu_nb = + ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "tt subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_spu_nb ); + + for( j = 0 ; j < 28 /*VTSINF.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ ) + { + /* FIXME : Fix endianness issue here */ + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + } + } + } +#undef VTSINF + + /* + * global cell map. + */ + if( MGINF.i_cell_inf_start_sector ) + { + if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start + + MGINF.i_cell_inf_start_sector ) < 0 ) + { + return -1; + } + } + + /* + * global vob unit map. + */ + if( MGINF.i_vobu_map_start_sector ) + { + if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start + + MGINF.i_vobu_map_start_sector ) < 0 ) + { + return -1; + } + } +#undef MGINF + + p_ifo->vts.b_initialized = 0; + +//X intf_Warn( p_input, 2, "vmg initialized" ); + + return 0; +} + +/***************************************************************************** + * IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure. + *****************************************************************************/ +int IfoTitleSet( ifo_t * p_ifo, int i_title ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_off; + int i_start; + u64 i_temp; + u16 i_short; + int i, j; + + if( p_ifo->vts.b_initialized ) + { + FreeTitleSet( &p_ifo->vts ); + } + + i_off = p_ifo->vmg.title_inf.p_attr[i_title-1].i_start_sector + + p_ifo->i_start; + + //fprintf(stderr, "offset: %d\n" , i_off ); + + p_tmp = FillBuffer( p_ifo, p_buf, i_off ); + //i_start = p_ifo->i_pos; + p_ifo->vts.i_pos = p_ifo->i_pos; + +#define MGINF p_ifo->vts.manager_inf + + /* + * read manager information + */ + //fprintf( stderr, "VTSI\n" ); + + ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 ); + MGINF.psz_id[12] = '\0'; + MGINF.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 12 ); + MGINF.i_inf_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp ); + MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 90 ); + MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 60 ); + MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 24 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 28 ; i++ ) + { + /* FIXME : take care of endianness */ + ReadBytes( p_ifo, p_buf, &p_tmp, (u8*)(&i_temp), 6 ); + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + + i_short = ReadWord( p_ifo, p_buf, &p_tmp ); + i_short >>= 2; + MGINF.video_attr.i_mode = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_letterboxed = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_source_res = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_line21_2 = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_line21_1 = i_short & 0x1; + i_short >>= 1; + MGINF.video_attr.i_perm_displ = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_ratio = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_system = i_short & 0x3; + i_short >>= 2; + MGINF.video_attr.i_compression = i_short & 0x3; + + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_temp = ReadQuad( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "Audio %d: %llx\n", i, i_temp ); + i_temp >>= 8; + MGINF.p_audio_attr[i].i_bar = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_caption = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_foo = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff; + i_temp >>= 16; + MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7; + i_temp >>= 3; + MGINF.p_audio_attr[i].i_test = i_temp & 0x1; + i_temp >>= 1; + MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_type = i_temp & 0x3; + i_temp >>= 2; + MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1; + i_temp >>= 1; + MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7; + } + + DumpBytes( p_ifo, p_buf, &p_tmp, 17 ); + MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb ); + + for( i=0 ; i> 16; + //fprintf( stderr, "Subpic %d: %llx\n", i, i_temp ); + MGINF.p_spu_attr[i].i_caption = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_spu_attr[i].i_foo = i_temp & 0xff; + i_temp >>= 8; + MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff; + i_temp >>= 16; + MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff; + } + + /* + * read title information: set of pointers to title + */ +#define TITINF p_ifo->vts.title_inf + if( MGINF.i_title_inf_start_sector ) + { + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos + + MGINF.i_title_inf_start_sector ); + + i_start = p_ifo->i_pos; + + //fprintf( stderr, "VTS PTR\n" ); + + TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(u32) ); + if( TITINF.pi_start_byte == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) + { + TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + /* Parsing of tts */ + TITINF.p_title_start = malloc( TITINF.i_title_nb + * sizeof(title_start_t) ); + if( TITINF.p_title_start == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TITINF.i_title_nb ; i++ ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( TITINF.pi_start_byte[i] ) ) + + (TITINF.pi_start_byte[i] & 0x7ff); + + TITINF.p_title_start[i].i_title_id = + ReadWord( p_ifo, p_buf, &p_tmp ); + TITINF.p_title_start[i].i_chapter = + ReadWord( p_ifo, p_buf, &p_tmp ); + } + } +#undef TITINF + + /* + * menu unit information + */ + if( MGINF.i_menu_unit_start_sector ) + { + if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos + + MGINF.i_menu_unit_start_sector ) < 0 ) + { + return -1; + } + } + + /* + * title unit information + */ + if( MGINF.i_title_unit_start_sector ) + { + if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos + + MGINF.i_title_unit_start_sector, 0 ) < 0 ) + { + return -1; + } + } + + /* + * time map information + */ +#define TIMINF p_ifo->vts.time_inf + if( MGINF.i_time_inf_start_sector ) + { + u8 p_buf[DVD_LB_SIZE]; + + p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos + + MGINF.i_time_inf_start_sector ); + + //fprintf( stderr, "TMAP\n" ); + + TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );; + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + TIMINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(u32) ); + if( TIMINF.pi_start_byte == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TIMINF.i_nb ; i++ ) + { + TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) ); + if( TIMINF.p_time_map == NULL ) + { +//X intf_Err( p_input, "out of memory in IfoTitleSet" ); + return -1; + } + + for( i = 0 ; i < TIMINF.i_nb ; i++ ) + { + TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + + if( TIMINF.p_time_map[i].i_entry_nb ) + { + TIMINF.p_time_map[i].pi_sector = + malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(u32) ); + if( TIMINF.p_time_map[i].pi_sector == NULL ) + { +//X msg_Err( p_input, "out of memory in IfoTitleSet" ); + return -1; + } + + for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ ) + { + TIMINF.p_time_map[i].pi_sector[j] = + ReadDouble( p_ifo, p_buf, &p_tmp ); + } + } + } + } +#undef TIMINF + + if( MGINF.i_menu_cell_inf_start_sector + && ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos + + MGINF.i_menu_cell_inf_start_sector ) < 0 ) + { + return -1; + } + + if( MGINF.i_menu_vobu_map_start_sector + && ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos + + MGINF.i_menu_vobu_map_start_sector ) < 0 ) + { + return -1; + } + + if( MGINF.i_cell_inf_start_sector + && ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos + + MGINF.i_cell_inf_start_sector ) ) + { + return -1; + } + + if( MGINF.i_vobu_map_start_sector + && ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos + + MGINF.i_vobu_map_start_sector ) ) + { + return -1; + } +#undef MGINF + +//X intf_Warn( p_input, 4, "vts %d initialized", +//X p_ifo->vmg.title_inf.p_attr[i_title-1].i_title_set_num ); + + p_ifo->vts.b_initialized = 1; + + return 0; +} + +/***************************************************************************** + * FreeTitleSet : free all structures allocated by IfoTitleSet + *****************************************************************************/ +static int FreeTitleSet( vts_t * p_vts ) +{ + int i; + + if( p_vts->manager_inf.i_vobu_map_start_sector ) + { + FreeVobuMap( &p_vts->vobu_map ); + } + + if( p_vts->manager_inf.i_cell_inf_start_sector ) + { + FreeCellInf( &p_vts->cell_inf ); + } + + if( p_vts->manager_inf.i_menu_vobu_map_start_sector ) + { + FreeVobuMap( &p_vts->menu_vobu_map ); + } + + if( p_vts->manager_inf.i_menu_cell_inf_start_sector ) + { + FreeCellInf( &p_vts->menu_cell_inf ); + } + + if( p_vts->manager_inf.i_time_inf_start_sector ) + { + for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ ) + { + if( p_vts->time_inf.p_time_map[i].i_entry_nb ) + { + free( p_vts->time_inf.p_time_map[i].pi_sector ); + } + } + + free( p_vts->time_inf.p_time_map ); + free( p_vts->time_inf.pi_start_byte ); + } + + if( p_vts->manager_inf.i_title_unit_start_sector ) + { + FreeUnitInf( &p_vts->title_unit ); + } + + if( p_vts->manager_inf.i_menu_unit_start_sector ) + { + FreeTitleUnit( &p_vts->menu_unit ); + } + + if( p_vts->manager_inf.i_title_inf_start_sector ) + { + free( p_vts->title_inf.pi_start_byte ); + free( p_vts->title_inf.p_title_start ); + } + + p_vts->b_initialized = 0; + + return 0; +} + +/***************************************************************************** + * IfoDestroy : Frees all the memory allocated to ifo structures + *****************************************************************************/ +void IfoDestroy( ifo_t * p_ifo ) +{ + int i, j; + + FreeTitleSet( &p_ifo->vts ); + + if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector ) + { + FreeVobuMap( &p_ifo->vmg.vobu_map ); + } + + if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector ) + { + FreeCellInf( &p_ifo->vmg.cell_inf ); + } + + if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector ) + { + free( p_ifo->vmg.vts_inf.p_vts_attr ); + free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte ); + } + + /* free parental information structures */ + if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector ) + { + for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ ) + { + for( j = 0 ; j < 8 ; j++ ) + { + free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] ); + } + } + + free( p_ifo->vmg.parental_inf.p_parental_mask ); + free( p_ifo->vmg.parental_inf.p_parental_desc ); + } + + if( p_ifo->vmg.manager_inf.i_title_unit_start_sector ) + { + FreeTitleUnit( &p_ifo->vmg.title_unit ); + } + + if( p_ifo->vmg.manager_inf.i_title_inf_start_sector ) + { + free( p_ifo->vmg.title_inf.p_attr ); + } + + FreeTitle( &p_ifo->vmg.title ); + + free( p_ifo ); + + return; +} + +/* + * Function common to Video Manager and Video Title set Processing + */ + +/***************************************************************************** + * ReadTitle : Fills the title structure. + ***************************************************************************** + * Titles are logical stream units that correspond to a whole inside the dvd. + * Several title can point to the same part of the physical DVD, and give + * map to different anglesfor instance. + *****************************************************************************/ +static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + u16 i_audio; + u32 i_spu; + int i; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes; + + i_start = p_ifo->i_pos; + + //fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); + + DumpBytes( p_ifo, p_buf, &p_tmp, 2); + p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb ); + p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp ); + p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 8 ; i++ ) + { + i_audio = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->pi_audio_status[i].i_foo = i_audio & 0xff; + i_audio >>= 8; + p_title->pi_audio_status[i].i_position = i_audio & 0x07; + i_audio >>= 7; + p_title->pi_audio_status[i].i_available = i_audio; + } + + for( i = 0 ; i < 32 ; i++ ) + { + i_spu = ReadDouble( p_ifo, p_buf, &p_tmp ); + p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f; + i_spu >>= 8; + p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f; + i_spu >>= 7; + p_title->pi_spu_status[i].i_available = i_spu; + } + + p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp ); + p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp ); + + for( i = 0 ; i < 16 ; i++ ) + { + /* FIXME : We have to erase the extra bit */ + p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp ); + + /* parsing of command_t */ + if( p_title->i_command_start_byte ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_command_start_byte + i_bytes ) ) + + ( (p_title->i_command_start_byte + i_bytes) & 0x7ff ); + + /* header */ + p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + + /* pre-title commands */ + if( p_title->command.i_pre_command_nb ) + { + p_title->command.p_pre_command = + malloc( p_title->command.i_pre_command_nb + * sizeof(command_desc_t) ); + + if( p_title->command.p_pre_command == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ ) + { + p_title->command.p_pre_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); + } + } + else + { + p_title->command.p_pre_command = NULL; + } + + /* post-title commands */ + if( p_title->command.i_post_command_nb ) + { + p_title->command.p_post_command = + malloc( p_title->command.i_post_command_nb + * sizeof(command_desc_t) ); + + if( p_title->command.p_post_command == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ ) + { + p_title->command.p_post_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); + } + } + else + { + p_title->command.p_post_command = NULL; + } + + /* cell commands */ + if( p_title->command.i_cell_command_nb ) + { + p_title->command.p_cell_command = + malloc( p_title->command.i_cell_command_nb + * sizeof(command_desc_t) ); + + if( p_title->command.p_cell_command == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ ) + { + p_title->command.p_cell_command[i] = + ReadQuad( p_ifo, p_buf, &p_tmp ); + } + } + else + { + p_title->command.p_cell_command = NULL; + } + } + + /* parsing of chapter_map_t: it gives the entry cell for each chapter */ + if( p_title->i_chapter_map_start_byte ) + { + p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, + OFF2LB( i_start + p_title->i_chapter_map_start_byte ), + DVDCSS_NOFLAGS ); + + p_title->chapter_map.pi_start_cell = + malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) ); + + if( p_title->chapter_map.pi_start_cell == NULL ) + { +//X intf_Err( p_input, "out of memory in Read Title" ); + return -1; + } + + ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell, + p_title->i_chapter_nb ); + } + else + { + p_title->chapter_map.pi_start_cell = NULL; + } + + /* parsing of cell_play_t */ + if( p_title->i_cell_play_start_byte ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) ) + + ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff ); + + p_title->p_cell_play = malloc( p_title->i_cell_nb + * sizeof(cell_play_t) ); + + if( p_title->p_cell_play == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitle" ); + return -1; + } + + for( i = 0 ; i < p_title->i_cell_nb ; i++ ) + { +#define PLAY p_title->p_cell_play[i] + PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp ); + PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp ); + PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp ); + PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); + PLAY.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef PLAY + } + } + + /* Parsing of cell_pos_t */ + if( p_title->i_cell_pos_start_byte ) + { + p_tmp = FillBuffer( p_ifo, p_buf, i_start + + OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) ) + + ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff ); + + p_title->p_cell_pos = malloc( p_title->i_cell_nb + * sizeof(cell_pos_t) ); + + if( p_title->p_cell_pos == NULL ) + { +//X intf_Err( p_input, "out of memory" ); + return -1; + } + + for( i = 0 ; i < p_title->i_cell_nb ; i++ ) + { + p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp ); + } + } + + return 0; +} + +/***************************************************************************** + * FreeTitle: frees alla structure allocated by a call to ReadTitle + *****************************************************************************/ +static int FreeTitle( title_t * p_title ) +{ + if( p_title->i_command_start_byte ) + { + if( p_title->command.i_pre_command_nb ) + { + free( p_title->command.p_pre_command ); + } + + if( p_title->command.i_post_command_nb ) + { + free( p_title->command.p_post_command ); + } + + if( p_title->command.i_cell_command_nb ) + { + free( p_title->command.p_cell_command ); + } + } + + if( p_title->i_chapter_map_start_byte ) + { + free( p_title->chapter_map.pi_start_cell ); + } + + if( p_title->i_cell_play_start_byte ) + { + free( p_title->p_cell_play ); + } + + if( p_title->i_cell_pos_start_byte ) + { + free( p_title->p_cell_pos ); + } + + return 0; +} + +/***************************************************************************** + * ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table + *****************************************************************************/ +static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf, + int i_block, int i_bytes ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes; + + i_start = p_ifo->i_pos; + //fprintf( stderr, "Unit\n" ); + + p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_unit_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + p_unit_inf->p_title = + malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) ); + if( p_unit_inf->p_title == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadUnit" ); + return -1; + } + + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) + { +#define TITLE p_unit_inf->p_title[i] + TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp ); + TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); + TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp ); + TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef TITLE + } + + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) + { + //fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); + ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start + + OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ), + (p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff ); + } + + return 0; +} + +/***************************************************************************** + * FreeUnitInf : frees a structure allocated by ReadUnit + *****************************************************************************/ +static int FreeUnitInf( unit_inf_t * p_unit_inf ) +{ + int i; + + if( p_unit_inf->p_title != NULL ) + { + for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ ) + { + FreeTitle( &p_unit_inf->p_title[i].title ); + } + + free( p_unit_inf->p_title ); + } + + return 0; +} + + +/***************************************************************************** + * ReadTitleUnit: Fills the Title Unit structure. + *****************************************************************************/ +static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit, + int i_block ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i; + int i_start; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; + //fprintf( stderr, "Unit Table\n" ); + + p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_title_unit->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + //fprintf(stderr, "Unit: nb %d last %d\n", p_title_unit->i_unit_nb, p_title_unit->i_last_byte ); + + p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) ); + if( p_title_unit->p_unit == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitleUnit" ); + return -1; + } + + for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ ) + { + //ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); + p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp ); + //fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + p_title_unit->p_unit[i].i_existence_mask = + ReadByte( p_ifo, p_buf, &p_tmp ); + p_title_unit->p_unit[i].i_unit_inf_start_byte = + ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + p_title_unit->p_unit_inf = + malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) ); + if( p_title_unit->p_unit_inf == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadTitleUnit" ); + return -1; + } + + for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ ) + { + ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start + + OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ), + p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff ); + } + + return 0; +} + +/***************************************************************************** + * FreeTitleUnit: frees a structure allocateed by ReadTitleUnit + *****************************************************************************/ +static int FreeTitleUnit( title_unit_t * p_title_unit ) +{ + int i; + + if( p_title_unit->p_unit_inf != NULL ) + { + for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ ) + { + FreeUnitInf( &p_title_unit->p_unit_inf[i] ); + } + + free( p_title_unit->p_unit_inf ); + } + + return 0; +} + +/***************************************************************************** + * ReadCellInf : Fills the Cell Information structure. + *****************************************************************************/ +static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; +// fprintf( stderr, "CELL ADD\n" ); + + p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 2 ); + p_cell_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + + p_cell_inf->i_cell_nb = (p_cell_inf->i_last_byte + 1/* - 7*/) / sizeof(cell_map_t); + +/* fprintf( stderr, "Cell inf: vob %d, %d cells, last byte %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_cell_nb, p_cell_inf->i_last_byte ); +*/ + p_cell_inf->p_cell_map = + malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) ); + if( p_cell_inf->p_cell_map == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadCellInf" ); + return -1; + } + + for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ ) + { +#define MAP p_cell_inf->p_cell_map[i] + MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp ); + MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp ); + DumpBytes( p_ifo, p_buf, &p_tmp, 1 ); + MAP.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); +/* fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(u32*)(p_tmp)), p_ifo->i_pos);*/ + MAP.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp ); +#undef MAP + } + + return 0; +} + +/***************************************************************************** + * FreeCellInf : frees structures allocated by ReadCellInf + *****************************************************************************/ +static int FreeCellInf( cell_inf_t * p_cell_inf ) +{ + free( p_cell_inf->p_cell_map ); + + return 0; +} + +/***************************************************************************** + * ReadVobuMap : Fills the VOBU Map structure. + *****************************************************************************/ +static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block ) +{ + u8 p_buf[DVD_LB_SIZE]; + u8 * p_tmp; + int i_start; + int i, i_max; + + p_tmp = FillBuffer( p_ifo, p_buf, i_block ); + i_start = p_ifo->i_pos; + //fprintf( stderr, "VOBU ADMAP\n" ); + + p_vobu_map->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp ); + i_max = ( i_start + p_vobu_map->i_last_byte + 1 - p_ifo->i_pos ) + / sizeof(u32); + + p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(u32) ); + if( p_vobu_map->pi_vobu_start_sector == NULL ) + { +//X intf_Err( p_input, "out of memory in ReadVobuMap" ); + return -1; + } + + for( i = 0 ; i < i_max ; i++ ) + { + p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp ); + } + + return 0; +} + +/***************************************************************************** + * FreeVobuMap: frees structures allocated by ReadVobuMap + *****************************************************************************/ +static int FreeVobuMap( vobu_map_t * p_vobu_map ) +{ + free( p_vobu_map->pi_vobu_start_sector ); + + return 0; +} + +/* + * IFO virtual machine : a set of commands that give the + * interactive behaviour of the dvd + */ +#if 0 + +#define OP_VAL_16(i) (ntoh16( com.data.pi_16[i])) +#define OP_VAL_8(i) ((com.data.pi_8[i])) + +static char ifo_reg[][80]= +{ + "Menu_Language_Code", + "Audio_Stream_#", + "SubPicture_Stream_#", + "Angle_#", + "VTS_#", + "VTS_Title_#", + "PGC_#", + "PTT_#", + "Highlighted_Button_#", + "Nav_Timer", + "TimedPGC", + "Karaoke_audio_mixing_mode", + "Parental_mgmt_country_code", + "Parental_Level", + "Player_Video_Cfg", + "Player_Audio_Cfg", + "Audio_language_code_setting", + "Audio_language_extension_code", + "SPU_language_code_setting", + "SPU_language_extension_code", + "?Player_Regional_Code", + "Reserved_21", + "Reserved_22", + "Reserved_23" +}; + +static char * IfoMath( char val ) +{ + static char math_op[][10] = + { + "none", + "=", + "<->", // swap + "+=", + "-=", + "*=", + "/=", + "%=", + "rnd", // rnd + "&=", + "|=", + "^=", + "??", // invalid + "??", // invalid + "??", // invalid + "??" // invalid + }; + + return (char *) math_op[val & 0x0f]; +} + + +char ifo_cmp[][10] = +{ + "none", + "&&", + "==", + "!=", + ">=", + ">", + "<", + "<=" +}; + +char ifo_parental[][10] = +{ + "0", + "G", + "2", + "PG", + "PG-13", + "5", + "R", + "NC-17" +}; + +char ifo_menu_id[][80] = +{ + "-0-", + "-1-", + "Title (VTS menu)", + "Root", + "Sub-Picture", + "Audio", + "Angle", + "Part of Title", +}; + +char * IfoMenuName( char index ) +{ + return ifo_menu_id[index&0x07]; +} + +static void IfoRegister( u16 i_data, u8 i_direct) +{ + if( i_direct ) + { + if( 0/*isalpha( i_data >> 8 & 0xff )*/ ) + { + printf("'%c%c'", i_data>>8&0xff, i_data&0xff); + } + else + { + printf("0x%02x", i_data); + } + } + else + { + if( i_data & 0x80 ) + { + i_data &= 0x1f; + + if( i_data > 0x17 ) + { + printf("s[ILL]"); + } + else + { + printf("s[%s]", ifo_reg[i_data]); + } + } + else + { + i_data &= 0x1f; + + if( i_data > 0xf ) + { + printf("r[ILL]"); + } + else + { + printf("r[0x%02x]", i_data); + } + } + } +} + +static void IfoAdvanced( u8 *pi_code ) +{ + u8 i_cmd = pi_code[0]; + + printf(" { "); + + if( pi_code[1]>>2 ) + { + printf( " Highlight button %d; ", pi_code[1]>>2 ); + } + + if( i_cmd == 0xff ) + { + printf( " Illegal " ); + } + + if( i_cmd == 0x00 ) + { + printf( "ReSuME %d", pi_code[7] ); + } + else if( ( i_cmd & 0x06) == 0x02 ) + { // XX01Y + printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next"); + } + else + { + printf( "advanced (0x%02x) ", i_cmd ); + } + printf(" } "); +} + +static void IfoJmp( ifo_command_t com ) +{ + + printf ("jmp "); + + switch( com.i_sub_cmd ) + { + case 0x01: + printf( "Exit" ); + break; + case 0x02: + printf( "VTS 0x%02x", OP_VAL_8(3) ); + break; + case 0x03: + printf( "This VTS Title 0x%02x", OP_VAL_8(3) ); + break; + case 0x05: + printf( "This VTS Title 0x%02x Part 0x%04x", + OP_VAL_8(3), + OP_VAL_8(0)<<8|OP_VAL_8(1)); + break; + case 0x06: +#if 0 + printf ("in SystemSpace "); + switch (OP_VAL_8(3)>>4) { + case 0x00: + printf ("to play first PGC"); + break; + case 0x01: { + printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3))); + } + break; + case 0x02: + printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2)); + break; + case 0x03: + printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1)); + break; + case 0x08: + printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3))); + break; +#else + switch( OP_VAL_8(3)>>6 ) + { + case 0x00: + printf( "to play first PGC" ); + break; + case 0x01: + printf( "to VMG title menu (?)" ); + break; + case 0x02: + printf( "vts 0x%02x lu 0x%02x menu \"%s\"", + OP_VAL_8(2), + OP_VAL_8(1), + IfoMenuName( OP_VAL_8(3)&0xF ) ); + break; + case 0x03: + printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) ); + break; +#endif + } + break; + case 0x08: +#if 0 + switch(OP_VAL_8(3)>>4) { + case 0x00: + printf ("system first pgc"); + break; + case 0x01: + printf ("system title menu"); + break; + case 0x02: + printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3))); + break; + case 0x03: + printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1)); + break; + case 0x08: + printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3))); + break; + case 0x0c: + printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1)); + break; + } +#else + // OP_VAL_8(2) is number of cell + // it is processed BEFORE switch + // under some conditions, it is ignored + // I don't understand exactly what it means + printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) ); + + switch( OP_VAL_8(3)>>6 ) + { + case 0: + printf( "to FP PGC" ); + break; + case 1: + printf( "to VMG root menu (?)" ); + break; + case 2: + printf( "to VTS menu \"%s\" (?)", + IfoMenuName(OP_VAL_8(3)&0xF) ); + break; + case 3: + printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) ); + break; + } +#endif + break; + } +} + +static void IfoLnk( ifo_command_t com ) +{ + u16 i_button=OP_VAL_8(4)>>2; + + printf ("lnk to "); + + switch( com.i_sub_cmd ) + { + case 0x01: + IfoAdvanced( &OP_VAL_8(4) ); + break; + + case 0x04: + printf( "PGC 0x%02x", OP_VAL_16(2) ); + break; + + case 0x05: + printf( "PTT 0x%02x", OP_VAL_16(2) ); + break; + + case 0x06: + printf( "Program 0x%02x this PGC", OP_VAL_8(5) ); + break; + + case 0x07: + printf( "Cell 0x%02x this PGC", OP_VAL_8(5) ); + break; + default: + return; + } + + if( i_button ) + { + printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 ); + } + +} + +void IfoSetSystem( ifo_command_t com ) +{ + switch( com.i_cmd ) + { + case 1: { + int i; + + for( i=1; i<=3; i++ ) + { + if( OP_VAL_8(i)&0x80 ) + { + if( com.i_direct ) + { + printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf); + } + else + { + printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf); + } + } + } +#if 0 + if(op->direct) { + if(OP_VAL_8(1]&0x80) + printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf); + if(OP_VAL_8(2)&0x80) +//DENT: lwhat about 0x7f here ??? + printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f); + if(OP_VAL_8(3)&0x80) + printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf); + } else { + if(OP_VAL_8(1)&0x80) + printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf); + if(OP_VAL_8(2)&0x80) + printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf); + if(OP_VAL_8(3)&0x80) + printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf); + } +#endif + } + break; + case 2: + if( com.i_direct ) + { + printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) ); + } + else + { + printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f ); + } + + printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x", + ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000); + break; + case 3: + if( com.i_direct ) + { + printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) ); + } + else + { + printf ("r[r[0x%02x]] = r[0x%02x]", + OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f); + } + break; + case 4: + //actually only bits 00011100 00011100 are set + if( com.i_direct ) + { + printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1)); + } + else + { + printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f ); + } + break; + case 6: + //actually, + //s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA); + //but it is way too ugly + if( com.i_direct ) + { + printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 ); + } + else + { + printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f ); + } + break; + default: + printf ("unknown"); + } +} + +static void IfoSet( ifo_command_t com ) +{ + IfoRegister( OP_VAL_16(0), 0 ); + printf( " %s ", IfoMath( com.i_cmd ) ); + IfoRegister( OP_VAL_16(1), com.i_direct ); +} + +/***************************************************************************** + * CommandRead : translates the command strings in ifo into command + * structures. + *****************************************************************************/ +void CommandRead( ifo_command_t com ) +{ + u8* pi_code = (u8*)(&com); + + switch( com.i_type ) + { + /* Goto */ + case 0: + /* Main command */ + if( !pi_code[1] ) + { + printf( "NOP\n" ); + } + else + { + if( com.i_cmp ) + { + printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f, + ifo_cmp[com.i_cmp]); + IfoRegister (OP_VAL_16(1), com.i_dir_cmp); + printf (") "); + } + + /* Sub command */ + switch( com.i_sub_cmd ) + { + case 1: + printf( "goto Line 0x%02x", OP_VAL_16(2) ); + break; + + case 2: + printf( "stop VM" ); + break; + + case 3: + printf( "Set Parental Level To %s and goto Line 0x%02x", + ifo_parental[OP_VAL_8(4)&0x7], + OP_VAL_8(5) ); + break; + + default: + printf( "Illegal" ); + break; + } + } + break; + + /* Lnk */ + case 1: + /* Main command */ + if( !pi_code[1] ) + { + printf( "NOP\n" ); + } + else + { + if( com.i_direct ) + { + if( com.i_cmp ) + { + printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, + ifo_cmp[com.i_cmp] ); + IfoRegister( OP_VAL_8(5), 0 ); + printf( ") " ); + } + + /* Sub command */ + IfoJmp( com ); + } + else + { + if( com.i_cmp ) + { + printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f, + ifo_cmp[com.i_cmp] ); + IfoRegister( OP_VAL_16(1), com.i_dir_cmp ); + printf( ") " ); + } + + /* Sub command */ + IfoLnk( com ); + } + } + break; + + /* SetSystem */ + case 2: + if( !pi_code[1] ) + { + IfoSetSystem( com ); + } + else if( com.i_cmp && !com.i_sub_cmd ) + { + printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]); + IfoRegister( OP_VAL_8(5), 0 ); + printf (") "); + IfoSetSystem( com ); + } + else if( !com.i_cmp && com.i_sub_cmd ) + { + printf( "if (" ); + IfoSetSystem( com ); + printf( ") " ); + IfoLnk( com ); + } + else + { + printf("nop"); + } + break; + + /* Set */ + case 3: + if( ! pi_code[1] ) + { + IfoSet( com ); + } + else if( com.i_cmp && !com.i_sub_cmd ) + { + printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]); + IfoRegister( OP_VAL_16(2), com.i_dir_cmp ); + printf (") "); + IfoSet( com ); + } + else if( !com.i_cmp && com.i_sub_cmd ) + { + printf ("if ("); + IfoSet( com ); + printf (") "); + IfoLnk( com ); + } + else + { + printf( "nop" ); + } + break; + + /* + * math command on r[opcode[1]] and + * direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed + * ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)] + * are swapped ) + * boolean operation cmp on r[opcode[1]] and + * dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed + * on true result, buttons(c[6], c[7]) is called + * problem is 'what is buttons()' + */ + case 4: + printf( "r[0x%X] ", pi_code[1] ); + printf( " %s ", IfoMath( com.i_cmd ) ); + if( com.i_cmd == 2 ) + { + printf( "r[0x%X] ", OP_VAL_8(1) ); + } + else + { + IfoRegister( OP_VAL_16(0), com.i_direct ); + } + printf("; "); + + printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] ); + IfoRegister( OP_VAL_8(1), com.i_dir_cmp ); + printf( " ) then {" ); + IfoAdvanced( &OP_VAL_8(4) ); + printf( "}" ); + break; + + /* + * opposite to case 4: boolean, math and buttons. + */ + case 5: + case 6: + printf("if ("); + + if( !com.i_direct && com.i_dir_cmp ) + { + printf( "0x%X", OP_VAL_16(1) ); + } + else + { + IfoRegister( OP_VAL_8(3), 0 ); + if( OP_VAL_8(3)&0x80 ) + { + printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] ); + } + else + { + printf( "r[0x%X]", OP_VAL_8(3)&0x1F); + // 0x1F is either not a mistake, + // or Microsoft programmer's mistake!!! + } + } + + printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp], + com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) ); + printf( " ) then {" ); + printf( "r[0x%X] ", pi_code[1] & 0xF ); + printf( " %s ", IfoMath( com.i_cmd ) ); + + if( com.i_cmd == 0x02 ) // swap + { + printf("r[0x%X] ", OP_VAL_8(0)&0x1F); + } + else + { + if( com.i_direct ) + { + printf( "0x%X", OP_VAL_16(0) ); + } + else + { + if( OP_VAL_8(0) & 0x80 ) + { + printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] ); + } + else + { + printf("r[0x%X]", OP_VAL_8(0) & 0x1F ); + } + } + } + + printf("; "); + IfoAdvanced( &OP_VAL_8(4) ); + printf("}"); + + break; + + default: + printf( "Unknown Command\n" ); + break; + } + + return; +} + +/***************************************************************************** + * CommandPrint : print in clear text (I hope so !) what a command does + *****************************************************************************/ +void CommandPrint( ifo_t ifo ) +{ + return; +} + +#endif + +/***************************************************************************** + * ReadByte and so + *****************************************************************************/ +static u8* FillBuffer( ifo_t* p_ifo, u8* p_buf, int i_pos ) +{ + p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS ); + dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS ); + + return p_buf; +} + +static void ReadBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, + u8* pi_dest, int i_nb ) +{ + if( i_nb > DVD_LB_SIZE ) + { +//X intf_Err( p_input, "excessive ReadBytes call (%i)", i_nb ); + } + + if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE ) + { + int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp ); + + /* Copy the bytes remaining in the current buffer */ + memcpy( pi_dest, *pp_tmp, i_spare ); + pi_dest += i_spare; + i_nb -= i_spare; + + /* Load the next buffer */ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); + } + + memcpy( pi_dest, *pp_tmp, i_nb ); + *pp_tmp += i_nb; + + return; +} + +static void DumpBytes( ifo_t* p_ifo, u8* p_buf, u8** pp_tmp, int i_nb ) +{ + if( i_nb > DVD_LB_SIZE ) + { +//X intf_Err( p_input, "excessive DumpBytes call (%i)", i_nb ); + } + + *pp_tmp += i_nb; + + if( *pp_tmp >= p_buf + DVD_LB_SIZE ) + { + /* If we went too far, load the next buffer */ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ) + + (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) ); + } + + return; +} + +#define ADDBYTE \ + if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \ + { \ + *pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \ + } \ + i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++; + +static u8 ReadByte( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u8 i_ret = 0; + ADDBYTE; + return i_ret; +} + +static u16 ReadWord( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u16 i_ret = 0; + ADDBYTE; ADDBYTE; + return i_ret; +} + +static u32 ReadDouble( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u32 i_ret = 0; + ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; + return i_ret; +} + +static u64 ReadQuad( ifo_t * p_ifo, u8* p_buf, u8** pp_tmp ) +{ + u64 i_ret = 0; + ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; + return i_ret; +} + diff --git a/modules/access/dvd/ifo.h b/modules/access/dvd/ifo.h new file mode 100644 index 0000000000..e07a2dee40 --- /dev/null +++ b/modules/access/dvd/ifo.h @@ -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 + * + * based on: + * - libifo by Thomas Mirlacher + * - 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; // 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; // 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 * ); + diff --git a/modules/access/dvd/seek.c b/modules/access/dvd/seek.c new file mode 100644 index 0000000000..35524c26f5 --- /dev/null +++ b/modules/access/dvd/seek.c @@ -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 + * + * 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 +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#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 diff --git a/modules/access/dvd/seek.h b/modules/access/dvd/seek.h new file mode 100644 index 0000000000..5b334a1b91 --- /dev/null +++ b/modules/access/dvd/seek.h @@ -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 + * + * 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 ); + diff --git a/modules/access/dvd/summary.c b/modules/access/dvd/summary.c new file mode 100644 index 0000000000..f6837be007 --- /dev/null +++ b/modules/access/dvd/summary.c @@ -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 + * + * 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 +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#if !defined( WIN32 ) +# include +#endif + +#include +#include + +#include +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif +#include + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#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 diff --git a/modules/access/dvd/summary.h b/modules/access/dvd/summary.h new file mode 100644 index 0000000000..9deda0e399 --- /dev/null +++ b/modules/access/dvd/summary.h @@ -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 + * + * 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 ); + + diff --git a/modules/access/dvd/udf.c b/modules/access/dvd/udf.c new file mode 100644 index 0000000000..53e88db892 --- /dev/null +++ b/modules/access/dvd/udf.c @@ -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 + * + * based on: + * - dvdudf by Christian Wolff + * - fixes by Billy Biggs + * + * 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 +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#ifdef GOD_DAMN_DMCA +# include "dvdcss.h" +#else +# include +#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; +} + diff --git a/modules/access/dvd/udf.h b/modules/access/dvd/udf.h new file mode 100644 index 0000000000..84b35f266f --- /dev/null +++ b/modules/access/dvd/udf.h @@ -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 + * + * based on: + * - dvdudf by Christian Wolff + * + * 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 * ); + diff --git a/modules/access/dvdplay/.cvsignore b/modules/access/dvdplay/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/dvdplay/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/dvdplay/Makefile b/modules/access/dvdplay/Makefile new file mode 100644 index 0000000000..2d87cf4444 --- /dev/null +++ b/modules/access/dvdplay/Makefile @@ -0,0 +1 @@ +dvdplay_SOURCES = dvd.c access.c demux.c intf.c es.c tools.c diff --git a/modules/access/dvdplay/access.c b/modules/access/dvdplay/access.c new file mode 100644 index 0000000000..7161c83536 --- /dev/null +++ b/modules/access/dvdplay/access.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 + * + * 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 +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#if defined( WIN32 ) +# include /* read() */ +#else +# include /* 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; +} diff --git a/modules/access/dvdplay/access.h b/modules/access/dvdplay/access.h new file mode 100644 index 0000000000..5fb5189409 --- /dev/null +++ b/modules/access/dvdplay/access.h @@ -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 + * + * 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 * ); diff --git a/modules/access/dvdplay/demux.c b/modules/access/dvdplay/demux.c new file mode 100644 index 0000000000..021f5c7ced --- /dev/null +++ b/modules/access/dvdplay/demux.c @@ -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 + * + * 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 +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#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; +} + diff --git a/modules/access/dvdplay/demux.h b/modules/access/dvdplay/demux.h new file mode 100644 index 0000000000..72a12059b5 --- /dev/null +++ b/modules/access/dvdplay/demux.h @@ -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 + * + * 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 * ); diff --git a/modules/access/dvdplay/dvd.c b/modules/access/dvdplay/dvd.c new file mode 100644 index 0000000000..28aa113884 --- /dev/null +++ b/modules/access/dvdplay/dvd.c @@ -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 + * + * 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 /* malloc(), free() */ +#include /* strdup() */ + +#include + +/***************************************************************************** + * 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(); + diff --git a/modules/access/dvdplay/dvd.h b/modules/access/dvdplay/dvd.h new file mode 100644 index 0000000000..b1418a67f1 --- /dev/null +++ b/modules/access/dvdplay/dvd.h @@ -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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; + diff --git a/modules/access/dvdplay/es.c b/modules/access/dvdplay/es.c new file mode 100644 index 0000000000..a09e133f31 --- /dev/null +++ b/modules/access/dvdplay/es.c @@ -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 + * + * 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 +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#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 ); +} + + diff --git a/modules/access/dvdplay/es.h b/modules/access/dvdplay/es.h new file mode 100644 index 0000000000..013305f2e6 --- /dev/null +++ b/modules/access/dvdplay/es.h @@ -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 + * + * 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 * ); diff --git a/modules/access/dvdplay/intf.c b/modules/access/dvdplay/intf.c new file mode 100644 index 0000000000..7c10f201ad --- /dev/null +++ b/modules/access/dvdplay/intf.c @@ -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 + * + * 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 /* malloc(), free() */ +#include +#include + +#include +#include + +#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; +} + + diff --git a/modules/access/dvdplay/intf.h b/modules/access/dvdplay/intf.h new file mode 100644 index 0000000000..f04a2d8fd0 --- /dev/null +++ b/modules/access/dvdplay/intf.h @@ -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 + * + * 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 ); diff --git a/modules/access/dvdplay/tools.c b/modules/access/dvdplay/tools.c new file mode 100644 index 0000000000..709fe72b28 --- /dev/null +++ b/modules/access/dvdplay/tools.c @@ -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 + * + * 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 +#include +#include +#include + +#include + +#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; +} diff --git a/modules/access/dvdplay/tools.h b/modules/access/dvdplay/tools.h new file mode 100644 index 0000000000..e0b612f994 --- /dev/null +++ b/modules/access/dvdplay/tools.h @@ -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 + * + * 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* ); diff --git a/modules/access/dvdread/.cvsignore b/modules/access/dvdread/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/dvdread/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/dvdread/Makefile b/modules/access/dvdread/Makefile new file mode 100644 index 0000000000..6e7cf66cbd --- /dev/null +++ b/modules/access/dvdread/Makefile @@ -0,0 +1 @@ +dvdread_SOURCES = dvdread.c input.c diff --git a/modules/access/dvdread/dvdread.c b/modules/access/dvdread/dvdread.c new file mode 100644 index 0000000000..6414f6f05b --- /dev/null +++ b/modules/access/dvdread/dvdread.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 + * + * 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 /* malloc(), free() */ +#include /* strdup() */ + +#include + +/***************************************************************************** + * 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(); + diff --git a/modules/access/dvdread/input.c b/modules/access/dvdread/input.c new file mode 100644 index 0000000000..82380ee426 --- /dev/null +++ b/modules/access/dvdread/input.c @@ -0,0 +1,1233 @@ +/***************************************************************************** + * input.c: DvdRead plugin. + ***************************************************************************** + * This plugins should handle all the known specificities of the DVD format, + * especially the 2048 bytes logical block size. + * It depends on: libdvdread for ifo files and block reading. + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: input.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Author: Stéphane Borel + * + * Some code taken form the play_title.c by Billy Biggs + * in libdvdread. + * + * 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 +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif + +#if defined( WIN32 ) +# include /* read() */ +#else +# include /* struct iovec */ +#endif + +#if defined( WIN32 ) +# include "input_iovec.h" +#endif + +#include +#include +#include +#include +#include + +#include "input.h" + +#include "iso_lang.h" + +/* how many blocks DVDRead will read in each loop */ +#define DVD_BLOCK_READ_ONCE 64 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +/* called from outside */ +static int DvdReadDemux ( input_thread_t * ); +static int DvdReadRewind ( input_thread_t * ); + +static int DvdReadSetArea ( input_thread_t *, input_area_t * ); +static int DvdReadSetProgram ( input_thread_t *, pgrm_descriptor_t * ); +static int DvdReadRead ( input_thread_t *, byte_t *, size_t ); +static void DvdReadSeek ( input_thread_t *, off_t ); + +/* called only from here */ +static void DvdReadLauchDecoders( input_thread_t * p_input ); +static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, u8 * p_data ); +static void DvdReadFindCell ( thread_dvd_data_t * p_dvd ); + +/* + * Data demux functions + */ + +/***************************************************************************** + * InitDVD: initializes DVD structures + *****************************************************************************/ +int E_(InitDVD) ( 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 = DvdReadDemux; + p_input->pf_rewind = NULL; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + DvdReadLauchDecoders( p_input ); + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return 0; +} + +/***************************************************************************** + * DvdReadDemux + *****************************************************************************/ +#define PEEK( SIZE ) \ + i_result = input_Peek( p_input, &p_peek, SIZE ); \ + if( i_result == -1 ) \ + { \ + return( -1 ); \ + } \ + else if( i_result < SIZE ) \ + { \ + /* EOF */ \ + return( 0 ); \ + } + +static int DvdReadDemux( input_thread_t * p_input ) +{ + int i; + byte_t * p_peek; + data_packet_t * p_data; + ssize_t i_result; + int i_packet_size; + + + /* Read headers to compute payload length */ + for( i = 0 ; i < DVD_BLOCK_READ_ONCE ; i++ ) + { + + /* Read what we believe to be a packet header. */ + PEEK( 4 ); + + /* Default header */ + if( U32_AT( p_peek ) != 0x1BA ) + { + /* That's the case for all packets, except pack header. */ + i_packet_size = U16_AT( p_peek + 4 ); + } + else + { + /* MPEG-2 Pack header. */ + i_packet_size = 8; + } + + /* Fetch a packet of the appropriate size. */ + i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 ); + if( i_result <= 0 ) + { + return( i_result ); + } + + /* In MPEG-2 pack headers we still have to read stuffing bytes. */ + if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) ) + { + size_t i_stuffing = (p_data->p_demux_start[13] & 0x7); + /* Force refill of the input buffer - though we don't care + * about p_peek. Please note that this is unoptimized. */ + PEEK( i_stuffing ); + p_input->p_current_data += i_stuffing; + } + + input_DemuxPS( p_input, p_data ); + + } + + return i; +} + +/***************************************************************************** + * DVDRewind : reads a stream backward + *****************************************************************************/ +static int DvdReadRewind( input_thread_t * p_input ) +{ + return( -1 ); +} + +/* + * Data access functions + */ + +/***************************************************************************** + * OpenDVD: open libdvdread + *****************************************************************************/ +int E_(OpenDVD) ( 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_dvd_data_t * p_dvd; + dvd_reader_t * p_dvdread; + input_area_t * p_area; + int i_title = 1; + int i_chapter = 1; + int i_angle = 1; + int i; + + psz_orig = psz_parser = psz_source = strdup( p_input->psz_name ); + if( !psz_orig ) + { + return( -1 ); + } + + p_input->pf_read = DvdReadRead; + p_input->pf_seek = DvdReadSeek; + p_input->pf_set_area = DvdReadSetArea; + p_input->pf_set_program = DvdReadSetProgram; + + 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 ); + if( *psz_next ) + { + i_angle = (int)strtol( psz_next + 1, NULL, 10 ); + } + } + + i_title = i_title ? i_title : 1; + i_chapter = i_chapter ? i_chapter : 1; + i_angle = i_angle ? i_angle : 1; + } + + if( !*psz_source ) + { + if( !p_input->psz_access ) + { + free( psz_orig ); + return -1; + } + 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( -1 ); + } + if( !S_ISBLK(stat_info.st_mode) && + !S_ISCHR(stat_info.st_mode) && + !S_ISDIR(stat_info.st_mode) ) + { + msg_Warn( p_input, "dvdread module discarded (not a valid source)" ); + return -1; + } + + msg_Dbg( p_input, "dvdroot=%s title=%d chapter=%d angle=%d", + psz_source, i_title, i_chapter, i_angle ); + + + p_dvdread = DVDOpen( psz_source ); + + /* free allocated strings */ + if( psz_source != psz_orig ) + free( psz_source ); + free( psz_orig ); + + if( ! p_dvdread ) + { + msg_Err( p_input, "libdvdcss cannot open source" ); + return -1; + } + + /* set up input */ + p_input->i_mtu = 0; + + p_dvd = malloc( sizeof(thread_dvd_data_t) ); + if( p_dvd == NULL ) + { + msg_Err( p_input, "out of memory" ); + return -1; + } + + p_dvd->p_dvdread = p_dvdread; + p_dvd->p_title = NULL; + p_dvd->p_vts_file = NULL; + + + p_input->p_access_data = (void *)p_dvd; + + /* Ifo allocation & initialisation */ + if( ! ( p_dvd->p_vmg_file = ifoOpen( p_dvd->p_dvdread, 0 ) ) ) + { + msg_Err( p_input, "cannot open VMG info" ); + free( p_dvd ); + return -1; + } + msg_Dbg( p_input, "VMG opened" ); + + /* Set stream and area data */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_input->stream.i_method = INPUT_METHOD_DVD; + + /* If we are here we can control the pace... */ + 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 ) ); + + /* disc input method */ + p_input->stream.i_method = INPUT_METHOD_DVD; + +#define tt_srpt p_dvd->p_vmg_file->tt_srpt + msg_Dbg( p_input, "number of titles: %d", tt_srpt->nr_of_srpts ); + +#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 <= tt_srpt->nr_of_srpts ; 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 = tt_srpt->title[i-1].nr_of_ptts; + area[i]->i_part = 1; + + area[i]->i_plugin_data = tt_srpt->title[i-1].title_set_nr; + } +#undef area + + p_dvd->i_title = i_title <= tt_srpt->nr_of_srpts ? i_title : 1; +#undef tt_srpt + + p_area = p_input->stream.pp_areas[p_dvd->i_title]; + p_dvd->i_chapter = i_chapter; + + p_dvd->i_chapter = i_chapter < p_area->i_part_nb ? i_chapter : 1; + p_area->i_part = p_dvd->i_chapter; + + p_dvd->i_angle = i_angle; + + /* set title, chapter, audio and subpic */ + if( DvdReadSetArea( p_input, p_area ) ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return -1; + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + p_input->psz_demux = "dvdread"; + + return 0; +} + +/***************************************************************************** + * CloseDVD: close libdvdread + *****************************************************************************/ +void E_(CloseDVD) ( 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; + + /* close libdvdread */ + DVDCloseFile( p_dvd->p_title ); + ifoClose( p_dvd->p_vts_file ); + ifoClose( p_dvd->p_vmg_file ); + + DVDClose( p_dvd->p_dvdread ); + free( p_dvd ); + p_input->p_access_data = NULL; + +} + +/***************************************************************************** + * DvdReadSetProgram: Does nothing, a DVD is mono-program + *****************************************************************************/ +static int DvdReadSetProgram( 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; + + p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); + p_dvd->i_angle = p_program->i_number; + + memcpy( p_program, p_input->stream.p_selected_program, + sizeof(pgrm_descriptor_t) ); + p_program->i_number = p_dvd->i_angle; + p_input->stream.p_selected_program = p_program; + + msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle ); + } + + return 0; +} + +#define p_pgc p_dvd->p_cur_pgc + +/***************************************************************************** + * DvdReadSetArea: 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 DvdReadSetArea( input_thread_t * p_input, input_area_t * p_area ) +{ + thread_dvd_data_t * p_dvd; + int pgc_id = 0; + int pgn = 0; + + 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 ) + { + es_descriptor_t * p_es; + int i_cell = 0; + int i_audio_nb = 0; + int i_spu_nb = 0; + int i; + +#define p_vmg p_dvd->p_vmg_file +#define p_vts p_dvd->p_vts_file + if( p_dvd->p_title != NULL ) + { + DVDCloseFile( p_dvd->p_title ); + } + + if( p_vts != NULL ) + { + ifoClose( p_vts ); + } + + /* Reset the Chapter position of the old title */ + p_input->stream.p_selected_area->i_part = 1; + + /* + * We have to load all title information + */ + /* Change the default area */ + p_input->stream.p_selected_area = p_area; + + msg_Dbg( p_input, "open VTS %d, for title %d", + p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr, + p_area->i_id ); + + /* ifo vts */ + if( ! ( p_vts = ifoOpen( p_dvd->p_dvdread, + p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr ) ) ) + { + msg_Err( p_input, "fatal error in vts ifo" ); + ifoClose( p_vmg ); + DVDClose( p_dvd->p_dvdread ); + return -1; + } + + /* title position inside the selected vts */ + p_dvd->i_ttn = p_vmg->tt_srpt->title[ p_area->i_id - 1 ].vts_ttn; + + /* + * Set selected title start + */ + pgc_id = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgcn; + pgn = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgn; + p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc; + i_cell = p_pgc->program_map[ pgn - 1 ] - 1; + + p_area->i_start = + LB2OFF( p_dvd->p_cur_pgc->cell_playback[ i_cell ].first_sector ); + + msg_Dbg( p_input, "start %d vts_title %d pgc %d pgn %d", + p_area->i_id, p_dvd->i_ttn, pgc_id, pgn ); + + /* + * Find title end + */ + i_cell = p_dvd->p_cur_pgc->nr_of_cells - 1; + + p_dvd->i_end_block = p_pgc->cell_playback[ i_cell ].last_sector; + p_area->i_size = LB2OFF( p_dvd->i_end_block )- p_area->i_start; + + msg_Dbg( p_input, "start %lld size %lld end %d", + p_area->i_start , p_area->i_size, p_dvd->i_end_block ); + + /* + * Set properties for current chapter + */ + /* Remeber current chapter */ + p_dvd->i_chapter = p_area->i_part; + p_dvd->b_eoc = 0; + + pgc_id = p_vts->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn; + pgn = p_vts->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn; + + p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; + p_dvd->i_pack_len = 0; + p_dvd->i_next_cell = p_dvd->i_cur_cell = p_pgc->program_map[pgn-1] - 1; + DvdReadFindCell( p_dvd ); + + p_dvd->i_next_vobu = p_dvd->i_cur_block = + p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; + + /* + * Angle management + */ + p_dvd->i_angle_nb = p_vmg->tt_srpt->title[p_area->i_id-1].nr_of_angles; + + if( p_dvd->i_angle > p_dvd->i_angle_nb ) + { + p_dvd->i_angle = 1; + } + + /* + * We've got enough info, time to open the title set data. + */ + if( ! ( p_dvd->p_title = DVDOpenFile( p_dvd->p_dvdread, + p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr, + DVD_READ_TITLE_VOBS ) ) ) + { + msg_Err( p_input, "cannot open title (VTS_%02d_1.VOB)", + p_vmg->tt_srpt->title[p_area->i_id-1].title_set_nr ); + ifoClose( p_vts ); + ifoClose( p_vmg ); + DVDClose( p_dvd->p_dvdread ); + return -1; + } + +// IfoPrintTitle( p_dvd ); + + /* + * Destroy obsolete ES by reinitializing program 0 + * and find all ES in title with ifo data + */ + 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; + } + + 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 < p_dvd->i_angle_nb ; i++ ) + { + input_AddProgram( p_input, i+1, 0 ); + } + + DvdReadSetProgram( p_input, + p_input->stream.pp_programs[p_dvd->i_angle-1] ); + + /* No PSM to read in DVD mode, we already have all information */ + p_input->stream.p_selected_program->b_is_ok = 1; + + p_es = NULL; + + /* ES 0 -> video MPEG2 */ +// IfoPrintVideo( p_dvd ); + + p_es = input_AddES( p_input, NULL, 0xe0, 0 ); + p_es->i_stream_id = 0xe0; + p_es->i_fourcc = VLC_FOURCC('m','p','g','v'); + p_es->i_cat = VIDEO_ES; + +#define audio_control \ + p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1] + /* Audio ES, in the order they appear in .ifo */ + for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams ; i++ ) + { + int i_position = 0; + u16 i_id; + +// IfoPrintAudio( p_dvd, i ); + + /* audio channel is active if first byte is 0x80 */ + if( audio_control & 0x8000 ) + { + i_audio_nb++; + i_position = ( audio_control & 0x7F00 ) >> 8; + + msg_Dbg( p_input, "audio position %d", i_position ); + switch( p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format ) + { + case 0x00: /* A52 */ + i_id = ( ( 0x80 + i_position ) << 8 ) | 0xbd; + p_es = input_AddES( p_input, NULL, i_id, 0 ); + p_es->i_stream_id = 0xbd; + p_es->i_fourcc = VLC_FOURCC('a','5','2',' '); + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( + p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ); + strcat( p_es->psz_desc, " (A52)" ); + + break; + case 0x02: + case 0x03: /* MPEG audio */ + i_id = 0xc0 + i_position; + p_es = input_AddES( p_input, NULL, i_id, 0 ); + p_es->i_stream_id = i_id; + p_es->i_fourcc = VLC_FOURCC('m','p','g','a'); + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( + p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ); + strcat( p_es->psz_desc, " (mpeg)" ); + + break; + case 0x04: /* LPCM */ + + i_id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd; + p_es = input_AddES( p_input, NULL, i_id, 0 ); + p_es->i_stream_id = i_id; + p_es->i_fourcc = VLC_FOURCC('l','p','c','m'); + p_es->i_cat = AUDIO_ES; + strcpy( p_es->psz_desc, DecodeLanguage( + p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) ); + strcat( p_es->psz_desc, " (lpcm)" ); + + break; + case 0x06: /* DTS */ + i_id = ( ( 0x88 + 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", + p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format ); + } + } + } +#undef audio_control +#define spu_control \ + p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1] + + /* Sub Picture ES */ + + for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ ) + { + int i_position = 0; + u16 i_id; + +// IfoPrintSpu( p_dvd, i ); + msg_Dbg( p_input, "spu %d 0x%02x", i, spu_control ); + + if( spu_control & 0x80000000 ) + { + i_spu_nb++; + + /* there are several streams for one spu */ + if( p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) + { + /* 16:9 */ + switch( p_vts->vtsi_mat->vts_video_attr.permitted_df ) + { + case 1: + i_position = spu_control & 0xff; + break; + case 2: + i_position = ( spu_control >> 8 ) & 0xff; + break; + default: + i_position = ( spu_control >> 16 ) & 0xff; + break; + } + } + else + { + /* 4:3 */ + i_position = ( spu_control >> 24 ) & 0x7F; + } + + i_id = ( ( 0x20 + i_position ) << 8 ) | 0xbd; + p_es = input_AddES( p_input, NULL, i_id, 0 ); + p_es->i_stream_id = 0xbd; + p_es->i_fourcc = VLC_FOURCC('s','p','u',' '); + p_es->i_cat = SPU_ES; + strcpy( p_es->psz_desc, DecodeLanguage( + p_vts->vtsi_mat->vts_subp_attr[i-1].lang_code ) ); + } + } +#undef spu_control + + /* FIXME: hack to check that the demuxer is ready, and set + * the decoders */ + if( p_input->p_demux ) + { + DvdReadLauchDecoders( p_input ); + } + + } /* i_title >= 0 */ + else + { + p_area = p_input->stream.p_selected_area; + } + + /* + * Chapter selection + */ + + if( p_area->i_part != p_dvd->i_chapter ) + { + if( ( p_area->i_part > 0 ) && + ( p_area->i_part <= p_area->i_part_nb )) + { + p_dvd->i_ttn = p_vmg->tt_srpt->title[p_area->i_id-1].vts_ttn; + pgc_id = p_vts->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn; + pgn = p_vts->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn; + + p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc; + + p_dvd->i_cur_cell = p_pgc->program_map[ pgn - 1 ] - 1; + p_dvd->i_chapter = p_area->i_part; + DvdReadFindCell( p_dvd ); + + p_dvd->i_pack_len = 0; + p_dvd->i_next_vobu = p_dvd->i_cur_block = + p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; + } + else + { + p_area->i_part = p_dvd->i_chapter; + } + } +#undef p_vts +#undef p_vmg + + /* warn interface that something has changed */ + p_area->i_tell = LB2OFF( p_dvd->i_next_vobu ) - p_area->i_start; + p_input->stream.b_seekable = 1; + p_input->stream.b_changed = 1; + + return 0; +} + + +/***************************************************************************** + * DvdReadRead: reads data packets into the netlist. + ***************************************************************************** + * Returns -1 in case of error, 0 if everything went well, and 1 in case of + * EOF. + *****************************************************************************/ +static int DvdReadRead( input_thread_t * p_input, + byte_t * p_buffer, size_t i_count ) +{ + thread_dvd_data_t * p_dvd; + byte_t * p_buf; + int i_blocks_once; + int i_blocks; + int i_read; + int i_read_total; + vlc_bool_t b_eot = 0; + + p_dvd = (thread_dvd_data_t *)p_input->p_access_data; + p_buf = p_buffer; + + /* + * Playback by cell in this pgc, starting at the cell for our chapter. + */ + i_blocks = OFF2LB( i_count ); + i_read_total = 0; + i_read = 0; + + while( i_blocks ) + { + /* + * End of pack, we select the following one + */ + if( ! p_dvd->i_pack_len ) + { + /* + * Read NAV packet. + */ + if( ( i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_next_vobu, + 1, p_buf ) ) != 1 ) + { + msg_Err( p_input, "read failed for block %d", + p_dvd->i_next_vobu ); + return -1; + } + + /* basic check to be sure we don't have a empty title + * go to next title if so */ + //assert( p_buffer[41] == 0xbf && p_buffer[1027] == 0xbf ); + + /* + * Parse the contained dsi packet. + */ + + DvdReadHandleDSI( p_dvd, p_buf ); + + /* End of File */ + if( p_dvd->i_next_vobu >= p_dvd->i_end_block + 1 ) + { + return 1; + } + + assert( p_dvd->i_pack_len < 1024 ); + /* FIXME: Ugly kludge: we send the pack block to the input for it + * sometimes has a zero scr and restart the sync */ + p_dvd->i_cur_block ++; + //p_dvd->i_pack_len++; + + i_read_total++; + p_buf += DVD_VIDEO_LB_LEN; + i_blocks--; + } + + /* + * Compute the number of blocks to read + */ + i_blocks_once = p_dvd->i_pack_len >= i_blocks + ? i_blocks : p_dvd->i_pack_len; + p_dvd->i_pack_len -= i_blocks_once; + + /* Reads from DVD */ + i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_cur_block, + i_blocks_once, p_buf ); + if( i_read != i_blocks_once ) + { + msg_Err( p_input, "read failed for %d/%d blocks at 0x%02x", + i_read, i_blocks_once, p_dvd->i_cur_block ); + return -1; + } + + i_blocks -= i_read; + i_read_total += i_read; + p_dvd->i_cur_block += i_read; + p_buf += LB2OFF( i_read ); + + } +/* + msg_Dbg( p_input, "i_blocks: %d len: %d current: 0x%02x", i_read, p_dvd->i_pack_len, p_dvd->i_cur_block ); +*/ + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_input->stream.p_selected_area->i_tell = + LB2OFF( p_dvd->i_cur_block ) - + p_input->stream.p_selected_area->i_start; + + if( p_dvd->b_eoc ) + { + /* We modify i_part only at end of chapter not to erase + * some modification from the interface */ + p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; + p_dvd->b_eoc = 0; + } + + if( p_input->stream.p_selected_area->i_tell + >= p_input->stream.p_selected_area->i_size || b_eot ) + { + if( ( p_input->stream.p_selected_area->i_id + 1 ) >= + p_input->stream.i_area_nb ) + { + /* EOF */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return 1; + } + + /* EOT */ + msg_Dbg( p_input, "new title" ); + DvdReadSetArea( p_input, p_input->stream.pp_areas[ + p_input->stream.p_selected_area->i_id+1] ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return 0; + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return LB2OFF( i_read_total ); +} +#undef p_pgc + +/***************************************************************************** + * DvdReadSeek : 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 DvdReadSeek( input_thread_t * p_input, off_t i_off ) +{ + thread_dvd_data_t * p_dvd; + int i_lb; + int i_tmp; + int i_chapter = 0; + int i_cell = 0; + int i_vobu = 0; + int i_sub_cell = 0; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + i_off += p_input->stream.p_selected_area->i_start; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + i_lb = OFF2LB( i_off ); + p_dvd = ( thread_dvd_data_t * )p_input->p_access_data; + + /* find cell */ + while( p_dvd->p_cur_pgc->cell_playback[i_cell].last_sector < i_lb ) + { + i_cell++; + } + + /* find chapter */ + do + { + pgc_t * p_pgc; + int pgc_id, pgn; + + i_chapter++; + pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[i_chapter-1].pgcn; + pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[i_chapter-1].pgn; + + p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; + i_tmp = p_pgc->program_map[pgn-1]; + + } while( i_tmp <= i_cell ); + + /* find vobu */ + while( p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu] + <= i_lb ) + { + i_vobu++; + } + + /* find sub_cell */ + while( p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell].start_sector < + p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu-1] ) + { + i_sub_cell++; + } + +/* + msg_Dbg( p_input, "cell %d i_sub_cell %d chapter %d vobu %d cell_sector %d vobu_sector %d sub_cell_sector %d", + i_cell, i_sub_cell,i_chapter, i_vobu, + p_dvd->p_cur_pgc->cell_playback[i_cell].first_sector, + p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu], + p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell-1].start_sector); +*/ + p_dvd->i_cur_block = i_lb; + p_dvd->i_next_vobu = + p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu]; + p_dvd->i_pack_len = p_dvd->i_next_vobu - i_lb; + p_dvd->i_cur_cell = i_cell; + p_dvd->i_chapter = i_chapter; + DvdReadFindCell( p_dvd ); + + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.p_selected_area->i_tell = + LB2OFF ( p_dvd->i_cur_block ) + - p_input->stream.p_selected_area->i_start; + p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return; +} + +/***************************************************************************** + * DvdReadHandleDSI + *****************************************************************************/ +static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, u8 * p_data ) +{ + navRead_DSI( &(p_dvd->dsi_pack), &(p_data[ DSI_START_BYTE ]) ); + + /* + * Determine where we go next. These values are the ones we mostly + * care about. + */ + p_dvd->i_cur_block = p_dvd->dsi_pack.dsi_gi.nv_pck_lbn; + + /* + * If we're not at the end of this cell, we can determine the next + * VOBU to display using the VOBU_SRI information section of the + * DSI. Using this value correctly follows the current angle, + * avoiding the doubled scenes in The Matrix, and makes our life + * really happy. + */ + if( p_dvd->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) + { +#if 1 + switch( ( p_dvd->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 ) + { + case 0x4: + /* interleaved unit with no angle */ + if( p_dvd->dsi_pack.sml_pbi.ilvu_sa != -1 ) + { + p_dvd->i_next_vobu = p_dvd->i_cur_block + + p_dvd->dsi_pack.sml_pbi.ilvu_sa; + p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea; + } + else + { + p_dvd->i_next_vobu = p_dvd->i_cur_block + + p_dvd->dsi_pack.dsi_gi.vobu_ea + 1; + p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; + } + break; + case 0x5: + /* vobu is end of ilvu */ + if( p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address ) + { + p_dvd->i_next_vobu = p_dvd->i_cur_block + + p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address; + p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea; + + break; + } + case 0x6: + /* vobu is beginning of ilvu */ + case 0x9: + /* next scr is 0 */ + case 0xa: + /* entering interleaved section */ + case 0x8: + /* non interleaved cells in interleaved section */ + default: + p_dvd->i_next_vobu = p_dvd->i_cur_block + + ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; + break; + } +#else + p_dvd->i_next_vobu = p_dvd->i_cur_block + + ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; +#endif + } + else + { + p_dvd->i_cur_cell = p_dvd->i_next_cell; + DvdReadFindCell( p_dvd ); + + p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; + p_dvd->i_next_vobu = + p_dvd->p_cur_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; + } + +#if 0 + msg_Dbg( p_input, 12, "scr %d lbn 0x%02x vobu_ea %d vob_id %d c_id %d", + p_dvd->dsi_pack.dsi_gi.nv_pck_scr, + p_dvd->dsi_pack.dsi_gi.nv_pck_lbn, + p_dvd->dsi_pack.dsi_gi.vobu_ea, + p_dvd->dsi_pack.dsi_gi.vobu_vob_idn, + p_dvd->dsi_pack.dsi_gi.vobu_c_idn ); + + msg_Dbg( p_input, 12, "cat 0x%02x ilvu_ea %d ilvu_sa %d size %d", + p_dvd->dsi_pack.sml_pbi.category, + p_dvd->dsi_pack.sml_pbi.ilvu_ea, + p_dvd->dsi_pack.sml_pbi.ilvu_sa, + p_dvd->dsi_pack.sml_pbi.size ); + + msg_Dbg( p_input, 12, "next_vobu %d next_ilvu1 %d next_ilvu2 %d", + p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff, + p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle - 1 ].address, + p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle ].address); +#endif +} + +/***************************************************************************** + * DvdReadFindCell + *****************************************************************************/ +static void DvdReadFindCell( thread_dvd_data_t * p_dvd ) +{ + int pgc_id, pgn; + int i = 0; + pgc_t * p_pgc; +#define cell p_dvd->p_cur_pgc->cell_playback + if( cell[p_dvd->i_cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) + { +#if 0 + p_dvd->i_next_cell = p_dvd->i_cur_cell + p_dvd->i_angle_nb; + p_dvd->i_cur_cell += p_dvd->i_angle - 1; +#else + p_dvd->i_cur_cell += p_dvd->i_angle - 1; + + while( cell[p_dvd->i_cur_cell+i].block_mode != BLOCK_MODE_LAST_CELL ) + { + i++; + } + p_dvd->i_next_cell = p_dvd->i_cur_cell + i + 1; +#endif + } + else + { + p_dvd->i_next_cell = p_dvd->i_cur_cell + 1; + } +#undef cell + pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_dvd->i_chapter-1].pgcn; + pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[ + p_dvd->i_ttn-1].ptt[p_dvd->i_chapter-1].pgn; + p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + if( p_pgc->program_map[pgn-1] <= p_dvd->i_cur_cell ) + { + p_dvd->i_chapter++; + p_dvd->b_eoc = 1; + } +} + +/***************************************************************************** + * DvdReadLaunchDecoders + *****************************************************************************/ +static void DvdReadLauchDecoders( input_thread_t * p_input ) +{ + thread_dvd_data_t * p_dvd; + + p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); + + if( config_GetInt( p_input, "video" ) ) + { + input_SelectES( p_input, p_input->stream.pp_es[0] ); + } + + if( config_GetInt( p_input, "audio" ) ) + { + /* For audio: first one if none or a not existing one specified */ + int i_audio = config_GetInt( p_input, "audio-channel" ); + if( i_audio < 0 /*|| i_audio > i_audio_nb*/ ) + { + config_PutInt( p_input, "audio-channel", 1 ); + i_audio = 1; + } + if( i_audio > 0/* && i_audio_nb > 0*/ ) + { + 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_vts_file->vtsi_mat->nr_of_vts_audio_streams ) ) + { + 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] ); + } + } + } + + if( config_GetInt( p_input, "video" ) ) + { + /* for spu, default is none */ + int i_spu = config_GetInt( p_input, "spu-channel" ); + if( i_spu < 0 /*|| i_spu > i_spu_nb*/ ) + { + config_PutInt( p_input, "spu-channel", 0 ); + i_spu = 0; + } + if( i_spu > 0 /*&& i_spu_nb > 0*/ ) + { + i_spu += p_dvd->p_vts_file->vtsi_mat->nr_of_vts_audio_streams; + input_SelectES( p_input, p_input->stream.pp_es[i_spu] ); + } + } +} diff --git a/modules/access/dvdread/input.h b/modules/access/dvdread/input.h new file mode 100644 index 0000000000..3d14a669a6 --- /dev/null +++ b/modules/access/dvdread/input.h @@ -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 + * + * 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; + diff --git a/modules/access/file.c b/modules/access/file.c new file mode 100644 index 0000000000..cdda4d139c --- /dev/null +++ b/modules/access/file.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#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(); + diff --git a/modules/access/http.c b/modules/access/http.c new file mode 100644 index 0000000000..c7badd18cf --- /dev/null +++ b/modules/access/http.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#ifdef WIN32 +# include +# include +# ifndef IN_MULTICAST +# define IN_MULTICAST(a) IN_CLASSD(a) +# endif +#else +# include +#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 : + * //[:][/] */ + 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 ); +} + diff --git a/modules/access/satellite/.cvsignore b/modules/access/satellite/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/satellite/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/satellite/Makefile b/modules/access/satellite/Makefile new file mode 100644 index 0000000000..dd4d0aa894 --- /dev/null +++ b/modules/access/satellite/Makefile @@ -0,0 +1 @@ +satellite_SOURCES = satellite.c access.c dvb.c diff --git a/modules/access/satellite/access.c b/modules/access/satellite/access.c new file mode 100644 index 0000000000..1e828e0952 --- /dev/null +++ b/modules/access/satellite/access.c @@ -0,0 +1,434 @@ +/***************************************************************************** + * access.c: Satellite card input + ***************************************************************************** + * Copyright (C) 1998-2002 VideoLAN + * + * Authors: Johan Bilien + * + * 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 +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#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; +} diff --git a/modules/access/satellite/dvb.c b/modules/access/satellite/dvb.c new file mode 100644 index 0000000000..563b63032b --- /dev/null +++ b/modules/access/satellite/dvb.c @@ -0,0 +1,235 @@ +/***************************************************************************** + * dvb.c : functions to control a DVB card under Linux + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * + * Authors: Damien Lucas + * Johan Bilien + * + * 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 + +#include +#include +#ifdef HAVE_INTTYPES_H +# include /* int16_t .. */ +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* DVB Card Drivers */ +#include +#include +#include + + +#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 + * + * 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 ); diff --git a/modules/access/satellite/satellite.c b/modules/access/satellite/satellite.c new file mode 100644 index 0000000000..87c8496de6 --- /dev/null +++ b/modules/access/satellite/satellite.c @@ -0,0 +1,83 @@ +/***************************************************************************** + * satellite.c : Satellite input module for vlc + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ + +#include + +/***************************************************************************** + * 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(); + diff --git a/modules/access/udp.c b/modules/access/udp.c new file mode 100644 index 0000000000..3df44d2901 --- /dev/null +++ b/modules/access/udp.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#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 ); +} diff --git a/modules/access/vcd/.cvsignore b/modules/access/vcd/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/access/vcd/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/access/vcd/Makefile b/modules/access/vcd/Makefile new file mode 100644 index 0000000000..3a17ed6186 --- /dev/null +++ b/modules/access/vcd/Makefile @@ -0,0 +1 @@ +vcd_SOURCES = vcd.c cdrom.c diff --git a/modules/access/vcd/cdrom.c b/modules/access/vcd/cdrom.c new file mode 100644 index 0000000000..a0ff6ad000 --- /dev/null +++ b/modules/access/vcd/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 + * Jon Lech Johansen + * + * 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 +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#include + +#if defined( SYS_BSDI ) +# include +#elif defined ( SYS_DARWIN ) +# include +# include +# include +# include +# include +#elif defined( HAVE_IOC_TOC_HEADER_IN_SYS_CDIO_H ) +# include +# include +#else +# include +#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 diff --git a/modules/access/vcd/cdrom.h b/modules/access/vcd/cdrom.h new file mode 100644 index 0000000000..945ec55ba2 --- /dev/null +++ b/modules/access/vcd/cdrom.h @@ -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 + * + * 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 * ); + diff --git a/modules/access/vcd/vcd.c b/modules/access/vcd/vcd.c new file mode 100644 index 0000000000..4fa9125139 --- /dev/null +++ b/modules/access/vcd/vcd.c @@ -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 + * + * 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 +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include + +#if defined( WIN32 ) +# include /* read() */ +#else +# include /* 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; +} diff --git a/modules/access/vcd/vcd.h b/modules/access/vcd/vcd.h new file mode 100644 index 0000000000..a15201b03b --- /dev/null +++ b/modules/access/vcd/vcd.h @@ -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 + * + * 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; + diff --git a/modules/audio_output/alsa/.cvsignore b/modules/audio_output/alsa/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/audio_output/alsa/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/audio_output/alsa/Makefile b/modules/audio_output/alsa/Makefile new file mode 100644 index 0000000000..bf4dfff657 --- /dev/null +++ b/modules/audio_output/alsa/Makefile @@ -0,0 +1 @@ +alsa_SOURCES = alsa.c diff --git a/modules/audio_output/alsa/alsa.c b/modules/audio_output/alsa/alsa.c new file mode 100644 index 0000000000..1b23d3d83e --- /dev/null +++ b/modules/audio_output/alsa/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 - Original Author + * Jeffrey Baker - Port to ALSA 1.0 API + * John Paul Lorenti - 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 /* ENOMEM */ +#include /* strerror() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include + +/***************************************************************************** + * 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 ); +} + diff --git a/modules/audio_output/arts/.cvsignore b/modules/audio_output/arts/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/audio_output/arts/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/audio_output/arts/Makefile b/modules/audio_output/arts/Makefile new file mode 100644 index 0000000000..ddd35a10db --- /dev/null +++ b/modules/audio_output/arts/Makefile @@ -0,0 +1 @@ +arts_SOURCES = arts.c diff --git a/modules/audio_output/arts/arts.c b/modules/audio_output/arts/arts.c new file mode 100644 index 0000000000..80e12b4c65 --- /dev/null +++ b/modules/audio_output/arts/arts.c @@ -0,0 +1,150 @@ +/***************************************************************************** + * arts.c : aRts module + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * + * Authors: Emmanuel Blindauer + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* strerror() */ +#include /* write(), close() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include + +/***************************************************************************** + * 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 ); +} + diff --git a/modules/audio_output/dsp/.cvsignore b/modules/audio_output/dsp/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/audio_output/dsp/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/audio_output/dsp/Makefile b/modules/audio_output/dsp/Makefile new file mode 100644 index 0000000000..393faf0a4f --- /dev/null +++ b/modules/audio_output/dsp/Makefile @@ -0,0 +1 @@ +dsp_SOURCES = dsp.c diff --git a/modules/audio_output/dsp/dsp.c b/modules/audio_output/dsp/dsp.c new file mode 100644 index 0000000000..069593d644 --- /dev/null +++ b/modules/audio_output/dsp/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 + * Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* ioctl() */ +#include /* strerror() */ +#include /* write(), close() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +/* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED, + * SNDCTL_DSP_GETOSPACE */ +#ifdef HAVE_SOUNDCARD_H +# include +#elif defined( HAVE_SYS_SOUNDCARD_H ) +# include +#elif defined( HAVE_MACHINE_SOUNDCARD_H ) +# include +#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 ); +} diff --git a/modules/audio_output/esd/.cvsignore b/modules/audio_output/esd/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/audio_output/esd/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/audio_output/esd/Makefile b/modules/audio_output/esd/Makefile new file mode 100644 index 0000000000..b9443245b2 --- /dev/null +++ b/modules/audio_output/esd/Makefile @@ -0,0 +1 @@ +esd_SOURCES = esd.c diff --git a/modules/audio_output/esd/esd.c b/modules/audio_output/esd/esd.c new file mode 100644 index 0000000000..fa8c008055 --- /dev/null +++ b/modules/audio_output/esd/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 + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* strerror() */ +#include /* write(), close() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include + +/***************************************************************************** + * 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 ); +} + diff --git a/modules/audio_output/waveout/.cvsignore b/modules/audio_output/waveout/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/audio_output/waveout/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/audio_output/waveout/Makefile b/modules/audio_output/waveout/Makefile new file mode 100644 index 0000000000..ca29f24828 --- /dev/null +++ b/modules/audio_output/waveout/Makefile @@ -0,0 +1 @@ +waveout_SOURCES = waveout.c diff --git a/modules/audio_output/waveout/waveout.c b/modules/audio_output/waveout/waveout.c new file mode 100644 index 0000000000..5369675a82 --- /dev/null +++ b/modules/audio_output/waveout/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 + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* strerror() */ + +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include + +/***************************************************************************** + * 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; ip_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; ip_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 ); +} diff --git a/modules/codec/a52/.cvsignore b/modules/codec/a52/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/a52/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/a52/Makefile b/modules/codec/a52/Makefile new file mode 100644 index 0000000000..ba23988e50 --- /dev/null +++ b/modules/codec/a52/Makefile @@ -0,0 +1 @@ +a52_SOURCES = a52.c diff --git a/modules/codec/a52/a52.c b/modules/codec/a52/a52.c new file mode 100644 index 0000000000..dbb917bed4 --- /dev/null +++ b/modules/codec/a52/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 + * + * 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 +#include +#include + +#include /* malloc(), free() */ +#include /* strdup() */ +#ifdef HAVE_STDINT_H +# include /* int16_t .. */ +#elif HAVE_INTTYPES_H +# include /* 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; */ + } +} diff --git a/modules/codec/a52/a52.h b/modules/codec/a52/a52.h new file mode 100644 index 0000000000..71bfaca7d7 --- /dev/null +++ b/modules/codec/a52/a52.h @@ -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 + * + * 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; diff --git a/modules/codec/a52old/.cvsignore b/modules/codec/a52old/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/a52old/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/a52old/Makefile b/modules/codec/a52old/Makefile new file mode 100644 index 0000000000..f07f59de0b --- /dev/null +++ b/modules/codec/a52old/Makefile @@ -0,0 +1 @@ +a52old_SOURCES = a52old.c decoder.c parse.c exponent.c bit_allocate.c mantissa.c rematrix.c imdct.c diff --git a/modules/codec/a52old/a52old.c b/modules/codec/a52old/a52old.c new file mode 100644 index 0000000000..5d1c71c836 --- /dev/null +++ b/modules/codec/a52old/a52old.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 + * + * 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 /* malloc(), free() */ +#include /* memset() */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include /* 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; */ + } +} + diff --git a/modules/codec/a52old/adec.h b/modules/codec/a52old/adec.h new file mode 100644 index 0000000000..8789a3de6d --- /dev/null +++ b/modules/codec/a52old/adec.h @@ -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 + * Renaud Dartus + * + * 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 */ +}; + diff --git a/modules/codec/a52old/bit_allocate.c b/modules/codec/a52old/bit_allocate.c new file mode 100644 index 0000000000..200f27e020 --- /dev/null +++ b/modules/codec/a52old/bit_allocate.c @@ -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 + * Aaron Holtzman + * Renaud Dartus + * + * 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 /* memcpy() */ + +#include +#include + +#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; binpsd[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); +} diff --git a/modules/codec/a52old/decoder.c b/modules/codec/a52old/decoder.c new file mode 100644 index 0000000000..2892e5ec15 --- /dev/null +++ b/modules/codec/a52old/decoder.c @@ -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 + * Michel Lespinasse + * Aaron Holtzman + * + * 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 /* memcpy() */ + +#include +#include + +#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; +} + diff --git a/modules/codec/a52old/decoder.h b/modules/codec/a52old/decoder.h new file mode 100644 index 0000000000..a41db75c58 --- /dev/null +++ b/modules/codec/a52old/decoder.h @@ -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 + * Renaud Dartus + * + * 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; + +}; + diff --git a/include/ac3_downmix.h b/modules/codec/a52old/downmix.h similarity index 94% rename from include/ac3_downmix.h rename to modules/codec/a52old/downmix.h index 80737951cd..0da1074155 100644 --- a/include/ac3_downmix.h +++ b/modules/codec/a52old/downmix.h @@ -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 * Renaud Dartus diff --git a/modules/codec/a52old/downmix/.cvsignore b/modules/codec/a52old/downmix/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/a52old/downmix/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/a52old/downmix/Makefile b/modules/codec/a52old/downmix/Makefile new file mode 100644 index 0000000000..accc86d126 --- /dev/null +++ b/modules/codec/a52old/downmix/Makefile @@ -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 diff --git a/modules/codec/a52old/downmix/downmix.c b/modules/codec/a52old/downmix/downmix.c new file mode 100644 index 0000000000..56b5ffadbf --- /dev/null +++ b/modules/codec/a52old/downmix/downmix.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 + * + * 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 +#include + +#include + +#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(); + diff --git a/modules/codec/a52old/downmix/downmix_3dn.c b/modules/codec/a52old/downmix/downmix_3dn.c new file mode 100644 index 0000000000..b86bc923f3 --- /dev/null +++ b/modules/codec/a52old/downmix/downmix_3dn.c @@ -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 + * + * 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 + +#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)); + +} + diff --git a/modules/codec/a52old/downmix/downmix_c.c b/modules/codec/a52old/downmix/downmix_c.c new file mode 100644 index 0000000000..2689687364 --- /dev/null +++ b/modules/codec/a52old/downmix/downmix_c.c @@ -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 + * Aaron Holtzman + * + * 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 /* memcpy() */ + +#include + +#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; + } +} + diff --git a/modules/codec/a52old/downmix/downmix_common.h b/modules/codec/a52old/downmix/downmix_common.h new file mode 100644 index 0000000000..f2e57f9c7d --- /dev/null +++ b/modules/codec/a52old/downmix/downmix_common.h @@ -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 + * Aaron Holtzman + * + * 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 * ); + diff --git a/modules/codec/a52old/downmix/downmix_sse.c b/modules/codec/a52old/downmix/downmix_sse.c new file mode 100644 index 0000000000..c32ab4b6d1 --- /dev/null +++ b/modules/codec/a52old/downmix/downmix_sse.c @@ -0,0 +1,312 @@ +/***************************************************************************** + * downmix_sse.c: accelerated SSE A52 downmix functions + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: downmix_sse.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 + +#include "../downmix.h" + +static const float sqrt2_sse __asm__ ("sqrt2_sse") __attribute__ ((aligned (16))) = 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 $64, %%ebx\n" /* loop counter */ + + "movss (%%ecx), %%xmm5\n" /* unit */ + "shufps $0, %%xmm5, %%xmm5\n" /* unit | unit | unit | unit */ + + "movss 4(%%ecx), %%xmm6\n" /* clev */ + "shufps $0, %%xmm6, %%xmm6\n" /* clev | clev | clev | clev */ + + "movss 8(%%ecx), %%xmm7\n" /* slev */ + "shufps $0, %%xmm7, %%xmm7\n" /* slev | slev | slev | slev */ + + ".align 16\n" +".loop:\n" + "movaps (%%eax), %%xmm0\n" /* left */ + "movaps 2048(%%eax), %%xmm1\n" /* right */ + "movaps 1024(%%eax), %%xmm2\n" /* center */ + "movaps 3072(%%eax), %%xmm3\n" /* leftsur */ + "movaps 4096(%%eax), %%xmm4\n" /* rithgsur */ + "mulps %%xmm5, %%xmm0\n" + "mulps %%xmm5, %%xmm1\n" + "mulps %%xmm6, %%xmm2\n" + "addps %%xmm2, %%xmm0\n" + "addps %%xmm2, %%xmm1\n" + "mulps %%xmm7, %%xmm3\n" + "mulps %%xmm7, %%xmm4\n" + "addps %%xmm3, %%xmm0\n" + "addps %%xmm4, %%xmm1\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm1, 1024(%%eax)\n" + + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz .loop\n" + + "popl %%ebx\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 $64, %%ebx\n" /* loop counter */ + + "movss (%%ecx), %%xmm5\n" /* unit */ + "shufps $0, %%xmm5, %%xmm5\n" /* unit | unit | unit | unit */ + + "movss 8(%%ecx), %%xmm7\n" /* slev */ + "shufps $0, %%xmm7, %%xmm7\n" /* slev | slev | slev | slev */ + + ".align 16\n" +".loop3:\n" + "movaps (%%eax), %%xmm0\n" /* left */ + "movaps 1024(%%eax), %%xmm1\n" /* right */ + "movaps 2048(%%eax), %%xmm3\n" /* leftsur */ + "movaps 3072(%%eax), %%xmm4\n" /* rightsur */ + "mulps %%xmm5, %%xmm0\n" + "mulps %%xmm5, %%xmm1\n" + "mulps %%xmm7, %%xmm3\n" + "mulps %%xmm7, %%xmm4\n" + "addps %%xmm3, %%xmm0\n" + "addps %%xmm4, %%xmm1\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm1, 1024(%%eax)\n" + + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz .loop3\n" + + "popl %%ebx\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 $64, %%ebx\n" /* loop counter */ + + "movss (%%ecx), %%xmm5\n" /* unit */ + "shufps $0, %%xmm5, %%xmm5\n" /* unit | unit | unit | unit */ + + "movss 4(%%ecx), %%xmm6\n" /* clev */ + "shufps $0, %%xmm6, %%xmm6\n" /* clev | clev | clev | clev */ + + "movss 8(%%ecx), %%xmm7\n" /* slev */ + "shufps $0, %%xmm7, %%xmm7\n" /* slev | slev | slev | slev */ + + ".align 16\n" +".loop4:\n" + "movaps (%%eax), %%xmm0\n" /* left */ + "movaps 2048(%%eax), %%xmm1\n" /* right */ + "movaps 1024(%%eax), %%xmm2\n" /* center */ + "movaps 3072(%%eax), %%xmm3\n" /* sur */ + "mulps %%xmm5, %%xmm0\n" + "mulps %%xmm5, %%xmm1\n" + "mulps %%xmm6, %%xmm2\n" + "addps %%xmm2, %%xmm0\n" + "mulps %%xmm7, %%xmm3\n" + "addps %%xmm2, %%xmm1\n" + "subps %%xmm3, %%xmm0\n" + "addps %%xmm3, %%xmm1\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm1, 1024(%%eax)\n" + + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz .loop4\n" + + "popl %%ebx\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 $64, %%ebx\n" /* loop counter */ + + "movss (%%ecx), %%xmm5\n" /* unit */ + "shufps $0, %%xmm5, %%xmm5\n" /* unit | unit | unit | unit */ + + "movss 8(%%ecx), %%xmm7\n" /* slev */ + "shufps $0, %%xmm7, %%xmm7\n" /* slev | slev | slev | slev */ + + ".align 16\n" +".loop5:\n" + "movaps (%%eax), %%xmm0\n" /* left */ + "movaps 1024(%%eax), %%xmm1\n" /* right */ + "movaps 2048(%%eax), %%xmm3\n" /* sur */ + "mulps %%xmm5, %%xmm0\n" + "mulps %%xmm5, %%xmm1\n" + "mulps %%xmm7, %%xmm3\n" + "subps %%xmm3, %%xmm0\n" + "addps %%xmm3, %%xmm1\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm1, 1024(%%eax)\n" + + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz .loop5\n" + + "popl %%ebx\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 $64, %%ebx\n" /* loop counter */ + + "movss (%%ecx), %%xmm5\n" /* unit */ + "shufps $0, %%xmm5, %%xmm5\n" /* unit | unit | unit | unit */ + + "movss 4(%%ecx), %%xmm6\n" /* clev */ + "shufps $0, %%xmm6, %%xmm6\n" /* clev | clev | clev | clev */ + + ".align 16\n" +".loop6:\n" + "movaps (%%eax), %%xmm0\n" /*left */ + "movaps 2048(%%eax), %%xmm1\n" /* right */ + "movaps 1024(%%eax), %%xmm2\n" /* center */ + "mulps %%xmm5, %%xmm0\n" + "mulps %%xmm5, %%xmm1\n" + "mulps %%xmm6, %%xmm2\n" + "addps %%xmm2, %%xmm0\n" + "addps %%xmm2, %%xmm1\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm1, 1024(%%eax)\n" + + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz .loop6\n" + + "popl %%ebx\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_sse, %%edx\n" + "movss (%%edx), %%xmm7\n" + "shufps $0, %%xmm7, %%xmm7\n" /* sqrt2 | sqrt2 | sqrt2 | sqrt2 */ + "movl $64, %%ebx\n" + + ".align 16\n" +".loop2:\n" + "movaps (%%ecx), %%xmm0\n" /* c3 | c2 | c1 | c0 */ + "mulps %%xmm7, %%xmm0\n" + "movhlps %%xmm0, %%xmm2\n" /* c3 | c2 */ + + "cvtps2pi %%xmm0, %%mm0\n" /* c1 c0 --> mm0, int_32 */ + "cvtps2pi %%xmm2, %%mm1\n" /* c3 c2 --> mm1, int_32 */ + + "packssdw %%mm0, %%mm0\n" /* c1 c1 c0 c0 --> mm0, int_16 */ + "packssdw %%mm1, %%mm1\n" /* c3 c3 c2 c2 --> mm1, int_16 */ + + "movq %%mm0, (%%eax)\n" + "movq %%mm1, 8(%%eax)\n" + "addl $16, %%eax\n" + "addl $16, %%ecx\n" + + "decl %%ebx\n" + "jnz .loop2\n" + + "popl %%edx\n" + "popl %%ebx\n" + "emms\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 $64, %%ebx\n" + + ".align 16\n" +".loop1:\n" + "movaps (%%ecx), %%xmm0\n" /* l3 | l2 | l1 | l0 */ + "movaps (%%edx), %%xmm1\n" /* r3 | r2 | r1 | r0 */ + "movhlps %%xmm0, %%xmm2\n" /* l3 | l2 */ + "movhlps %%xmm1, %%xmm3\n" /* r3 | r2 */ + "unpcklps %%xmm1, %%xmm0\n" /* r1 | l1 | r0 | l0 */ + "unpcklps %%xmm3, %%xmm2\n" /* r3 | l3 | r2 | l2 */ + + "cvtps2pi %%xmm0, %%mm0\n" /* r0 l0 --> mm0, int_32 */ + "movhlps %%xmm0, %%xmm0\n" + "cvtps2pi %%xmm0, %%mm1\n" /* r1 l1 --> mm1, int_32 */ + "cvtps2pi %%xmm2, %%mm2\n" /* r2 l2 --> mm2, int_32 */ + "movhlps %%xmm2, %%xmm2\n" + "cvtps2pi %%xmm2, %%mm3\n" /* r3 l3 --> mm3, int_32 */ + + "packssdw %%mm1, %%mm0\n" /* r1 l1 r0 l0 --> mm0, int_16 */ + "packssdw %%mm3, %%mm2\n" /* r3 l3 r2 l2 --> mm2, int_16 */ + + "movq %%mm0, (%%eax)\n" + "movq %%mm2, 8(%%eax)\n" + "addl $16, %%eax\n" + "addl $16, %%ecx\n" + "addl $16, %%edx\n" + + "decl %%ebx\n" + "jnz .loop1\n" + + "popl %%ebx\n" + "emms\n" + : "=a" (s16_samples), "=c" (left), "=d" (right) + : "a" (s16_samples), "c" (left), "d" (right)); + +} + diff --git a/modules/codec/a52old/exponent.c b/modules/codec/a52old/exponent.c new file mode 100644 index 0000000000..1561565cfb --- /dev/null +++ b/modules/codec/a52old/exponent.c @@ -0,0 +1,83 @@ +/***************************************************************************** + * exponent.c: A52 exponent calculations + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: exponent.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * Aaron Holtzman + * + * 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 /* memcpy(), memset() */ + +#include +#include + +#include "imdct.h" +#include "downmix.h" +#include "adec.h" + +#include "internal.h" + +#include "exponent.h" + +int exponent_unpack (a52dec_t * p_a52dec) +{ + u16 i; + + for (i = 0; i < p_a52dec->bsi.nfchans; i++) + { + if (exp_unpack_ch (p_a52dec, UNPACK_FBW, p_a52dec->audblk.chexpstr[i], + p_a52dec->audblk.nchgrps[i], + p_a52dec->audblk.exps[i][0], + &p_a52dec->audblk.exps[i][1], + p_a52dec->audblk.fbw_exp[i])) + { + return 1; + } + } + + if (p_a52dec->audblk.cplinu) + { + if (exp_unpack_ch (p_a52dec, UNPACK_CPL, p_a52dec->audblk.cplexpstr, + p_a52dec->audblk.ncplgrps, + p_a52dec->audblk.cplabsexp << 1, + p_a52dec->audblk.cplexps, + &p_a52dec->audblk.cpl_exp[p_a52dec->audblk.cplstrtmant])) + { + return 1; + } + } + + if (p_a52dec->bsi.lfeon) + { + if (exp_unpack_ch (p_a52dec, UNPACK_LFE, p_a52dec->audblk.lfeexpstr, + 2, p_a52dec->audblk.lfeexps[0], + &p_a52dec->audblk.lfeexps[1], + p_a52dec->audblk.lfe_exp)) + { + return 1; + } + } + + return 0; +} + diff --git a/modules/codec/a52old/exponent.h b/modules/codec/a52old/exponent.h new file mode 100644 index 0000000000..18f1978516 --- /dev/null +++ b/modules/codec/a52old/exponent.h @@ -0,0 +1,152 @@ +/***************************************************************************** + * exponent.h: A52 exponent calculations + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: exponent.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * Aaron Holtzman + * + * 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. + *****************************************************************************/ + +static const s16 exps_1[128] = +{ + -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2, + -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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0 +}; + +static const s16 exps_2[128] = +{ + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + -2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 0, 0, 0 +}; + +static const s16 exps_3[128] = +{ + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2, + 0, 0, 0 +}; + +#define UNPACK_FBW 1 +#define UNPACK_CPL 2 +#define UNPACK_LFE 4 + +static inline int exp_unpack_ch( a52dec_t * p_a52dec, u16 type, + u16 expstr, u16 ngrps, u16 initial_exp, + u16 exps[], u16 * dest ) +{ + u16 i,j; + s16 exp_acc; + + if (expstr == EXP_REUSE) + { + return 0; + } + + /* Handle the initial absolute exponent */ + exp_acc = initial_exp; + j = 0; + + /* In the case of a fbw channel then the initial absolute values is + * also an exponent */ + if (type != UNPACK_CPL) + { + dest[j++] = exp_acc; + } + + /* Loop through the groups and fill the dest array appropriately */ + switch (expstr) + { + case EXP_D15: /* 1 */ + for (i = 0; i < ngrps; i++) + { + if (exps[i] > 124) + { + msg_Err( p_a52dec->p_fifo, "invalid exponent" ); + return 1; + } + exp_acc += (exps_1[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + exp_acc += (exps_2[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + exp_acc += (exps_3[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + } + break; + + case EXP_D25: /* 2 */ + for (i = 0; i < ngrps; i++) + { + if (exps[i] > 124) + { + msg_Err( p_a52dec->p_fifo, "invalid exponent" ); + return 1; + } + exp_acc += (exps_1[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + exp_acc += (exps_2[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + exp_acc += (exps_3[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + } + break; + + case EXP_D45: /* 3 */ + for (i = 0; i < ngrps; i++) + { + if (exps[i] > 124) + { + msg_Err( p_a52dec->p_fifo, "invalid exponent" ); + return 1; + } + exp_acc += (exps_1[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + exp_acc += (exps_2[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + exp_acc += (exps_3[exps[i]] /*- 2*/); + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + dest[j++] = exp_acc; + } + break; + } + + return 0; +} + diff --git a/modules/codec/a52old/imdct.c b/modules/codec/a52old/imdct.c new file mode 100644 index 0000000000..f88e596dc9 --- /dev/null +++ b/modules/codec/a52old/imdct.c @@ -0,0 +1,262 @@ +/***************************************************************************** + * imdct.c: A52 DCT + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: imdct.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Aaron Holtzman + * Renaud Dartus + * + * 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 /* memcpy() */ + +#include +#include + +#include +#include + +#include "imdct.h" +#include "downmix.h" +#include "adec.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void E_( imdct_init )(imdct_t * p_imdct) +{ + int i; + float scale = 181.019; + + p_imdct->pf_imdct_init( p_imdct ); + + /* More twiddle factors to turn IFFT into IMDCT */ + for (i=0; i < 64; i++) { + p_imdct->xcos2[i] = cos(2.0f * M_PI * (8*i+1)/(4*N)) * scale; + p_imdct->xsin2[i] = sin(2.0f * M_PI * (8*i+1)/(4*N)) * scale; + } +} + +void imdct (a52dec_t * p_a52dec, s16 * buffer) +{ + int i; + int doable = 0; + float *center=NULL, *left, *right, *left_sur, *right_sur; + float *delay_left, *delay_right; + float *delay1_left, *delay1_right, *delay1_center, *delay1_sr, *delay1_sl; + float right_tmp, left_tmp; + void (*do_imdct)(imdct_t * p_imdct, float data[], float delay[]); + + /* test if dm in frequency is doable */ + if (!(doable = p_a52dec->audblk.blksw[0])) + { + do_imdct = p_a52dec->p_imdct->pf_imdct_512; + } + else + { + do_imdct = p_a52dec->p_imdct->pf_imdct_256; + } + + /* downmix in the frequency domain if all the channels + * use the same imdct */ + for (i=0; i < p_a52dec->bsi.nfchans; i++) + { + if (doable != p_a52dec->audblk.blksw[i]) + { + do_imdct = NULL; + break; + } + } + + if (do_imdct) + { + /* dowmix first and imdct */ + switch(p_a52dec->bsi.acmod) + { + case 7: /* 3/2 */ + p_a52dec->p_downmix->pf_downmix_3f_2r_to_2ch (p_a52dec->samples, &p_a52dec->dm_par); + break; + case 6: /* 2/2 */ + p_a52dec->p_downmix->pf_downmix_2f_2r_to_2ch (p_a52dec->samples, &p_a52dec->dm_par); + break; + case 5: /* 3/1 */ + p_a52dec->p_downmix->pf_downmix_3f_1r_to_2ch (p_a52dec->samples, &p_a52dec->dm_par); + break; + case 4: /* 2/1 */ + p_a52dec->p_downmix->pf_downmix_2f_1r_to_2ch (p_a52dec->samples, &p_a52dec->dm_par); + break; + case 3: /* 3/0 */ + p_a52dec->p_downmix->pf_downmix_3f_0r_to_2ch (p_a52dec->samples, &p_a52dec->dm_par); + break; + case 2: + break; + default: /* 1/0 */ +// if (p_a52dec->bsi.acmod == 1) + center = p_a52dec->samples; +// else if (p_a52dec->bsi.acmod == 0) +// center = samples[config.dual_mono_ch_sel]; + do_imdct(p_a52dec->p_imdct, center, p_a52dec->p_imdct->delay); /* no downmix*/ + + p_a52dec->p_downmix->pf_stream_sample_1ch_to_s16 (buffer, center); + + return; + break; + } + + do_imdct (p_a52dec->p_imdct, p_a52dec->samples, p_a52dec->p_imdct->delay); + do_imdct (p_a52dec->p_imdct, p_a52dec->samples+256, p_a52dec->p_imdct->delay+256); + p_a52dec->p_downmix->pf_stream_sample_2ch_to_s16(buffer, p_a52dec->samples, p_a52dec->samples+256); + + } else { + /* imdct and then downmix + * delay and samples should be saved and mixed + * fprintf(stderr, "time domain downmix\n"); */ + for (i=0; ibsi.nfchans; i++) + { + if (p_a52dec->audblk.blksw[i]) + { + /* There is only a C function */ + p_a52dec->p_imdct->pf_imdct_256_nol( p_a52dec->p_imdct, + p_a52dec->samples+256*i, p_a52dec->p_imdct->delay1+256*i ); + } + else + { + p_a52dec->p_imdct->pf_imdct_512_nol( p_a52dec->p_imdct, + p_a52dec->samples+256*i, p_a52dec->p_imdct->delay1+256*i ); + } + } + + /* mix the sample, overlap */ + switch(p_a52dec->bsi.acmod) + { + case 7: /* 3/2 */ + left = p_a52dec->samples; + center = p_a52dec->samples+256; + right = p_a52dec->samples+2*256; + left_sur = p_a52dec->samples+3*256; + right_sur = p_a52dec->samples+4*256; + delay_left = p_a52dec->p_imdct->delay; + delay_right = p_a52dec->p_imdct->delay+256; + delay1_left = p_a52dec->p_imdct->delay1; + delay1_center = p_a52dec->p_imdct->delay1+256; + delay1_right = p_a52dec->p_imdct->delay1+2*256; + delay1_sl = p_a52dec->p_imdct->delay1+3*256; + delay1_sr = p_a52dec->p_imdct->delay1+4*256; + + for (i = 0; i < 256; i++) { + left_tmp = p_a52dec->dm_par.unit * *left++ + p_a52dec->dm_par.clev * *center + p_a52dec->dm_par.slev * *left_sur++; + right_tmp= p_a52dec->dm_par.unit * *right++ + p_a52dec->dm_par.clev * *center++ + p_a52dec->dm_par.slev * *right_sur++; + *buffer++ = (s16)(left_tmp + *delay_left); + *buffer++ = (s16)(right_tmp + *delay_right); + *delay_left++ = p_a52dec->dm_par.unit * *delay1_left++ + p_a52dec->dm_par.clev * *delay1_center + p_a52dec->dm_par.slev * *delay1_sl++; + *delay_right++ = p_a52dec->dm_par.unit * *delay1_right++ + p_a52dec->dm_par.clev * *center++ + p_a52dec->dm_par.slev * *delay1_sr++; + } + break; + case 6: /* 2/2 */ + left = p_a52dec->samples; + right = p_a52dec->samples+256; + left_sur = p_a52dec->samples+2*256; + right_sur = p_a52dec->samples+3*256; + delay_left = p_a52dec->p_imdct->delay; + delay_right = p_a52dec->p_imdct->delay+256; + delay1_left = p_a52dec->p_imdct->delay1; + delay1_right = p_a52dec->p_imdct->delay1+256; + delay1_sl = p_a52dec->p_imdct->delay1+2*256; + delay1_sr = p_a52dec->p_imdct->delay1+3*256; + + for (i = 0; i < 256; i++) { + left_tmp = p_a52dec->dm_par.unit * *left++ + p_a52dec->dm_par.slev * *left_sur++; + right_tmp= p_a52dec->dm_par.unit * *right++ + p_a52dec->dm_par.slev * *right_sur++; + *buffer++ = (s16)(left_tmp + *delay_left); + *buffer++ = (s16)(right_tmp + *delay_right); + *delay_left++ = p_a52dec->dm_par.unit * *delay1_left++ + p_a52dec->dm_par.slev * *delay1_sl++; + *delay_right++ = p_a52dec->dm_par.unit * *delay1_right++ + p_a52dec->dm_par.slev * *delay1_sr++; + } + break; + case 5: /* 3/1 */ + left = p_a52dec->samples; + center = p_a52dec->samples+256; + right = p_a52dec->samples+2*256; + right_sur = p_a52dec->samples+3*256; + delay_left = p_a52dec->p_imdct->delay; + delay_right = p_a52dec->p_imdct->delay+256; + delay1_left = p_a52dec->p_imdct->delay1; + delay1_center = p_a52dec->p_imdct->delay1+256; + delay1_right = p_a52dec->p_imdct->delay1+2*256; + delay1_sl = p_a52dec->p_imdct->delay1+3*256; + + for (i = 0; i < 256; i++) { + left_tmp = p_a52dec->dm_par.unit * *left++ + p_a52dec->dm_par.clev * *center - p_a52dec->dm_par.slev * *right_sur; + right_tmp= p_a52dec->dm_par.unit * *right++ + p_a52dec->dm_par.clev * *center++ + p_a52dec->dm_par.slev * *right_sur++; + *buffer++ = (s16)(left_tmp + *delay_left); + *buffer++ = (s16)(right_tmp + *delay_right); + *delay_left++ = p_a52dec->dm_par.unit * *delay1_left++ + p_a52dec->dm_par.clev * *delay1_center + p_a52dec->dm_par.slev * *delay1_sl; + *delay_right++ = p_a52dec->dm_par.unit * *delay1_right++ + p_a52dec->dm_par.clev * *center++ + p_a52dec->dm_par.slev * *delay1_sl++; + } + break; + case 4: /* 2/1 */ + left = p_a52dec->samples; + right = p_a52dec->samples+256; + right_sur = p_a52dec->samples+2*256; + delay_left = p_a52dec->p_imdct->delay; + delay_right = p_a52dec->p_imdct->delay+256; + delay1_left = p_a52dec->p_imdct->delay1; + delay1_right = p_a52dec->p_imdct->delay1+256; + delay1_sl = p_a52dec->p_imdct->delay1+2*256; + + for (i = 0; i < 256; i++) { + left_tmp = p_a52dec->dm_par.unit * *left++ - p_a52dec->dm_par.slev * *right_sur; + right_tmp= p_a52dec->dm_par.unit * *right++ + p_a52dec->dm_par.slev * *right_sur++; + *buffer++ = (s16)(left_tmp + *delay_left); + *buffer++ = (s16)(right_tmp + *delay_right); + *delay_left++ = p_a52dec->dm_par.unit * *delay1_left++ + p_a52dec->dm_par.slev * *delay1_sl; + *delay_right++ = p_a52dec->dm_par.unit * *delay1_right++ + p_a52dec->dm_par.slev * *delay1_sl++; + } + break; + case 3: /* 3/0 */ + left = p_a52dec->samples; + center = p_a52dec->samples+256; + right = p_a52dec->samples+2*256; + delay_left = p_a52dec->p_imdct->delay; + delay_right = p_a52dec->p_imdct->delay+256; + delay1_left = p_a52dec->p_imdct->delay1; + delay1_center = p_a52dec->p_imdct->delay1+256; + delay1_right = p_a52dec->p_imdct->delay1+2*256; + + for (i = 0; i < 256; i++) { + left_tmp = p_a52dec->dm_par.unit * *left++ + p_a52dec->dm_par.clev * *center; + right_tmp= p_a52dec->dm_par.unit * *right++ + p_a52dec->dm_par.clev * *center++; + *buffer++ = (s16)(left_tmp + *delay_left); + *buffer++ = (s16)(right_tmp + *delay_right); + *delay_left++ = p_a52dec->dm_par.unit * *delay1_left++ + p_a52dec->dm_par.clev * *delay1_center; + *delay_right++ = p_a52dec->dm_par.unit * *delay1_right++ + p_a52dec->dm_par.clev * *center++; + } + break; + case 2: /* copy to output */ + for (i = 0; i < 256; i++) { + *buffer++ = (s16) *(p_a52dec->samples+i); + *buffer++ = (s16) *(p_a52dec->samples+256+i); + } + break; + } + } +} diff --git a/include/ac3_imdct.h b/modules/codec/a52old/imdct.h similarity index 97% rename from include/ac3_imdct.h rename to modules/codec/a52old/imdct.h index e6e101c859..37d27ebf13 100644 --- a/include/ac3_imdct.h +++ b/modules/codec/a52old/imdct.h @@ -1,8 +1,8 @@ /***************************************************************************** - * ac3_imdct.h : AC3 IMDCT types + * imdct.h : A52 IMDCT types ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: ac3_imdct.h,v 1.10 2002/07/31 20:56:50 sam Exp $ + * $Id: imdct.h,v 1.1 2002/08/04 17:23:42 sam Exp $ * * Authors: Michel Kaempf * Renaud Dartus diff --git a/modules/codec/a52old/imdct/.cvsignore b/modules/codec/a52old/imdct/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/a52old/imdct/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/a52old/imdct/Makefile b/modules/codec/a52old/imdct/Makefile new file mode 100644 index 0000000000..6e31fa1a10 --- /dev/null +++ b/modules/codec/a52old/imdct/Makefile @@ -0,0 +1,5 @@ +COMMON_SOURCES = imdct_common.c + +imdct_SOURCES = imdct.c imdct_c.c srfft_c.c $(COMMON_SOURCES) +imdctsse_SOURCES = imdct.c imdct_sse.c srfft_sse.c $(COMMON_SOURCES) +imdct3dn_SOURCES = imdct.c imdct_3dn.c srfft_3dn.c $(COMMON_SOURCES) diff --git a/modules/codec/a52old/imdct/imdct.c b/modules/codec/a52old/imdct/imdct.c new file mode 100644 index 0000000000..ea1653fe66 --- /dev/null +++ b/modules/codec/a52old/imdct/imdct.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * imdct.c : IMDCT module + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: imdct.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Gaël Hendryckx + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "imdct_common.h" + +/***************************************************************************** + * Module initializer + *****************************************************************************/ +static int Open ( vlc_object_t *p_this ) +{ + imdct_t *p_imdct = (imdct_t *)p_this; + + p_imdct->pf_imdct_init = E_( imdct_init ); + p_imdct->pf_imdct_256 = E_( imdct_do_256 ); + p_imdct->pf_imdct_256_nol = E_( imdct_do_256_nol ); + p_imdct->pf_imdct_512 = E_( imdct_do_512 ); + p_imdct->pf_imdct_512_nol = E_( imdct_do_512_nol ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#if defined( MODULE_NAME_IS_imdct ) + set_description( _("A52 IMDCT module") ); + set_capability( "imdct", 50 ); + add_shortcut( "c" ); +#elif defined( MODULE_NAME_IS_imdctsse ) + set_description( _("SSE A52 IMDCT module") ); + set_capability( "imdct", 200 ); + add_shortcut( "sse" ); +#elif defined( MODULE_NAME_IS_imdct3dn ) + set_description( _("3D Now! A52 IMDCT module") ); + set_capability( "imdct", 200 ); + add_shortcut( "3dn" ); + add_shortcut( "3dnow" ); +#endif + set_callbacks( Open, NULL ); +vlc_module_end(); + diff --git a/modules/codec/a52old/imdct/imdct_3dn.c b/modules/codec/a52old/imdct/imdct_3dn.c new file mode 100644 index 0000000000..cb2e0dd21b --- /dev/null +++ b/modules/codec/a52old/imdct/imdct_3dn.c @@ -0,0 +1,538 @@ +/***************************************************************************** + * imdct_3dn.c: accelerated 3D Now! A52 DCT + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: imdct_3dn.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "imdct_common.h" +#include "retables.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void E_( fft_64p ) ( complex_t *x ); +void E_( fft_128p ) ( complex_t *a ); + +static void imdct512_pre_ifft_twiddle_3dn (const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse); +static void imdct512_post_ifft_twiddle_3dn (complex_t *buf, float *xcos_sin_sse); +static void imdct512_window_delay_3dn (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); +static void imdct512_window_delay_nol_3dn (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt); + + +void E_( imdct_init ) (imdct_t * p_imdct) +{ + int i; + float scale = 181.019; + + for (i=0; i < 128; i++) + { + float xcos_i = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + float xsin_i = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + p_imdct->xcos_sin_sse[i * 4] = xcos_i; + p_imdct->xcos_sin_sse[i * 4 + 1] = -xsin_i; + p_imdct->xcos_sin_sse[i * 4 + 2] = -xsin_i; + p_imdct->xcos_sin_sse[i * 4 + 3] = -xcos_i; + } +} + +void E_( imdct_do_512 ) (imdct_t * p_imdct, float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_3dn (pm128, p_imdct->buf, data, p_imdct->xcos_sin_sse); + E_( fft_128p ) (p_imdct->buf); + imdct512_post_ifft_twiddle_3dn (p_imdct->buf, p_imdct->xcos_sin_sse); + imdct512_window_delay_3dn (p_imdct->buf, data, window, delay); +} + +void E_( imdct_do_512_nol ) (imdct_t * p_imdct, float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_3dn (pm128, p_imdct->buf, data, p_imdct->xcos_sin_sse); + E_( fft_128p ) (p_imdct->buf); + imdct512_post_ifft_twiddle_3dn (p_imdct->buf, p_imdct->xcos_sin_sse); + imdct512_window_delay_nol_3dn (p_imdct->buf, data, window, delay); +} + +static void imdct512_pre_ifft_twiddle_3dn (const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse) +{ + __asm__ __volatile__ ( + ".align 16\n" + "pushl %%ebx\n" + "pushl %%esi\n" + + "movl $128, %%ebx\n" /* loop counter */ + + ".align 16\n" +"0:\n" + "movl (%%eax), %%esi\n" + "movd (%%ecx, %%esi, 8), %%mm1\n" /* 2j */ + "punpckldq %%mm1, %%mm1\n" /* 2j | 2j */ + + "shll $1, %%esi\n" + + "movq (%%edx, %%esi, 8), %%mm0\n" /* -s_j | c_j */ + "movq 8(%%edx, %%esi, 8), %%mm2\n" /* -c_j | -s_j */ + + "negl %%esi\n" + + "movd 1020(%%ecx, %%esi, 4), %%mm4\n" /* 255-2j */ + "punpckldq %%mm4, %%mm4\n" /* 255-2j | 255-2j */ + "addl $4, %%eax\n" + + "pfmul %%mm4, %%mm0\n" /* 255-2j * -s_j | 255-2j * c_j */ + "pfmul %%mm1, %%mm2\n" /* 2j * -c_j | 2j * -s_j */ + "addl $8, %%edi\n" + "pfadd %%mm2, %%mm0\n" /* 2j * -c_j + 255-2j * -s_j | 2j * -s_j + 255-2j * c_j */ + + "movq %%mm0, -8(%%edi)\n" + "decl %%ebx\n" + "jnz 0b\n" + + "popl %%esi\n" + "popl %%ebx\n" + + "femms\n" + : "=D" (buf) + : "a" (pmt), "c" (data), "d" (xcos_sin_sse), "D" (buf)); +} + +static void imdct512_post_ifft_twiddle_3dn (complex_t *buf, float *xcos_sin_sse) +{ + __asm__ __volatile__ ( + ".align 16\n" + "pushl %%ebx\n" + "movl $64, %%ebx\n" /* loop counter */ + + ".align 16\n" +"0:\n" + "movq (%%eax), %%mm0\n" /* im0 | re0 */ + "movq %%mm0, %%mm1\n" /* im0 | re0 */ + "punpckldq %%mm0, %%mm0\n" /* re0 | re0 */ + "punpckhdq %%mm1, %%mm1\n" /* im0 | im0 */ + + "movq (%%ecx), %%mm2\n" /* -s | c */ + "movq 8(%%ecx), %%mm3\n" /* -c | -s */ + "movq %%mm3, %%mm4\n" + + "punpckhdq %%mm2,%%mm3\n" /* -s | -c */ + "punpckldq %%mm2,%%mm4\n" /* c | -s */ + + "movq 8(%%eax), %%mm2\n" /* im1 | re1 */ + "movq %%mm2, %%mm5\n" /* im1 | re1 */ + "punpckldq %%mm2, %%mm2\n" /* re1 | re1 */ + "punpckhdq %%mm5, %%mm5\n" /* im1 | im1 */ + + "pfmul %%mm3, %%mm0\n" /* -s * re0 | -c * re0 */ + "pfmul %%mm4, %%mm1\n" /* c * im0 | -s * im0 */ + + "movq 16(%%ecx), %%mm6\n" /* -s1 | c1 */ + "movq 24(%%ecx), %%mm7\n" /* -c1 | -s1 */ + "movq %%mm7, %%mm4\n" + + "punpckhdq %%mm6,%%mm7\n" /* -s1 | -c1 */ + "punpckldq %%mm6,%%mm4\n" /* c1 | -s1 */ + + "pfmul %%mm7, %%mm2\n" /* -s1*re1 | -c1*re1 */ + "pfmul %%mm4, %%mm5\n" /* c1*im1 | -s1*im1 */ + + "pfadd %%mm1, %%mm0\n" /* -s * re0 + c * im0 | -c * re0 - s * im0 */ + "pfadd %%mm5, %%mm2\n" /* -s1 * re1 + c1 * im1 | -c1 * re1 - s1 * im1 */ + + "movq %%mm0, (%%eax)\n" + "movq %%mm2, 8(%%eax)\n" + "addl $32, %%ecx\n" + "addl $16, %%eax\n" + "decl %%ebx\n" + "jnz 0b\n" + + "popl %%ebx\n" + "femms\n" + : "=a" (buf) + : "a" (buf), "c" (xcos_sin_sse) ); +} + +static void imdct512_window_delay_3dn (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt) +{ + __asm__ __volatile__ ( + ".align 16\n" + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%edi\n" + "pushl %%esi\n" + "pushl %%ebp\n" + + "movl %%esi, %%ebp\n" /* buf */ + "movl $32, %%ebx\n" /* loop count */ + "leal 516(%%ebp), %%esi\n" /* buf[64].im */ + "leal 504(%%ebp), %%edi\n" /* buf[63].re */ + + + ".align 16\n" +".first_128_samples:\n" + "movd (%%esi), %%mm0\n" /* im0 */ + "movd 8(%%esi), %%mm2\n" /* im1 */ + "movd (%%edi), %%mm1\n" /* re0 */ + "movd -8(%%edi), %%mm3\n" /* re1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -im0 */ + "pfsub %%mm2, %%mm5\n" /* -im1 */ + + "punpckldq %%mm1, %%mm4\n" /* re0 | -im0 */ + "punpckldq %%mm3, %%mm5\n" /* re1 | -im1 */ + + "movq (%%edx), %%mm0\n" /* w1 | w0 */ + "movq 8(%%edx), %%mm1\n" /* w3 | w2 */ + "movq (%%ecx), %%mm2\n" /* d1 | d0 */ + "movq 8(%%ecx), %%mm3\n" /* d3 | d2 */ + + "pfmul %%mm4, %%mm0\n" /* w1*re0 | -w0*im0 */ + "pfmul %%mm5, %%mm1\n" /* w3*re1 | -w2*im1 */ + + "pfadd %%mm2, %%mm0\n" /* w1*re0+d1 | -w0*im0+d0 */ + "pfadd %%mm3, %%mm1\n" /* w3*re1+d3 | -w2*im1+d2 */ + + "addl $16, %%edx\n" + "movq %%mm0, (%%eax)\n" + "movq %%mm1, 8(%%eax)\n" + "addl $16, %%ecx\n" + "addl $16, %%esi\n" + "addl $16, %%eax\n" + "addl $-16, %%edi\n" + "decl %%ebx\n" + "jnz .first_128_samples\n" + + "movl %%ebp, %%esi\n" /* buf[0].re */ + "movl $32, %%ebx\n" /* loop count */ + "leal 1020(%%ebp), %%edi\n" /* buf[127].im */ + + ".align 16\n" +".second_128_samples:\n" + "movd (%%esi), %%mm0\n" /* buf[i].re */ + "movd 8(%%esi), %%mm2\n" /* re1 */ + "movd (%%edi), %%mm1\n" /* buf[127-i].im */ + "movd -8(%%edi), %%mm3\n" /* im1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -re0 */ + "pfsub %%mm2, %%mm5\n" /* -re1 */ + + "punpckldq %%mm1, %%mm4\n" /* im0 | -re0 */ + "punpckldq %%mm3, %%mm5\n" /* im1 | -re1 */ + + "movq (%%edx), %%mm0\n" /* w1 | w0 */ + "movq 8(%%edx), %%mm1\n" /* w3 | w2 */ + "movq (%%ecx), %%mm2\n" /* d1 | d0 */ + "movq 8(%%ecx), %%mm3\n" /* d3 | d2 */ + + "addl $16, %%esi\n" + + "pfmul %%mm4, %%mm0\n" /* w1*im0 | -w0*re0 */ + "pfmul %%mm5, %%mm1\n" /* w3*im1 | -w2*re1 */ + + "pfadd %%mm2, %%mm0\n" /* w1*im0+d1 | -w0*re0+d0 */ + "pfadd %%mm3, %%mm1\n" /* w3*im1+d3 | -w2*re1+d2 */ + + "addl $-16, %%edi\n" + + "movq %%mm0, (%%eax)\n" + "movq %%mm1, 8(%%eax)\n" + + "addl $16, %%edx\n" + "addl $16, %%eax\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .second_128_samples\n" + + "leal 512(%%ebp), %%esi\n" /* buf[64].re */ + "leal 508(%%ebp), %%edi\n" /* buf[63].im */ + "movl $32, %%ebx\n" /* loop count */ + "addl $-1024, %%ecx\n" /* delay */ + + ".align 16\n" +".first_128_delay:\n" + "movd (%%esi), %%mm0\n" /* re0 */ + "movd 8(%%esi), %%mm2\n" /* re1 */ + "movd (%%edi), %%mm1\n" /* im0 */ + "movd -8(%%edi), %%mm3\n" /* im1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -re0 */ + "pfsub %%mm2, %%mm5\n" /* -re1 */ + + "punpckldq %%mm1, %%mm4\n" /* im0 | -re0 */ + "punpckldq %%mm3, %%mm5\n" /* im1 | -re1 */ + + + "movq -16(%%edx), %%mm1\n" /* w3 | w2 */ + "movq -8(%%edx), %%mm0\n" /* w1 | w0 */ + + "addl $-16, %%edx\n" + + "pfmul %%mm4, %%mm0\n" /* w1*im0 | -w0*re0 */ + "pfmul %%mm5, %%mm1\n" /* w3*im1 | -w2*re1 */ + + "movq %%mm0, (%%ecx)\n" + "movq %%mm1, 8(%%ecx)\n" + "addl $16, %%esi\n" + "addl $-16, %%edi\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .first_128_delay\n" + + "leal 4(%%ebp), %%esi\n" /* buf[0].im */ + "leal 1016(%%ebp), %%edi\n" /* buf[127].re */ + "movl $32, %%ebx\n" /* loop count */ + + ".align 16\n" +".second_128_delay:\n" + "movd (%%esi), %%mm0\n" /* im0 */ + "movd 8(%%esi), %%mm2\n" /* im1 */ + "movd (%%edi), %%mm1\n" /* re0 */ + "movd -8(%%edi), %%mm3\n" /* re1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm1, %%mm4\n" /* -re0 */ + "pfsub %%mm3, %%mm5\n" /* -re1 */ + + "punpckldq %%mm4, %%mm0\n" /* -re0 | im0 */ + "punpckldq %%mm5, %%mm2\n" /* -re1 | im1 */ + + + "movq -16(%%edx), %%mm1\n" /* w3 | w2 */ + "movq -8(%%edx), %%mm3\n" /* w1 | w0 */ + + "addl $-16, %%edx\n" + + "pfmul %%mm0, %%mm1\n" /* -w1*re0 | w0*im0 */ + "pfmul %%mm2, %%mm3\n" /* -w3*re1 | w2*im1 */ + + + "movq %%mm1, (%%ecx)\n" + "movq %%mm3, 8(%%ecx)\n" + "addl $16, %%esi\n" + "addl $-16, %%edi\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .second_128_delay\n" + + "popl %%ebp\n" + "popl %%esi\n" + "popl %%edi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + + "femms\n" + : "=S" (buf), "=a" (data_ptr), "=c" (delay_prt), "=d" (window_prt) + : "S" (buf), "a" (data_ptr), "c" (delay_prt), "d" (window_prt)); +} + +static void imdct512_window_delay_nol_3dn (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt) +{ + __asm__ __volatile__ ( + ".align 16\n" + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%edi\n" + "pushl %%esi\n" + "pushl %%ebp\n" + + "movl %%esi, %%ebp\n" /* buf */ + "movl $32, %%ebx\n" /* loop count */ + "leal 516(%%ebp), %%esi\n" /* buf[64].im */ + "leal 504(%%ebp), %%edi\n" /* buf[63].re */ + + ".align 16\n" +".first_128_samples2:\n" + "movd (%%esi), %%mm0\n" /* im0 */ + "movd 8(%%esi), %%mm2\n" /* im1 */ + "movd (%%edi), %%mm1\n" /* re0 */ + "movd -8(%%edi), %%mm3\n" /* re1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -im0 */ + "pfsub %%mm2, %%mm5\n" /* -im1 */ + + "punpckldq %%mm1, %%mm4\n" /* re0 | -im0 */ + "punpckldq %%mm3, %%mm5\n" /* re1 | -im1 */ + + "movq (%%edx), %%mm0\n" /* w1 | w0 */ + "movq 8(%%edx), %%mm1\n" /* w3 | w2 */ + + "pfmul %%mm4, %%mm0\n" /* w1*re0 | -w0*im0 */ + "pfmul %%mm5, %%mm1\n" /* w3*re1 | -w2*im1 */ + + "addl $16, %%edx\n" + "movq %%mm0, (%%eax)\n" + "movq %%mm1, 8(%%eax)\n" + "addl $16, %%ecx\n" + "addl $16, %%esi\n" + "addl $16, %%eax\n" + "addl $-16, %%edi\n" + "decl %%ebx\n" + "jnz .first_128_samples2\n" + + "movl %%ebp, %%esi\n" /* buf[0].re */ + "movl $32, %%ebx\n" /* loop count */ + "leal 1020(%%ebp), %%edi\n" /* buf[127].im */ + + ".align 16\n" +".second_128_samples2:\n" + "movd (%%esi), %%mm0\n" /* buf[i].re */ + "movd 8(%%esi), %%mm2\n" /* re1 */ + "movd (%%edi), %%mm1\n" /* buf[127-i].im */ + "movd -8(%%edi), %%mm3\n" /* im1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -re0 */ + "pfsub %%mm2, %%mm5\n" /* -re1 */ + + "punpckldq %%mm1, %%mm4\n" /* im0 | -re0 */ + "punpckldq %%mm3, %%mm5\n" /* im1 | -re1 */ + + "movq (%%edx), %%mm0\n" /* w1 | w0 */ + "movq 8(%%edx), %%mm1\n" /* w3 | w2 */ + + "addl $16, %%esi\n" + + "pfmul %%mm4, %%mm0\n" /* w1*im0 | -w0*re0 */ + "pfmul %%mm5, %%mm1\n" /* w3*im1 | -w2*re1 */ + + "addl $-16, %%edi\n" + + "movq %%mm0, (%%eax)\n" + "movq %%mm1, 8(%%eax)\n" + + "addl $16, %%edx\n" + "addl $16, %%eax\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .second_128_samples2\n" + + "leal 512(%%ebp), %%esi\n" /* buf[64].re */ + "leal 508(%%ebp), %%edi\n" /* buf[63].im */ + "movl $32, %%ebx\n" /* loop count */ + "addl $-1024, %%ecx\n" /* delay */ + + ".align 16\n" +".first_128_delays:\n" + "movd (%%esi), %%mm0\n" /* re0 */ + "movd 8(%%esi), %%mm2\n" /* re1 */ + "movd (%%edi), %%mm1\n" /* im0 */ + "movd -8(%%edi), %%mm3\n" /* im1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm0, %%mm4\n" /* -re0 */ + "pfsub %%mm2, %%mm5\n" /* -re1 */ + + "punpckldq %%mm1, %%mm4\n" /* im0 | -re0 */ + "punpckldq %%mm3, %%mm5\n" /* im1 | -re1 */ + + + "movq -16(%%edx), %%mm1\n" /* w3 | w2 */ + "movq -8(%%edx), %%mm0\n" /* w1 | w0 */ + + "addl $-16, %%edx\n" + + "pfmul %%mm4, %%mm0\n" /* w1*im0 | -w0*re0 */ + "pfmul %%mm5, %%mm1\n" /* w3*im1 | -w2*re1 */ + + + "movq %%mm0, (%%ecx)\n" + "movq %%mm1, 8(%%ecx)\n" + "addl $16, %%esi\n" + "addl $-16, %%edi\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .first_128_delays\n" + + "leal 4(%%ebp), %%esi\n" /* buf[0].im */ + "leal 1016(%%ebp), %%edi\n" /* buf[127].re */ + "movl $32, %%ebx\n" /* loop count */ + + ".align 16\n" +".second_128_delays:\n" + "movd (%%esi), %%mm0\n" /* im0 */ + "movd 8(%%esi), %%mm2\n" /* im1 */ + "movd (%%edi), %%mm1\n" /* re0 */ + "movd -8(%%edi), %%mm3\n" /* re1 */ + + "pxor %%mm4, %%mm4\n" + "pxor %%mm5, %%mm5\n" + "pfsub %%mm1, %%mm4\n" /* -re0 */ + "pfsub %%mm3, %%mm5\n" /* -re1 */ + + "punpckldq %%mm4, %%mm0\n" /* -re0 | im0 */ + "punpckldq %%mm5, %%mm2\n" /* -re1 | im1 */ + + + "movq -16(%%edx), %%mm1\n" /* w3 | w2 */ + "movq -8(%%edx), %%mm3\n" /* w1 | w0 */ + + "addl $-16, %%edx\n" + + "pfmul %%mm0, %%mm1\n" /* -w1*re0 | w0*im0 */ + "pfmul %%mm2, %%mm3\n" /* -w3*re1 | w2*im1 */ + + + "movq %%mm1, (%%ecx)\n" + "movq %%mm3, 8(%%ecx)\n" + "addl $16, %%esi\n" + "addl $-16, %%edi\n" + "addl $16, %%ecx\n" + "decl %%ebx\n" + "jnz .second_128_delays\n" + + "popl %%ebp\n" + "popl %%esi\n" + "popl %%edi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + + "femms\n" + : "=S" (buf), "=a" (data_ptr), "=c" (delay_prt), "=d" (window_prt) + : "S" (buf), "a" (data_ptr), "c" (delay_prt), "d" (window_prt)); +} + diff --git a/modules/codec/a52old/imdct/imdct_c.c b/modules/codec/a52old/imdct/imdct_c.c new file mode 100644 index 0000000000..a25e288da2 --- /dev/null +++ b/modules/codec/a52old/imdct/imdct_c.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * imdct_c.c: A52 DCT in C + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: imdct_c.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 /* memcpy() */ + +#include +#include + +#include + +#include "../imdct.h" +#include "imdct_common.h" +#include "retables.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void E_( fft_64p ) ( complex_t *x ); +void E_( fft_128p ) ( complex_t *x ); + +void E_( imdct_init ) (imdct_t * p_imdct) +{ + int i; + float scale = 181.019; + + /* Twiddle factors to turn IFFT into IMDCT */ + for (i=0; i < 128; i++) { + p_imdct->xcos1[i] = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + p_imdct->xsin1[i] = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + } +} + +void E_( imdct_do_512 ) (imdct_t * p_imdct, float data[], float delay[]) +{ + int i, j; + float tmp_a_r, tmp_a_i; + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + /* 512 IMDCT with source and dest data in 'data' + * Pre IFFT complex multiply plus IFFT complex conjugate */ + + for( i=0; i < 128; i++) { + j = pm128[i]; + /* a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); + * c = data[2*j] * xcos1[j]; + * b = data[256-2*j-1] * xsin1[j]; + * buf1[i].real = a - b + c; + * buf1[i].imag = b + c; */ + p_imdct->buf[i].real = (data[256-2*j-1] * p_imdct->xcos1[j]) - (data[2*j] * p_imdct->xsin1[j]); + p_imdct->buf[i].imag = -1.0 * (data[2*j] * p_imdct->xcos1[j] + data[256-2*j-1] * p_imdct->xsin1[j]); + } + + E_( fft_128p ) ( &p_imdct->buf[0] ); + + /* Post IFFT complex multiply plus IFFT complex conjugate */ + for (i=0; i < 128; i++) { + tmp_a_r = p_imdct->buf[i].real; + tmp_a_i = p_imdct->buf[i].imag; + /* a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); + * b = tmp_a_r * xsin1[j]; + * c = tmp_a_i * xcos1[j]; + * buf[j].real = a - b + c; + * buf[j].imag = b + c; */ + p_imdct->buf[i].real =(tmp_a_r * p_imdct->xcos1[i]) + (tmp_a_i * p_imdct->xsin1[i]); + p_imdct->buf[i].imag =(tmp_a_r * p_imdct->xsin1[i]) - (tmp_a_i * p_imdct->xcos1[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal */ + for (i=0; i< 64; i++) { + *data_ptr++ = -p_imdct->buf[64+i].imag * *window_ptr++ + *delay_ptr++; + *data_ptr++ = p_imdct->buf[64-i-1].real * *window_ptr++ + *delay_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -p_imdct->buf[i].real * *window_ptr++ + *delay_ptr++; + *data_ptr++ = p_imdct->buf[128-i-1].imag * *window_ptr++ + *delay_ptr++; + } + + /* The trailing edge of the window goes into the delay line */ + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -p_imdct->buf[64+i].real * *--window_ptr; + *delay_ptr++ = p_imdct->buf[64-i-1].imag * *--window_ptr; + } + + for(i=0; i<64; i++) { + *delay_ptr++ = p_imdct->buf[i].imag * *--window_ptr; + *delay_ptr++ = -p_imdct->buf[128-i-1].real * *--window_ptr; + } +} + + +void E_( imdct_do_512_nol ) (imdct_t * p_imdct, float data[], float delay[]) +{ + int i, j; + + float tmp_a_i; + float tmp_a_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + /* 512 IMDCT with source and dest data in 'data' + * Pre IFFT complex multiply plus IFFT cmplx conjugate */ + + for( i=0; i < 128; i++) { + /* z[i] = (X[256-2*i-1] + j * X[2*i]) * (xcos1[i] + j * xsin1[i]) */ + j = pm128[i]; + /* a = (data[256-2*j-1] - data[2*j]) * (xcos1[j] + xsin1[j]); + * c = data[2*j] * xcos1[j]; + * b = data[256-2*j-1] * xsin1[j]; + * buf1[i].real = a - b + c; + * buf1[i].imag = b + c; */ + p_imdct->buf[i].real = (data[256-2*j-1] * p_imdct->xcos1[j]) - (data[2*j] * p_imdct->xsin1[j]); + p_imdct->buf[i].imag = -1.0 * (data[2*j] * p_imdct->xcos1[j] + data[256-2*j-1] * p_imdct->xsin1[j]); + } + + E_( fft_128p ) ( &p_imdct->buf[0] ); + + /* Post IFFT complex multiply plus IFFT complex conjugate*/ + for (i=0; i < 128; i++) { + /* y[n] = z[n] * (xcos1[n] + j * xsin1[n]) ; + * int j1 = i; */ + tmp_a_r = p_imdct->buf[i].real; + tmp_a_i = p_imdct->buf[i].imag; + /* a = (tmp_a_r - tmp_a_i) * (xcos1[j] + xsin1[j]); + * b = tmp_a_r * xsin1[j]; + * c = tmp_a_i * xcos1[j]; + * buf[j].real = a - b + c; + * buf[j].imag = b + c; */ + p_imdct->buf[i].real =(tmp_a_r * p_imdct->xcos1[i]) + (tmp_a_i * p_imdct->xsin1[i]); + p_imdct->buf[i].imag =(tmp_a_r * p_imdct->xsin1[i]) - (tmp_a_i * p_imdct->xcos1[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal, no overlap here*/ + for (i=0; i< 64; i++) { + *data_ptr++ = -p_imdct->buf[64+i].imag * *window_ptr++; + *data_ptr++ = p_imdct->buf[64-i-1].real * *window_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -p_imdct->buf[i].real * *window_ptr++; + *data_ptr++ = p_imdct->buf[128-i-1].imag * *window_ptr++; + } + + /* The trailing edge of the window goes into the delay line */ + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -p_imdct->buf[64+i].real * *--window_ptr; + *delay_ptr++ = p_imdct->buf[64-i-1].imag * *--window_ptr; + } + + for(i=0; i<64; i++) { + *delay_ptr++ = p_imdct->buf[i].imag * *--window_ptr; + *delay_ptr++ = -p_imdct->buf[128-i-1].real * *--window_ptr; + } +} + diff --git a/modules/codec/a52old/imdct/imdct_common.c b/modules/codec/a52old/imdct/imdct_common.c new file mode 100644 index 0000000000..774abcf4a6 --- /dev/null +++ b/modules/codec/a52old/imdct/imdct_common.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * imdct_common.c: common A52 DCT functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: imdct_common.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "retables.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void E_( fft_64p ) ( complex_t *x ); + +void E_( imdct_do_256 ) (imdct_t * p_imdct, float data[],float delay[]) +{ + int i, j, k; + int p, q; + + float tmp_a_i; + float tmp_a_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + complex_t *buf1, *buf2; + + buf1 = &p_imdct->buf[0]; + buf2 = &p_imdct->buf[64]; + + /* Pre IFFT complex multiply plus IFFT complex conjugate */ + for (k=0; k<64; k++) { + /* X1[k] = X[2*k] + * X2[k] = X[2*k+1] */ + + j = pm64[k]; + p = 2 * (128-2*j-1); + q = 2 * (2 * j); + + /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf1[k].real = data[p] * p_imdct->xcos2[j] - data[q] * p_imdct->xsin2[j]; + buf1[k].imag = -1.0f*(data[q] * p_imdct->xcos2[j] + data[p] * p_imdct->xsin2[j]); + /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf2[k].real = data[p + 1] * p_imdct->xcos2[j] - data[q + 1] * p_imdct->xsin2[j]; + buf2[k].imag = -1.0f*(data[q + 1] * p_imdct->xcos2[j] + data[p + 1] * p_imdct->xsin2[j]); + } + + E_( fft_64p ) ( &buf1[0] ); + E_( fft_64p ) ( &buf2[0] ); + + /* Post IFFT complex multiply */ + for( i=0; i < 64; i++) { + tmp_a_r = buf1[i].real; + tmp_a_i = -buf1[i].imag; + buf1[i].real = (tmp_a_r * p_imdct->xcos2[i]) - (tmp_a_i * p_imdct->xsin2[i]); + buf1[i].imag = (tmp_a_r * p_imdct->xsin2[i]) + (tmp_a_i * p_imdct->xcos2[i]); + tmp_a_r = buf2[i].real; + tmp_a_i = -buf2[i].imag; + buf2[i].real = (tmp_a_r * p_imdct->xcos2[i]) - (tmp_a_i * p_imdct->xsin2[i]); + buf2[i].imag = (tmp_a_r * p_imdct->xsin2[i]) + (tmp_a_i * p_imdct->xcos2[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal */ + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].imag * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].real * *window_ptr++ + *delay_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].real * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].imag * *window_ptr++ + *delay_ptr++; + } + + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf2[i].real * *--window_ptr; + *delay_ptr++ = buf2[64-i-1].imag * *--window_ptr; + } + + for(i=0; i< 64; i++) { + *delay_ptr++ = buf2[i].imag * *--window_ptr; + *delay_ptr++ = -buf2[64-i-1].real * *--window_ptr; + } +} + + +void E_( imdct_do_256_nol ) (imdct_t * p_imdct, float data[], float delay[]) +{ + int i, j, k; + int p, q; + + float tmp_a_i; + float tmp_a_r; + + float *data_ptr; + float *delay_ptr; + float *window_ptr; + + complex_t *buf1, *buf2; + + buf1 = &p_imdct->buf[0]; + buf2 = &p_imdct->buf[64]; + + /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ + for(k=0; k<64; k++) { + /* X1[k] = X[2*k] + * X2[k] = X[2*k+1] */ + j = pm64[k]; + p = 2 * (128-2*j-1); + q = 2 * (2 * j); + + /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf1[k].real = data[p] * p_imdct->xcos2[j] - data[q] * p_imdct->xsin2[j]; + buf1[k].imag = -1.0f*(data[q] * p_imdct->xcos2[j] + data[p] * p_imdct->xsin2[j]); + /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ + buf2[k].real = data[p + 1] * p_imdct->xcos2[j] - data[q + 1] * p_imdct->xsin2[j]; + buf2[k].imag = -1.0f*(data[q + 1] * p_imdct->xcos2[j] + data[p + 1] * p_imdct->xsin2[j]); + } + + E_( fft_64p ) ( &buf1[0] ); + E_( fft_64p ) ( &buf2[0] ); + + /* Post IFFT complex multiply */ + for( i=0; i < 64; i++) { + /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ + tmp_a_r = buf1[i].real; + tmp_a_i = -buf1[i].imag; + buf1[i].real =(tmp_a_r * p_imdct->xcos2[i]) - (tmp_a_i * p_imdct->xsin2[i]); + buf1[i].imag =(tmp_a_r * p_imdct->xsin2[i]) + (tmp_a_i * p_imdct->xcos2[i]); + /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ + tmp_a_r = buf2[i].real; + tmp_a_i = -buf2[i].imag; + buf2[i].real =(tmp_a_r * p_imdct->xcos2[i]) - (tmp_a_i * p_imdct->xsin2[i]); + buf2[i].imag =(tmp_a_r * p_imdct->xsin2[i]) + (tmp_a_i * p_imdct->xcos2[i]); + } + + data_ptr = data; + delay_ptr = delay; + window_ptr = window; + + /* Window and convert to real valued signal, no overlap */ + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].imag * *window_ptr++; + *data_ptr++ = buf1[64-i-1].real * *window_ptr++; + } + + for(i=0; i< 64; i++) { + *data_ptr++ = -buf1[i].real * *window_ptr++ + *delay_ptr++; + *data_ptr++ = buf1[64-i-1].imag * *window_ptr++ + *delay_ptr++; + } + + delay_ptr = delay; + + for(i=0; i< 64; i++) { + *delay_ptr++ = -buf2[i].real * *--window_ptr; + *delay_ptr++ = buf2[64-i-1].imag * *--window_ptr; + } + + for(i=0; i< 64; i++) { + *delay_ptr++ = buf2[i].imag * *--window_ptr; + *delay_ptr++ = -buf2[64-i-1].real * *--window_ptr; + } +} diff --git a/modules/codec/a52old/imdct/imdct_common.h b/modules/codec/a52old/imdct/imdct_common.h new file mode 100644 index 0000000000..e5f19a22dd --- /dev/null +++ b/modules/codec/a52old/imdct/imdct_common.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * imdct_common.h: common A52 DCT headers + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: imdct_common.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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_( imdct_init ) ( imdct_t * p_imdct ); +void E_( imdct_do_256 ) ( imdct_t * p_imdct, float data[], float delay[] ); +void E_( imdct_do_256_nol ) ( imdct_t * p_imdct, float data[], float delay[] ); +void E_( imdct_do_512 ) ( imdct_t * p_imdct, float data[], float delay[] ); +void E_( imdct_do_512_nol ) ( imdct_t * p_imdct, float data[], float delay[] ); diff --git a/modules/codec/a52old/imdct/imdct_sse.c b/modules/codec/a52old/imdct/imdct_sse.c new file mode 100644 index 0000000000..fd5405ed8a --- /dev/null +++ b/modules/codec/a52old/imdct/imdct_sse.c @@ -0,0 +1,582 @@ +/***************************************************************************** + * imdct_sse.c: accelerated SSE A52 DCT + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: imdct_sse.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "imdct_common.h" +#include "retables.h" + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +void E_( fft_64p ) ( complex_t *x ); +void E_( fft_128p ) ( complex_t *a ); + +static void imdct512_pre_ifft_twiddle_sse ( const int *, complex_t *, + float *, float * ); +static void imdct512_post_ifft_twiddle_sse ( complex_t *, float * ); +static void imdct512_window_delay_sse ( complex_t *, float *, + float *, float * ); +static void imdct512_window_delay_nol_sse ( complex_t *, float *, + float *, float * ); + +void E_( imdct_init ) (imdct_t * p_imdct) +{ + int i; + float scale = 181.019; + + for (i=0; i < 128; i++) + { + float xcos_i = cos(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + float xsin_i = sin(2.0f * M_PI * (8*i+1)/(8*N)) * scale; + p_imdct->xcos_sin_sse[i * 4] = xcos_i; + p_imdct->xcos_sin_sse[i * 4 + 1] = -xsin_i; + p_imdct->xcos_sin_sse[i * 4 + 2] = -xsin_i; + p_imdct->xcos_sin_sse[i * 4 + 3] = -xcos_i; + } +} + +void E_( imdct_do_512 ) (imdct_t * p_imdct, float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_sse( pm128, p_imdct->buf, data, + p_imdct->xcos_sin_sse ); + E_( fft_128p ) ( p_imdct->buf ); + imdct512_post_ifft_twiddle_sse( p_imdct->buf, p_imdct->xcos_sin_sse ); + imdct512_window_delay_sse( p_imdct->buf, data, window, delay ); +} + + +void E_( imdct_do_512_nol ) (imdct_t * p_imdct, float data[], float delay[]) +{ + imdct512_pre_ifft_twiddle_sse( pm128, p_imdct->buf, data, + p_imdct->xcos_sin_sse ); + E_( fft_128p ) ( p_imdct->buf ); + imdct512_post_ifft_twiddle_sse( p_imdct->buf, p_imdct->xcos_sin_sse ); + imdct512_window_delay_nol_sse( p_imdct->buf, data, window, delay ); +} + +static void imdct512_pre_ifft_twiddle_sse (const int *pmt, complex_t *buf, float *data, float *xcos_sin_sse) +{ + __asm__ __volatile__ ( + ".align 16\n" + "pushl %%ebp\n" + "movl %%esp, %%ebp\n" + "addl $-4, %%esp\n" /* local variable, loop counter */ + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%edi\n" + "pushl %%esi\n" + + "movl %%edi, %%ebx\n" /* buf */ + "movl $64, -4(%%ebp)\n" + + ".align 16\n" +"0:\n" + "movl (%%eax), %%esi\n" + "movl 4(%%eax), %%edi\n" + "movss (%%ecx, %%esi, 8), %%xmm1\n" /* 2j */ + "movss (%%ecx, %%edi, 8), %%xmm3\n" /* 2(j+1) */ + + "shll $1, %%esi\n" + "shll $1, %%edi\n" + + "movaps (%%edx, %%esi, 8), %%xmm0\n" /* -c_j | -s_j | -s_j | c_j */ + "movaps (%%edx, %%edi, 8), %%xmm2\n" /* -c_j+1 | -s_j+1 | -s_j+1 | c_j+1 */ + + "negl %%esi\n" + "negl %%edi\n" + + "movss 1020(%%ecx, %%esi, 4), %%xmm4\n" /* 255-2j */ + "addl $8, %%eax\n" + "movss 1020(%%ecx, %%edi, 4), %%xmm5\n" /* 255-2(j+1) */ + + "shufps $0, %%xmm1, %%xmm4\n" /* 2j | 2j | 255-2j | 255-2j */ + "shufps $0, %%xmm3, %%xmm5\n" /* 2(j+1) | 2(j+1) | 255-2(j+1) | 255-2(j+1) */ + "mulps %%xmm4, %%xmm0\n" + "mulps %%xmm5, %%xmm2\n" + "movhlps %%xmm0, %%xmm1\n" + "movhlps %%xmm2, %%xmm3\n" + "addl $16, %%ebx\n" + "addps %%xmm1, %%xmm0\n" + "addps %%xmm3, %%xmm2\n" + "movlhps %%xmm2, %%xmm0\n" + + "movaps %%xmm0, -16(%%ebx)\n" + "decl -4(%%ebp)\n" + "jnz 0b\n" + + "popl %%esi\n" + "popl %%edi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + + "addl $4, %%esp\n" + "popl %%ebp\n" + : "=D" (buf) + : "a" (pmt), "c" (data), "d" (xcos_sin_sse), "D" (buf)); + +} + +static void imdct512_post_ifft_twiddle_sse (complex_t *buf, float *xcos_sin_sse) +{ + __asm__ __volatile__ ( + ".align 16\n" + "pushl %%ebx\n" + "movl $32, %%ebx\n" /* loop counter */ + + ".align 16\n" +"0:\n" + "movaps (%%eax), %%xmm0\n" /* im1 | re1 | im0 | re0 */ + + "movaps (%%ecx), %%xmm2\n" /* -c | -s | -s | c */ + "movhlps %%xmm0, %%xmm1\n" /* im1 | re1 */ + "movaps 16(%%ecx), %%xmm3\n" /* -c1 | -s1 | -s1 | c1 */ + + "shufps $0x50, %%xmm0, %%xmm0\n" /* im0 | im0 | re0 | re0 */ + "shufps $0x50, %%xmm1, %%xmm1\n" /* im1 | im1 | re1 | re1 */ + + "movaps 16(%%eax), %%xmm4\n" /* im3 | re3 | im2 | re2 */ + + "shufps $0x27, %%xmm2, %%xmm2\n" /* c | -s | -s | -c */ + "movhlps %%xmm4, %%xmm5\n" /* im3 | re3 */ + "shufps $0x27, %%xmm3, %%xmm3\n" /* c1 | -s1 | -s1 | -c1 */ + + "movaps 32(%%ecx), %%xmm6\n" /* -c2 | -s2 | -s2 | c2 */ + "movaps 48(%%ecx), %%xmm7\n" /* -c3 | -s3 | -s3 | c3 */ + + "shufps $0x50, %%xmm4, %%xmm4\n" /* im2 | im2 | re2 | re2 */ + "shufps $0x50, %%xmm5, %%xmm5\n" /* im3 | im3 | re3 | re3 */ + + "mulps %%xmm2, %%xmm0\n" + "mulps %%xmm3, %%xmm1\n" + + "shufps $0x27, %%xmm6, %%xmm6\n" /* c2 | -s2 | -s2 | -c2 */ + "shufps $0x27, %%xmm7, %%xmm7\n" /* c3 | -s3 | -s3 | -c3 */ + + "movhlps %%xmm0, %%xmm2\n" + "movhlps %%xmm1, %%xmm3\n" + + "mulps %%xmm6, %%xmm4\n" + "mulps %%xmm7, %%xmm5\n" + + "addps %%xmm2, %%xmm0\n" + "addps %%xmm3, %%xmm1\n" + + "movhlps %%xmm4, %%xmm6\n" + "movhlps %%xmm5, %%xmm7\n" + + "addps %%xmm6, %%xmm4\n" + "addps %%xmm7, %%xmm5\n" + + "movlhps %%xmm1, %%xmm0\n" + "movlhps %%xmm5, %%xmm4\n" + + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm4, 16(%%eax)\n" + "addl $64, %%ecx\n" + "addl $32, %%eax\n" + "decl %%ebx\n" + "jnz 0b\n" + + "popl %%ebx\n" + : "=a" (buf) + : "a" (buf), "c" (xcos_sin_sse) ); +} + +static void imdct512_window_delay_sse (complex_t *buf, float *data_ptr, float *window_prt, float *delay_prt) +{ + __asm__ __volatile__ ( + ".align 16\n" + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%edi\n" + "pushl %%esi\n" + "pushl %%ebp\n" + + "movl %%esi, %%ebp\n" /* buf */ + "movl $16, %%ebx\n" /* loop count */ + "leal 516(%%ebp), %%esi\n" /* buf[64].im */ + "leal 504(%%ebp), %%edi\n" /* buf[63].re */ + + ".align 16\n" +".first_128_samples:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | im1 | 0.0 | im0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | re1 | 0.0 | re0 */ + + "movaps (%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "movaps (%%ecx), %%xmm5\n" /* d3 | d2 | d1 | d0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* re1 | 0.0 | re0 | 0.0 */ + + "movss 16(%%esi), %%xmm6\n" /* im2 */ + "movss 24(%%esi), %%xmm7\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -re1 | im1 | -re0 | im0 */ + "movss -16(%%edi), %%xmm2\n" /* re2 */ + "movss -24(%%edi), %%xmm3\n" /* re3 */ + "mulps %%xmm4, %%xmm0\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | im3 | 0.0 | im2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | re3 | 0.0 | re2 */ + "addps %%xmm5, %%xmm0\n" + "shufps $0xb1, %%xmm2, %%xmm2\n"/* re3 | 0.0 | re2 | 0.0 */ + "movaps 16(%%edx), %%xmm4\n" /* w7 | w6 | w5 | w4 */ + "movaps 16(%%ecx), %%xmm5\n" /* d7 | d6 | d5 | d4 */ + "subps %%xmm2, %%xmm6\n" /* -re3 | im3 | -re2 | im2 */ + "addl $32, %%edx\n" + "movaps %%xmm0, (%%eax)\n" + "addl $32, %%ecx\n" + "mulps %%xmm4, %%xmm6\n" + "addl $32, %%esi\n" + "addl $32, %%eax\n" + "addps %%xmm5, %%xmm6\n" + "addl $-32, %%edi\n" + "movaps %%xmm6, -16(%%eax)\n" + "decl %%ebx\n" + "jnz .first_128_samples\n" + + "movl %%ebp, %%esi\n" /* buf[0].re */ + "movl $16, %%ebx\n" /* loop count */ + "leal 1020(%%ebp), %%edi\n" /* buf[127].im */ + + ".align 16\n" +".second_128_samples:\n" + "movss (%%esi), %%xmm0\n" /* buf[i].re */ + "movss 8(%%esi), %%xmm2\n" /* re1 */ + "movss (%%edi), %%xmm1\n" /* buf[127-i].im */ + "movss -8(%%edi), %%xmm3\n" /* im1 */ + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | re1 | 0.0 | re0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | im1 | 0.0 | im1 */ + + "movaps (%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "movaps (%%ecx), %%xmm5\n" /* d3 | d2 | d1 | d0 */ + + "shufps $0xb1, %%xmm1, %%xmm1\n"/* im1 | 0.0 | im0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* re2 */ + "movss 24(%%esi), %%xmm7\n" /* re3 */ + "movss -16(%%edi), %%xmm2\n" /* im2 */ + "movss -24(%%edi), %%xmm3\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -im1 | re1 | -im0 | re0 */ + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | re3 | 0.0 | re2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | im3 | 0.0 | im2 */ + "mulps %%xmm4, %%xmm0\n" + "shufps $0xb1, %%xmm2, %%xmm2\n"/* im3 | 0.0 | im2 | 0.0 */ + "movaps 16(%%edx), %%xmm4\n" /* w7 | w6 | w5 | w4 */ + "addl $32, %%esi\n" + "subps %%xmm2, %%xmm6\n" /* -im3 | re3 | -im2 | re2 */ + "addps %%xmm5, %%xmm0\n" + "mulps %%xmm4, %%xmm6\n" + "addl $-32, %%edi\n" + "movaps 16(%%ecx), %%xmm5\n" /* d7 | d6 | d5 | d4 */ + "movaps %%xmm0, (%%eax)\n" + "addps %%xmm5, %%xmm6\n" + "addl $32, %%edx\n" + "addl $32, %%eax\n" + "addl $32, %%ecx\n" + "movaps %%xmm6, -16(%%eax)\n" + "decl %%ebx\n" + "jnz .second_128_samples\n" + + "leal 512(%%ebp), %%esi\n" /* buf[64].re */ + "leal 508(%%ebp), %%edi\n" /* buf[63].im */ + "movl $16, %%ebx\n" /* loop count */ + "addl $-1024, %%ecx\n" /* delay */ + + ".align 16\n" +".first_128_delay:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | re1 | 0.0 | re0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | im1 | 0.0 | im0 */ + + "movaps -16(%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* im1 | 0.0 | im0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* re2 */ + "movss 24(%%esi), %%xmm7\n" /* re3 */ + "movss -16(%%edi), %%xmm2\n" /* im2 */ + "movss -24(%%edi), %%xmm3\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -im1 | re1 | -im0 | re0 */ + "addl $-32, %%edx\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | re3 | 0.0 | re2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | im3 | 0.0 | im2 */ + "mulps %%xmm4, %%xmm0\n" + "movaps (%%edx), %%xmm5\n" /* w7 | w6 | w5 | w4 */ + "shufps $0xb1, %%xmm2, %%xmm2\n"/* im3 | 0.0 | im2 | 0.0 */ + "movaps %%xmm0, (%%ecx)\n" + "addl $32, %%esi\n" + "subps %%xmm2, %%xmm6\n" /* -im3 | re3 | -im2 | re2 */ + "addl $-32, %%edi\n" + "mulps %%xmm5, %%xmm6\n" + "addl $32, %%ecx\n" + "movaps %%xmm6, -16(%%ecx)\n" + "decl %%ebx\n" + "jnz .first_128_delay\n" + + "leal 4(%%ebp), %%esi\n" /* buf[0].im */ + "leal 1016(%%ebp), %%edi\n" /* buf[127].re */ + "movl $16, %%ebx\n" /* loop count */ + + ".align 16\n" +".second_128_delay:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | im1 | 0.0 | im0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | re1 | 0.0 | re0 */ + + "movaps -16(%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* re1 | 0.0 | re0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* im2 */ + "movss 24(%%esi), %%xmm7\n" /* im3 */ + "movss -16(%%edi), %%xmm2\n" /* re2 */ + "movss -24(%%edi), %%xmm3\n" /* re3 */ + "subps %%xmm0, %%xmm1\n" /* re1 | -im1 | re0 | -im0 */ + "addl $-32, %%edx\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | im3 | 0.0 | im2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | re3 | 0.0 | re2 */ + "mulps %%xmm4, %%xmm1\n" + "movaps (%%edx), %%xmm5\n" /* w7 | w6 | w5 | w4 */ + "shufps $0xb1, %%xmm2, %%xmm2\n"/* re3 | 0.0 | re2 | 0.0 */ + "movaps %%xmm1, (%%ecx)\n" + "addl $32, %%esi\n" + "subps %%xmm6, %%xmm2\n" /* re | -im3 | re | -im2 */ + "addl $-32, %%edi\n" + "mulps %%xmm5, %%xmm2\n" + "addl $32, %%ecx\n" + "movaps %%xmm2, -16(%%ecx)\n" + "decl %%ebx\n" + "jnz .second_128_delay\n" + + "popl %%ebp\n" + "popl %%esi\n" + "popl %%edi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + : "=S" (buf), "=a" (data_ptr), "=c" (delay_prt), "=d" (window_prt) + : "S" (buf), "a" (data_ptr), "c" (delay_prt), "d" (window_prt)); + +} + +static void imdct512_window_delay_nol_sse( complex_t *buf, float *data_ptr, + float *window_prt, float *delay_prt ) +{ + __asm__ __volatile__ ( + ".align 16\n" + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%edi\n" + "pushl %%esi\n" + "pushl %%ebp\n" + + "movl %%esi, %%ebp\n" /* buf */ + "movl $16, %%ebx\n" /* loop count */ + "leal 516(%%ebp), %%esi\n" /* buf[64].im */ + "leal 504(%%ebp), %%edi\n" /* buf[63].re */ + + ".align 16\n" +".first_128_sample:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | im1 | 0.0 | im0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | re1 | 0.0 | re0 */ + + "movaps (%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* re1 | 0.0 | re0 | 0.0 */ + + "movss 16(%%esi), %%xmm6\n" /* im2 */ + "movss 24(%%esi), %%xmm7\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -re1 | im1 | -re0 | im0 */ + "movss -16(%%edi), %%xmm2\n" /* re2 */ + "movss -24(%%edi), %%xmm3\n" /* re3 */ + "mulps %%xmm4, %%xmm0\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | im3 | 0.0 | im2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | re3 | 0.0 | re2 */ + "shufps $0xb1, %%xmm2, %%xmm2\n"/* re3 | 0.0 | re2 | 0.0 */ + "movaps 16(%%edx), %%xmm4\n" /* w7 | w6 | w5 | w4 */ + "subps %%xmm2, %%xmm6\n" /* -re3 | im3 | -re2 | im2 */ + "addl $32, %%edx\n" + "movaps %%xmm0, (%%eax)\n" + "mulps %%xmm4, %%xmm6\n" + "addl $32, %%esi\n" + "addl $32, %%eax\n" + "addl $-32, %%edi\n" + "movaps %%xmm6, -16(%%eax)\n" + "decl %%ebx\n" + "jnz .first_128_sample\n" + + "movl %%ebp, %%esi\n" /* buf[0].re */ + "movl $16, %%ebx\n" /* loop count */ + "leal 1020(%%ebp), %%edi\n" /* buf[127].im */ + + ".align 16\n" +".second_128_sample:\n" + "movss (%%esi), %%xmm0\n" /* buf[i].re */ + "movss 8(%%esi), %%xmm2\n" /* re1 */ + "movss (%%edi), %%xmm1\n" /* buf[127-i].im */ + "movss -8(%%edi), %%xmm3\n" /* im1 */ + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | re1 | 0.0 | re0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | im1 | 0.0 | im1 */ + + "movaps (%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + + "shufps $0xb1, %%xmm1, %%xmm1\n"/* im1 | 0.0 | im0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* re2 */ + "movss 24(%%esi), %%xmm7\n" /* re3 */ + "movss -16(%%edi), %%xmm2\n" /* im2 */ + "movss -24(%%edi), %%xmm3\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -im1 | re1 | -im0 | re0 */ + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | re3 | 0.0 | re2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | im3 | 0.0 | im2 */ + "mulps %%xmm4, %%xmm0\n" + "shufps $0xb1, %%xmm2, %%xmm2\n"/* im3 | 0.0 | im2 | 0.0 */ + "movaps 16(%%edx), %%xmm4\n" /* w7 | w6 | w5 | w4 */ + "addl $32, %%esi\n" + "subps %%xmm2, %%xmm6\n" /* -im3 | re3 | -im2 | re2 */ + "mulps %%xmm4, %%xmm6\n" + "addl $-32, %%edi\n" + "movaps %%xmm0, (%%eax)\n" + "addl $32, %%edx\n" + "addl $32, %%eax\n" + "movaps %%xmm6, -16(%%eax)\n" + "decl %%ebx\n" + "jnz .second_128_sample\n" + + "leal 512(%%ebp), %%esi\n" /* buf[64].re */ + "leal 508(%%ebp), %%edi\n" /* buf[63].im */ + "movl $16, %%ebx\n" /* loop count */ + + ".align 16\n" +".first_128_delays:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | re1 | 0.0 | re0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | im1 | 0.0 | im0 */ + + "movaps -16(%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* im1 | 0.0 | im0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* re2 */ + "movss 24(%%esi), %%xmm7\n" /* re3 */ + "movss -16(%%edi), %%xmm2\n" /* im2 */ + "movss -24(%%edi), %%xmm3\n" /* im3 */ + "subps %%xmm1, %%xmm0\n" /* -im1 | re1 | -im0 | re0 */ + "addl $-32, %%edx\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | re3 | 0.0 | re2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | im3 | 0.0 | im2 */ + "mulps %%xmm4, %%xmm0\n" + "movaps (%%edx), %%xmm5\n" /* w7 | w6 | w5 | w4 */ + "shufps $0xb1, %%xmm2, %%xmm2\n"/* im3 | 0.0 | im2 | 0.0 */ + "movaps %%xmm0, (%%ecx)\n" + "addl $32, %%esi\n" + "subps %%xmm2, %%xmm6\n" /* -im3 | re3 | -im2 | re2 */ + "addl $-32, %%edi\n" + "mulps %%xmm5, %%xmm6\n" + "addl $32, %%ecx\n" + "movaps %%xmm6, -16(%%ecx)\n" + "decl %%ebx\n" + "jnz .first_128_delays\n" + + "leal 4(%%ebp), %%esi\n" /* buf[0].im */ + "leal 1016(%%ebp), %%edi\n" /* buf[127].re */ + "movl $16, %%ebx\n" /* loop count */ + + ".align 16\n" +".second_128_delays:\n" + "movss (%%esi), %%xmm0\n" + "movss 8(%%esi), %%xmm2\n" + "movss (%%edi), %%xmm1\n" + "movss -8(%%edi), %%xmm3\n" + + "movlhps %%xmm2, %%xmm0\n" /* 0.0 | im1 | 0.0 | im0 */ + "movlhps %%xmm3, %%xmm1\n" /* 0.0 | re1 | 0.0 | re0 */ + + "movaps -16(%%edx), %%xmm4\n" /* w3 | w2 | w1 | w0 */ + "shufps $0xb1, %%xmm1, %%xmm1\n"/* re1 | 0.0 | re0 | 0.0 */ + "movss 16(%%esi), %%xmm6\n" /* im2 */ + "movss 24(%%esi), %%xmm7\n" /* im3 */ + "movss -16(%%edi), %%xmm2\n" /* re2 */ + "movss -24(%%edi), %%xmm3\n" /* re3 */ + "subps %%xmm0, %%xmm1\n" /* re1 | -im1 | re0 | -im0 */ + "addl $-32, %%edx\n" + "movlhps %%xmm7, %%xmm6\n" /* 0.0 | im3 | 0.0 | im2 */ + "movlhps %%xmm3, %%xmm2\n" /* 0.0 | re3 | 0.0 | re2 */ + "mulps %%xmm4, %%xmm1\n" + "movaps (%%edx), %%xmm5\n" /* w7 | w6 | w5 | w4 */ + "shufps $0xb1, %%xmm2, %%xmm2\n"/* re3 | 0.0 | re2 | 0.0 */ + "movaps %%xmm1, (%%ecx)\n" + "addl $32, %%esi\n" + "subps %%xmm6, %%xmm2\n" /* re | -im3 | re | -im2 */ + "addl $-32, %%edi\n" + "mulps %%xmm5, %%xmm2\n" + "addl $32, %%ecx\n" + "movaps %%xmm2, -16(%%ecx)\n" + "decl %%ebx\n" + "jnz .second_128_delays\n" + + "popl %%ebp\n" + "popl %%esi\n" + "popl %%edi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + : "=S" (buf), "=a" (data_ptr), "=c" (delay_prt), "=d" (window_prt) + : "S" (buf), "a" (data_ptr), "c" (delay_prt), "d" (window_prt)); + +} diff --git a/modules/codec/a52old/imdct/retables.h b/modules/codec/a52old/imdct/retables.h new file mode 100644 index 0000000000..a9d496d7f0 --- /dev/null +++ b/modules/codec/a52old/imdct/retables.h @@ -0,0 +1,83 @@ +/***************************************************************************** + * retables.h: A52 DCT tables + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: retables.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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. + *****************************************************************************/ + +static float window[] ATTR_ALIGN(16) = { + 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, + 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, + 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, + 0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121, + 0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770, + 0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153, + 0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389, + 0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563, + 0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699, + 0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757, + 0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626, + 0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126, + 0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019, + 0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031, + 0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873, + 0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269, + 0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981, + 0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831, + 0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716, + 0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610, + 0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560, + 0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674, + 0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099, + 0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994, + 0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513, + 0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788, + 0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919, + 0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974, + 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, + 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, + 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, + 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 +}; + +static const int pm128[128] = +{ + 0, 16, 32, 48, 64, 80, 96, 112, 8, 40, 72, 104, 24, 56, 88, 120, + 4, 20, 36, 52, 68, 84, 100, 116, 12, 28, 44, 60, 76, 92, 108, 124, + 2, 18, 34, 50, 66, 82, 98, 114, 10, 42, 74, 106, 26, 58, 90, 122, + 6, 22, 38, 54, 70, 86, 102, 118, 14, 46, 78, 110, 30, 62, 94, 126, + 1, 17, 33, 49, 65, 81, 97, 113, 9, 41, 73, 105, 25, 57, 89, 121, + 5, 21, 37, 53, 69, 85, 101, 117, 13, 29, 45, 61, 77, 93, 109, 125, + 3, 19, 35, 51, 67, 83, 99, 115, 11, 43, 75, 107, 27, 59, 91, 123, + 7, 23, 39, 55, 71, 87, 103, 119, 15, 31, 47, 63, 79, 95, 111, 127 +}; + +static const int pm64[64] = +{ + 0, 8, 16, 24, 32, 40, 48, 56, + 4, 20, 36, 52, 12, 28, 44, 60, + 2, 10, 18, 26, 34, 42, 50, 58, + 6, 14, 22, 30, 38, 46, 54, 62, + 1, 9, 17, 25, 33, 41, 49, 57, + 5, 21, 37, 53, 13, 29, 45, 61, + 3, 11, 19, 27, 35, 43, 51, 59, + 7, 23, 39, 55, 15, 31, 47, 63 +}; + diff --git a/modules/codec/a52old/imdct/srfft.h b/modules/codec/a52old/imdct/srfft.h new file mode 100644 index 0000000000..fe91f8c014 --- /dev/null +++ b/modules/codec/a52old/imdct/srfft.h @@ -0,0 +1,292 @@ +/***************************************************************************** + * srfft.h: A52 FFT tables + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: srfft.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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. + *****************************************************************************/ + +static const complex_t delta16[4] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.92387953251129, -0.38268343236509}, + {0.70710678118655, -0.70710678118655}, + {0.38268343236509, -0.92387953251129}}; + +static const complex_t delta16_3[4] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.38268343236509, -0.92387953251129}, + {-0.70710678118655, -0.70710678118655}, + {-0.92387953251129, 0.38268343236509}}; + +static const complex_t delta32[8] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.98078528040323, -0.19509032201613}, + {0.92387953251129, -0.38268343236509}, + {0.83146961230255, -0.55557023301960}, + {0.70710678118655, -0.70710678118655}, + {0.55557023301960, -0.83146961230255}, + {0.38268343236509, -0.92387953251129}, + {0.19509032201613, -0.98078528040323}}; + +static const complex_t delta32_3[8] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.83146961230255, -0.55557023301960}, + {0.38268343236509, -0.92387953251129}, + {-0.19509032201613, -0.98078528040323}, + {-0.70710678118655, -0.70710678118655}, + {-0.98078528040323, -0.19509032201613}, + {-0.92387953251129, 0.38268343236509}, + {-0.55557023301960, 0.83146961230255}}; + +static const complex_t delta64[16] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.99518472667220, -0.09801714032956}, + {0.98078528040323, -0.19509032201613}, + {0.95694033573221, -0.29028467725446}, + {0.92387953251129, -0.38268343236509}, + {0.88192126434836, -0.47139673682600}, + {0.83146961230255, -0.55557023301960}, + {0.77301045336274, -0.63439328416365}, + {0.70710678118655, -0.70710678118655}, + {0.63439328416365, -0.77301045336274}, + {0.55557023301960, -0.83146961230255}, + {0.47139673682600, -0.88192126434835}, + {0.38268343236509, -0.92387953251129}, + {0.29028467725446, -0.95694033573221}, + {0.19509032201613, -0.98078528040323}, + {0.09801714032956, -0.99518472667220}}; + +static const complex_t delta64_3[16] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.95694033573221, -0.29028467725446}, + {0.83146961230255, -0.55557023301960}, + {0.63439328416365, -0.77301045336274}, + {0.38268343236509, -0.92387953251129}, + {0.09801714032956, -0.99518472667220}, + {-0.19509032201613, -0.98078528040323}, + {-0.47139673682600, -0.88192126434836}, + {-0.70710678118655, -0.70710678118655}, + {-0.88192126434835, -0.47139673682600}, + {-0.98078528040323, -0.19509032201613}, + {-0.99518472667220, 0.09801714032956}, + {-0.92387953251129, 0.38268343236509}, + {-0.77301045336274, 0.63439328416365}, + {-0.55557023301960, 0.83146961230255}, + {-0.29028467725446, 0.95694033573221}}; + +static const complex_t delta128[32] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.99879545620517, -0.04906767432742}, + {0.99518472667220, -0.09801714032956}, + {0.98917650996478, -0.14673047445536}, + {0.98078528040323, -0.19509032201613}, + {0.97003125319454, -0.24298017990326}, + {0.95694033573221, -0.29028467725446}, + {0.94154406518302, -0.33688985339222}, + {0.92387953251129, -0.38268343236509}, + {0.90398929312344, -0.42755509343028}, + {0.88192126434836, -0.47139673682600}, + {0.85772861000027, -0.51410274419322}, + {0.83146961230255, -0.55557023301960}, + {0.80320753148064, -0.59569930449243}, + {0.77301045336274, -0.63439328416365}, + {0.74095112535496, -0.67155895484702}, + {0.70710678118655, -0.70710678118655}, + {0.67155895484702, -0.74095112535496}, + {0.63439328416365, -0.77301045336274}, + {0.59569930449243, -0.80320753148064}, + {0.55557023301960, -0.83146961230255}, + {0.51410274419322, -0.85772861000027}, + {0.47139673682600, -0.88192126434835}, + {0.42755509343028, -0.90398929312344}, + {0.38268343236509, -0.92387953251129}, + {0.33688985339222, -0.94154406518302}, + {0.29028467725446, -0.95694033573221}, + {0.24298017990326, -0.97003125319454}, + {0.19509032201613, -0.98078528040323}, + {0.14673047445536, -0.98917650996478}, + {0.09801714032956, -0.99518472667220}, + {0.04906767432742, -0.99879545620517}}; + +static const complex_t delta128_3[32] ATTR_ALIGN(16) = + { {1.00000000000000, 0.00000000000000}, + {0.98917650996478, -0.14673047445536}, + {0.95694033573221, -0.29028467725446}, + {0.90398929312344, -0.42755509343028}, + {0.83146961230255, -0.55557023301960}, + {0.74095112535496, -0.67155895484702}, + {0.63439328416365, -0.77301045336274}, + {0.51410274419322, -0.85772861000027}, + {0.38268343236509, -0.92387953251129}, + {0.24298017990326, -0.97003125319454}, + {0.09801714032956, -0.99518472667220}, + {-0.04906767432742, -0.99879545620517}, + {-0.19509032201613, -0.98078528040323}, + {-0.33688985339222, -0.94154406518302}, + {-0.47139673682600, -0.88192126434836}, + {-0.59569930449243, -0.80320753148065}, + {-0.70710678118655, -0.70710678118655}, + {-0.80320753148065, -0.59569930449243}, + {-0.88192126434835, -0.47139673682600}, + {-0.94154406518302, -0.33688985339222}, + {-0.98078528040323, -0.19509032201613}, + {-0.99879545620517, -0.04906767432742}, + {-0.99518472667220, 0.09801714032956}, + {-0.97003125319454, 0.24298017990326}, + {-0.92387953251129, 0.38268343236509}, + {-0.85772861000027, 0.51410274419322}, + {-0.77301045336274, 0.63439328416365}, + {-0.67155895484702, 0.74095112535496}, + {-0.55557023301960, 0.83146961230255}, + {-0.42755509343028, 0.90398929312344}, + {-0.29028467725446, 0.95694033573221}, + {-0.14673047445536, 0.98917650996478}}; + +#define HSQRT2 0.707106781188; + +#define TRANSZERO(A0,A4,A8,A12) { \ + u_r = wTB[0].real; \ + v_i = u_r - wTB[k*2].real; \ + u_r += wTB[k*2].real; \ + u_i = wTB[0].imag; \ + v_r = wTB[k*2].imag - u_i; \ + u_i += wTB[k*2].imag; \ + a_r = A0.real; \ + a_i = A0.imag; \ + a1_r = a_r; \ + a1_r += u_r; \ + A0.real = a1_r; \ + a_r -= u_r; \ + A8.real = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A0.imag = a1_i; \ + a_i -= u_i; \ + A8.imag = a_i; \ + a1_r = A4.real; \ + a1_i = A4.imag; \ + a_r = a1_r; \ + a_r -= v_r; \ + A4.real = a_r; \ + a1_r += v_r; \ + A12.real = a1_r; \ + a_i = a1_i; \ + a_i -= v_i; \ + A4.imag = a_i; \ + a1_i += v_i; \ + A12.imag = a1_i; \ + } + +#define TRANSHALF_16(A2,A6,A10,A14) {\ + u_r = wTB[2].real; \ + a_r = u_r; \ + u_i = wTB[2].imag; \ + u_r += u_i; \ + u_i -= a_r; \ + a_r = wTB[6].real; \ + a1_r = a_r; \ + a_i = wTB[6].imag; \ + a_r = a_i - a_r; \ + a_i += a1_r; \ + v_i = u_r - a_r; \ + u_r += a_r; \ + v_r = u_i + a_i; \ + u_i -= a_i; \ + v_i *= HSQRT2; \ + v_r *= HSQRT2; \ + u_r *= HSQRT2; \ + u_i *= HSQRT2; \ + a_r = A2.real; \ + a_i = A2.imag; \ + a1_r = a_r; \ + a1_r += u_r; \ + A2.real = a1_r; \ + a_r -= u_r; \ + A10.real = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A2.imag = a1_i; \ + a_i -= u_i; \ + A10.imag = a_i; \ + a1_r = A6.real; \ + a1_i = A6.imag; \ + a_r = a1_r; \ + a1_r += v_r; \ + A6.real = a1_r; \ + a_r -= v_r; \ + A14.real = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A6.imag = a1_i; \ + a_i += v_i; \ + A14.imag = a_i; \ + } + +#define TRANS(A1,A5,A9,A13,WT,WB,D,D3) { \ + u_r = WT.real; \ + a_r = u_r; \ + a_r *= D.imag; \ + u_r *= D.real; \ + a_i = WT.imag; \ + a1_i = a_i; \ + a1_i *= D.real; \ + a_i *= D.imag; \ + u_r -= a_i; \ + u_i = a_r; \ + u_i += a1_i; \ + a_r = WB.real; \ + a1_r = a_r; \ + a1_r *= D3.real; \ + a_r *= D3.imag; \ + a_i = WB.imag; \ + a1_i = a_i; \ + a_i *= D3.real; \ + a1_i *= D3.imag; \ + a1_r -= a1_i; \ + a_r += a_i; \ + v_i = u_r - a1_r; \ + u_r += a1_r; \ + v_r = a_r - u_i; \ + u_i += a_r; \ + a_r = A1.real; \ + a_i = A1.imag; \ + a1_r = a_r; \ + a1_r += u_r; \ + A1.real = a1_r; \ + a_r -= u_r; \ + A9.real = a_r; \ + a1_i = a_i; \ + a1_i += u_i; \ + A1.imag = a1_i; \ + a_i -= u_i; \ + A9.imag = a_i; \ + a1_r = A5.real; \ + a1_i = A5.imag; \ + a_r = a1_r; \ + a1_r -= v_r; \ + A5.real = a1_r; \ + a_r += v_r; \ + A13.real = a_r; \ + a_i = a1_i; \ + a1_i -= v_i; \ + A5.imag = a1_i; \ + a_i += v_i; \ + A13.imag = a_i; \ + } + diff --git a/modules/codec/a52old/imdct/srfft_3dn.c b/modules/codec/a52old/imdct/srfft_3dn.c new file mode 100644 index 0000000000..1416241529 --- /dev/null +++ b/modules/codec/a52old/imdct/srfft_3dn.c @@ -0,0 +1,335 @@ +/***************************************************************************** + * srfft_3dn.c: accelerated 3D Now! A52 fft functions + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: srfft_3dn.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "srfft.h" + +void hsqrt2_3dn (void); +void C_1_3dn (void); +static void fft_4_3dn (complex_t *x); +static void fft_8_3dn (complex_t *x); +static void fft_asmb_3dn (int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3); + +void E_( fft_64p ) ( complex_t *a ) +{ + fft_8_3dn(&a[0]); fft_4_3dn(&a[8]); fft_4_3dn(&a[12]); + fft_asmb_3dn(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[16]), fft_8_3dn(&a[24]); + fft_asmb_3dn(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_3dn(&a[32]); fft_4_3dn(&a[40]); fft_4_3dn(&a[44]); + fft_asmb_3dn(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[48]); fft_4_3dn(&a[56]); fft_4_3dn(&a[60]); + fft_asmb_3dn(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_3dn(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); +} + +void E_( fft_128p ) ( complex_t *a ) +{ + fft_8_3dn(&a[0]); fft_4_3dn(&a[8]); fft_4_3dn(&a[12]); + fft_asmb_3dn(2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[16]), fft_8_3dn(&a[24]); + fft_asmb_3dn(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_3dn(&a[32]); fft_4_3dn(&a[40]); fft_4_3dn(&a[44]); + fft_asmb_3dn(2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[48]); fft_4_3dn(&a[56]); fft_4_3dn(&a[60]); + fft_asmb_3dn(2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_3dn(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); + + fft_8_3dn(&a[64]); fft_4_3dn(&a[72]); fft_4_3dn(&a[76]); + /* fft_16(&a[64]); */ + fft_asmb_3dn(2, &a[64], &a[72], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[80]); fft_8_3dn(&a[88]); + + /* fft_32(&a[64]); */ + fft_asmb_3dn(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); + + fft_8_3dn(&a[96]); fft_4_3dn(&a[104]), fft_4_3dn(&a[108]); + /* fft_16(&a[96]); */ + fft_asmb_3dn(2, &a[96], &a[104], &delta16[0], &delta16_3[0]); + + fft_8_3dn(&a[112]), fft_8_3dn(&a[120]); + /* fft_32(&a[96]); */ + fft_asmb_3dn(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); + + /* fft_128(&a[0]); */ + fft_asmb_3dn(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); +} + +void hsqrt2_3dn (void) +{ + __asm__ ( + ".float 0f0.707106781188\n" + ".float 0f0.707106781188\n" + ".float 0f-0.707106781188\n" + ".float 0f-0.707106781188\n" + ); +} + +void C_1_3dn (void) +{ + __asm__ ( + ".float 0f-1.0\n" + ".float 0f1.0\n" + ".float 0f-1.0\n" + ".float 0f1.0\n" + ); +} + +static void fft_4_3dn (complex_t *x) +{ + __asm__ __volatile__ ( + ".align 16\n" + "movq (%%eax), %%mm0\n" /* x[0] */ + "movq 8(%%eax), %%mm1\n" /* x[1] */ + "movq 16(%%eax), %%mm2\n" /* x[2] */ + "movq 24(%%eax), %%mm3\n" /* x[3] */ + "movq %%mm0, %%mm4\n" /* x[1] */ + "movq %%mm1, %%mm5\n" /* x[1] */ + "movq %%mm0, %%mm6\n" /* x[0] */ + "pfadd %%mm2, %%mm0\n" /* x[0] + x[2] */ + "pfadd %%mm3, %%mm1\n" /* x[1] + x[3] */ + "pfsub %%mm2, %%mm4\n" /* x[0] - x[2] */ + "pfsub %%mm3, %%mm5\n" /* x[1] - x[3] */ + + "pfadd %%mm1, %%mm0\n" /* x[0] + x[2] + x[1] + x[3] */ + "pfsub %%mm1, %%mm6\n" /* x[0] + x[2] - x[1] - x[3] */ + + "movq %%mm0, (%%eax)\n" + "movq %%mm6, 16(%%eax)\n" + + "pxor %%mm6, %%mm6\n" + "movq %%mm5, %%mm2\n" /* x[1] - x[3] */ + "movq %%mm4, %%mm3\n" /* x[0] - x[2] */ + "pfsub %%mm5, %%mm6\n" /* x[3] - x[1] */ + + "punpckhdq %%mm2,%%mm2\n" /* x[1] - x[3].im */ + "punpckldq %%mm6,%%mm6\n" /* x[3] - x[1].re */ + "punpckhdq %%mm6,%%mm2\n" /* x[3] - x[1].re, x[1] - x[3].im */ + + "pfsub %%mm2, %%mm4\n" /* x0i-x2i-x3r+x1.r,x0r-x2r-x1i+x3i */ + "pfadd %%mm3, %%mm2\n" /* x0i-x2i+x3r-x1.r, x0r-x2r+x1i-x3.i */ + + "movq %%mm2, 8(%%eax)\n" /* mm4_2 + mm6_1, mm4_1 + mm5_2 */ + "movq %%mm4, 24(%%eax)\n" /* mm4_2 - mm6_1, mm4_1 - mm5_2 */ + "femms\n" + : "=a" (x) + : "a" (x) ); +} + +static void fft_8_3dn (complex_t *x) +{ + register float wT1_r, wT1_i, wB1_r, wB1_i, wT2_r, wT2_i, wB2_r, wB2_i; + + wT1_r = x[1].real; + wT1_i = x[1].imag; + wB1_r = x[3].real; + wB1_i = x[3].imag; + + x[1] = x[2]; + x[2] = x[4]; + x[3] = x[6]; + { /* fft_4 */ + register float yt_r, yt_i, yb_r, yb_i, u_r, u_i, vi_r, vi_i; + + yt_r = x[0].real; + yb_r = yt_r - x[2].real; + yt_r += x[2].real; + + u_r = x[1].real; + vi_i = x[3].real - u_r; + u_r += x[3].real; + + u_i = x[1].imag; + vi_r = u_i - x[3].imag; + u_i += x[3].imag; + + yt_i = yt_r; + yt_i += u_r; + x[0].real = yt_i; + yt_r -= u_r; + x[2].real = yt_r; + yt_i = yb_r; + yt_i += vi_r; + x[1].real = yt_i; + yb_r -= vi_r; + x[3].real = yb_r; + + yt_i = x[0].imag; + yb_i = yt_i - x[2].imag; + yt_i += x[2].imag; + + yt_r = yt_i; + yt_r += u_i; + x[0].imag = yt_r; + yt_i -= u_i; + x[2].imag = yt_i; + yt_r = yb_i; + yt_r += vi_i; + x[1].imag = yt_r; + yb_i -= vi_i; + x[3].imag = yb_i; + } + + /* x[0] x[4] */ + wT2_r = x[5].real; + wT2_r += x[7].real; + wT2_r += wT1_r; + wT2_r += wB1_r; + wT2_i = wT2_r; + wT2_r += x[0].real; + wT2_i = x[0].real - wT2_i; + x[0].real = wT2_r; + x[4].real = wT2_i; + + wT2_i = x[5].imag; + wT2_i += x[7].imag; + wT2_i += wT1_i; + wT2_i += wB1_i; + wT2_r = wT2_i; + wT2_r += x[0].imag; + wT2_i = x[0].imag - wT2_i; + x[0].imag = wT2_r; + x[4].imag = wT2_i; + + /* x[2] x[6] */ + wT2_r = x[5].imag; + wT2_r -= x[7].imag; + wT2_r += wT1_i; + wT2_r -= wB1_i; + wT2_i = wT2_r; + wT2_r += x[2].real; + wT2_i = x[2].real - wT2_i; + x[2].real = wT2_r; + x[6].real = wT2_i; + + wT2_i = x[5].real; + wT2_i -= x[7].real; + wT2_i += wT1_r; + wT2_i -= wB1_r; + wT2_r = wT2_i; + wT2_r += x[2].imag; + wT2_i = x[2].imag - wT2_i; + x[2].imag = wT2_i; + x[6].imag = wT2_r; + + /* x[1] x[5] */ + wT2_r = wT1_r; + wT2_r += wB1_i; + wT2_r -= x[5].real; + wT2_r -= x[7].imag; + wT2_i = wT1_i; + wT2_i -= wB1_r; + wT2_i -= x[5].imag; + wT2_i += x[7].real; + + wB2_r = wT2_r; + wB2_r += wT2_i; + wT2_i -= wT2_r; + wB2_r *= HSQRT2; + wT2_i *= HSQRT2; + wT2_r = wB2_r; + wB2_r += x[1].real; + wT2_r = x[1].real - wT2_r; + + wB2_i = x[5].real; + x[1].real = wB2_r; + x[5].real = wT2_r; + + wT2_r = wT2_i; + wT2_r += x[1].imag; + wT2_i = x[1].imag - wT2_i; + wB2_r = x[5].imag; + x[1].imag = wT2_r; + x[5].imag = wT2_i; + + /* x[3] x[7] */ + wT1_r -= wB1_i; + wT1_i += wB1_r; + wB1_r = wB2_i - x[7].imag; + wB1_i = wB2_r + x[7].real; + wT1_r -= wB1_r; + wT1_i -= wB1_i; + wB1_r = wT1_r + wT1_i; + wB1_r *= HSQRT2; + wT1_i -= wT1_r; + wT1_i *= HSQRT2; + wB2_r = x[3].real; + wB2_i = wB2_r + wT1_i; + wB2_r -= wT1_i; + x[3].real = wB2_i; + x[7].real = wB2_r; + wB2_i = x[3].imag; + wB2_r = wB2_i + wB1_r; + wB2_i -= wB1_r; + x[3].imag = wB2_i; + x[7].imag = wB2_r; +} + + +static void fft_asmb_3dn (int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3) +{ + register complex_t *x2k, *x3k, *x4k, *wB; + register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; + + x2k = x + 2 * k; + x3k = x2k + 2 * k; + x4k = x3k + 2 * k; + wB = wTB + 2 * k; + + TRANSZERO(x[0],x2k[0],x3k[0],x4k[0]); + TRANS(x[1],x2k[1],x3k[1],x4k[1],wTB[1],wB[1],d[1],d_3[1]); + + --k; + for(;;) { + TRANS(x[2],x2k[2],x3k[2],x4k[2],wTB[2],wB[2],d[2],d_3[2]); + TRANS(x[3],x2k[3],x3k[3],x4k[3],wTB[3],wB[3],d[3],d_3[3]); + if (!--k) break; + x += 2; + x2k += 2; + x3k += 2; + x4k += 2; + d += 2; + d_3 += 2; + wTB += 2; + wB += 2; + } +} diff --git a/modules/codec/a52old/imdct/srfft_c.c b/modules/codec/a52old/imdct/srfft_c.c new file mode 100644 index 0000000000..db7a1811e1 --- /dev/null +++ b/modules/codec/a52old/imdct/srfft_c.c @@ -0,0 +1,306 @@ +/***************************************************************************** + * srfft.c: A52 FFT in C + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: srfft_c.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "srfft.h" + +static void fft_8 (complex_t *x); + +static void fft_4(complex_t *x) +{ + /* delta_p = 1 here */ + /* x[k] = sum_{i=0..3} x[i] * w^{i*k}, w=e^{-2*pi/4} + */ + + register float yt_r, yt_i, yb_r, yb_i, u_r, u_i, vi_r, vi_i; + + yt_r = x[0].real; + yb_r = yt_r - x[2].real; + yt_r += x[2].real; + + u_r = x[1].real; + vi_i = x[3].real - u_r; + u_r += x[3].real; + + u_i = x[1].imag; + vi_r = u_i - x[3].imag; + u_i += x[3].imag; + + yt_i = yt_r; + yt_i += u_r; + x[0].real = yt_i; + yt_r -= u_r; + x[2].real = yt_r; + yt_i = yb_r; + yt_i += vi_r; + x[1].real = yt_i; + yb_r -= vi_r; + x[3].real = yb_r; + + yt_i = x[0].imag; + yb_i = yt_i - x[2].imag; + yt_i += x[2].imag; + + yt_r = yt_i; + yt_r += u_i; + x[0].imag = yt_r; + yt_i -= u_i; + x[2].imag = yt_i; + yt_r = yb_i; + yt_r += vi_i; + x[1].imag = yt_r; + yb_i -= vi_i; + x[3].imag = yb_i; +} + + +static void fft_8 (complex_t *x) +{ + /* delta_p = diag{1, sqrt(i)} here */ + /* x[k] = sum_{i=0..7} x[i] * w^{i*k}, w=e^{-2*pi/8} + */ + register float wT1_r, wT1_i, wB1_r, wB1_i, wT2_r, wT2_i, wB2_r, wB2_i; + + wT1_r = x[1].real; + wT1_i = x[1].imag; + wB1_r = x[3].real; + wB1_i = x[3].imag; + + x[1] = x[2]; + x[2] = x[4]; + x[3] = x[6]; + fft_4(&x[0]); + + + /* x[0] x[4] */ + wT2_r = x[5].real; + wT2_r += x[7].real; + wT2_r += wT1_r; + wT2_r += wB1_r; + wT2_i = wT2_r; + wT2_r += x[0].real; + wT2_i = x[0].real - wT2_i; + x[0].real = wT2_r; + x[4].real = wT2_i; + + wT2_i = x[5].imag; + wT2_i += x[7].imag; + wT2_i += wT1_i; + wT2_i += wB1_i; + wT2_r = wT2_i; + wT2_r += x[0].imag; + wT2_i = x[0].imag - wT2_i; + x[0].imag = wT2_r; + x[4].imag = wT2_i; + + /* x[2] x[6] */ + wT2_r = x[5].imag; + wT2_r -= x[7].imag; + wT2_r += wT1_i; + wT2_r -= wB1_i; + wT2_i = wT2_r; + wT2_r += x[2].real; + wT2_i = x[2].real - wT2_i; + x[2].real = wT2_r; + x[6].real = wT2_i; + + wT2_i = x[5].real; + wT2_i -= x[7].real; + wT2_i += wT1_r; + wT2_i -= wB1_r; + wT2_r = wT2_i; + wT2_r += x[2].imag; + wT2_i = x[2].imag - wT2_i; + x[2].imag = wT2_i; + x[6].imag = wT2_r; + + + /* x[1] x[5] */ + wT2_r = wT1_r; + wT2_r += wB1_i; + wT2_r -= x[5].real; + wT2_r -= x[7].imag; + wT2_i = wT1_i; + wT2_i -= wB1_r; + wT2_i -= x[5].imag; + wT2_i += x[7].real; + + wB2_r = wT2_r; + wB2_r += wT2_i; + wT2_i -= wT2_r; + wB2_r *= HSQRT2; + wT2_i *= HSQRT2; + wT2_r = wB2_r; + wB2_r += x[1].real; + wT2_r = x[1].real - wT2_r; + + wB2_i = x[5].real; + x[1].real = wB2_r; + x[5].real = wT2_r; + + wT2_r = wT2_i; + wT2_r += x[1].imag; + wT2_i = x[1].imag - wT2_i; + wB2_r = x[5].imag; + x[1].imag = wT2_r; + x[5].imag = wT2_i; + + /* x[3] x[7] */ + wT1_r -= wB1_i; + wT1_i += wB1_r; + wB1_r = wB2_i - x[7].imag; + wB1_i = wB2_r + x[7].real; + wT1_r -= wB1_r; + wT1_i -= wB1_i; + wB1_r = wT1_r + wT1_i; + wB1_r *= HSQRT2; + wT1_i -= wT1_r; + wT1_i *= HSQRT2; + wB2_r = x[3].real; + wB2_i = wB2_r + wT1_i; + wB2_r -= wT1_i; + x[3].real = wB2_i; + x[7].real = wB2_r; + wB2_i = x[3].imag; + wB2_r = wB2_i + wB1_r; + wB2_i -= wB1_r; + x[3].imag = wB2_i; + x[7].imag = wB2_r; +} + + +static void fft_asmb(int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3) +{ + register complex_t *x2k, *x3k, *x4k, *wB; + register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; + + x2k = x + 2 * k; + x3k = x2k + 2 * k; + x4k = x3k + 2 * k; + wB = wTB + 2 * k; + + TRANSZERO(x[0],x2k[0],x3k[0],x4k[0]); + TRANS(x[1],x2k[1],x3k[1],x4k[1],wTB[1],wB[1],d[1],d_3[1]); + + --k; + for(;;) { + TRANS(x[2],x2k[2],x3k[2],x4k[2],wTB[2],wB[2],d[2],d_3[2]); + TRANS(x[3],x2k[3],x3k[3],x4k[3],wTB[3],wB[3],d[3],d_3[3]); + if (!--k) break; + x += 2; + x2k += 2; + x3k += 2; + x4k += 2; + d += 2; + d_3 += 2; + wTB += 2; + wB += 2; + } + +} + +static void fft_asmb16(complex_t *x, complex_t *wTB) +{ + register float a_r, a_i, a1_r, a1_i, u_r, u_i, v_r, v_i; + int k = 2; + + /* transform x[0], x[8], x[4], x[12] */ + TRANSZERO(x[0],x[4],x[8],x[12]); + + /* transform x[1], x[9], x[5], x[13] */ + TRANS(x[1],x[5],x[9],x[13],wTB[1],wTB[5],delta16[1],delta16_3[1]); + + /* transform x[2], x[10], x[6], x[14] */ + TRANSHALF_16(x[2],x[6],x[10],x[14]); + + /* transform x[3], x[11], x[7], x[15] */ + TRANS(x[3],x[7],x[11],x[15],wTB[3],wTB[7],delta16[3],delta16_3[3]); + +} + + +void E_( fft_64p ) ( complex_t *a ) +{ + fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); + fft_asmb16(&a[0], &a[8]); + + fft_8(&a[16]), fft_8(&a[24]); + fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); + fft_asmb16(&a[32], &a[40]); + + fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); + fft_asmb16(&a[48], &a[56]); + + fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); +} + + +void E_( fft_128p ) ( complex_t *a ) +{ + fft_8(&a[0]); fft_4(&a[8]); fft_4(&a[12]); + fft_asmb16(&a[0], &a[8]); + + fft_8(&a[16]), fft_8(&a[24]); + fft_asmb(4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8(&a[32]); fft_4(&a[40]); fft_4(&a[44]); + fft_asmb16(&a[32], &a[40]); + + fft_8(&a[48]); fft_4(&a[56]); fft_4(&a[60]); + fft_asmb16(&a[48], &a[56]); + + fft_asmb(8, &a[0], &a[32],&delta64[0], &delta64_3[0]); + + fft_8(&a[64]); fft_4(&a[72]); fft_4(&a[76]); + /* fft_16(&a[64]); */ + fft_asmb16(&a[64], &a[72]); + + fft_8(&a[80]); fft_8(&a[88]); + + /* fft_32(&a[64]); */ + fft_asmb(4, &a[64], &a[80],&delta32[0], &delta32_3[0]); + + fft_8(&a[96]); fft_4(&a[104]), fft_4(&a[108]); + /* fft_16(&a[96]); */ + fft_asmb16(&a[96], &a[104]); + + fft_8(&a[112]), fft_8(&a[120]); + /* fft_32(&a[96]); */ + fft_asmb(4, &a[96], &a[112], &delta32[0], &delta32_3[0]); + + /* fft_128(&a[0]); */ + fft_asmb(16, &a[0], &a[64], &delta128[0], &delta128_3[0]); +} + diff --git a/modules/codec/a52old/imdct/srfft_sse.c b/modules/codec/a52old/imdct/srfft_sse.c new file mode 100644 index 0000000000..37f65e608e --- /dev/null +++ b/modules/codec/a52old/imdct/srfft_sse.c @@ -0,0 +1,360 @@ +/***************************************************************************** + * srfft_sse.c: accelerated SSE A52 fft functions + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: srfft_sse.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Renaud Dartus + * Aaron Holtzman + * + * 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 +#include + +#include + +#include "../imdct.h" +#include "srfft.h" + + +static float hsqrt2_sse[] ATTR_ALIGN(16) = + { 0.707106781188, 0.707106781188, -0.707106781188, -0.707106781188 }; + +static float C_1_sse[] ATTR_ALIGN(16) = + { -1.0, 1.0, -1.0, 1.0 }; + +typedef struct { + int k; + void * C1; + } ck_sse_t; + + +static void fft_4_sse (complex_t *x); +static void fft_8_sse (complex_t *x); +static void fft_asmb_sse (ck_sse_t * ck, int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3); + +void E_( fft_64p ) ( complex_t *a ) +{ + ck_sse_t ck; + ck.C1 = C_1_sse; + + fft_8_sse(&a[0]); fft_4_sse(&a[8]); fft_4_sse(&a[12]); + fft_asmb_sse(&ck, 2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[16]), fft_8_sse(&a[24]); + fft_asmb_sse(&ck, 4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_sse(&a[32]); fft_4_sse(&a[40]); fft_4_sse(&a[44]); + fft_asmb_sse(&ck, 2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[48]); fft_4_sse(&a[56]); fft_4_sse(&a[60]); + fft_asmb_sse(&ck, 2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_sse(&ck, 8, &a[0], &a[32],&delta64[0], &delta64_3[0]); +} + +void E_( fft_128p ) ( complex_t *a ) +{ + ck_sse_t ck; + ck.C1 = C_1_sse; + + fft_8_sse(&a[0]); fft_4_sse(&a[8]); fft_4_sse(&a[12]); + fft_asmb_sse(&ck, 2, &a[0], &a[8], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[16]), fft_8_sse(&a[24]); + fft_asmb_sse(&ck, 4, &a[0], &a[16],&delta32[0], &delta32_3[0]); + + fft_8_sse(&a[32]); fft_4_sse(&a[40]); fft_4_sse(&a[44]); + fft_asmb_sse(&ck, 2, &a[32], &a[40], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[48]); fft_4_sse(&a[56]); fft_4_sse(&a[60]); + fft_asmb_sse(&ck, 2, &a[48], &a[56], &delta16[0], &delta16_3[0]); + + fft_asmb_sse(&ck, 8, &a[0], &a[32],&delta64[0], &delta64_3[0]); + + fft_8_sse(&a[64]); fft_4_sse(&a[72]); fft_4_sse(&a[76]); + /* fft_16(&a[64]); */ + fft_asmb_sse(&ck, 2, &a[64], &a[72], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[80]); fft_8_sse(&a[88]); + + /* fft_32(&a[64]); */ + fft_asmb_sse(&ck, 4, &a[64], &a[80],&delta32[0], &delta32_3[0]); + + fft_8_sse(&a[96]); fft_4_sse(&a[104]), fft_4_sse(&a[108]); + /* fft_16(&a[96]); */ + fft_asmb_sse(&ck, 2, &a[96], &a[104], &delta16[0], &delta16_3[0]); + + fft_8_sse(&a[112]), fft_8_sse(&a[120]); + /* fft_32(&a[96]); */ + fft_asmb_sse(&ck, 4, &a[96], &a[112], &delta32[0], &delta32_3[0]); + + /* fft_128(&a[0]); */ + fft_asmb_sse(&ck, 16, &a[0], &a[64], &delta128[0], &delta128_3[0]); +} + +static void fft_4_sse (complex_t *x) +{ + __asm__ __volatile__ ( + ".align 16\n" + "movaps (%%eax), %%xmm0\n" /* x[1] | x[0] */ + "movaps 16(%%eax), %%xmm2\n" /* x[3] | x[2] */ + "movaps %%xmm0, %%xmm1\n" /* x[1] | x[0] */ + "addps %%xmm2, %%xmm0\n" /* x[1] + x[3] | x[0] + x[2] */ + "subps %%xmm2, %%xmm1\n" /* x[1] - x[3] | x[0] - x[2] */ + "xorps %%xmm6, %%xmm6\n" + "movhlps %%xmm1, %%xmm4\n" /* ? | x[1] - x[3] */ + "movhlps %%xmm0, %%xmm3\n" /* ? | x[1] + x[3] */ + "subss %%xmm4, %%xmm6\n" /* 0 | -(x[1] - x[3]).re */ + "movlhps %%xmm1, %%xmm0\n" /* x[0] - x[2] | x[0] + x[2] */ + "movlhps %%xmm6, %%xmm4\n" /* 0 | -(x[1] - x[3]).re | (x[1] - x[3]).im | (x[3]-x[1]).re */ + "movaps %%xmm0, %%xmm2\n" /* x[0] - x[2] | x[0] + x[2] */ + "shufps $0x94, %%xmm4, %%xmm3\n" /* i*(x[1] - x[3]) | x[1] + x[3] */ + "addps %%xmm3, %%xmm0\n" + "subps %%xmm3, %%xmm2\n" + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm2, 16(%%eax)\n" + : "=a" (x) + : "a" (x) ); +} + +static void fft_8_sse (complex_t *x) +{ + __asm__ __volatile__ ( + ".align 16\n" + + "movlps (%%eax), %%xmm0\n" /* x[0] */ + "movlps 32(%%eax), %%xmm1\n" /* x[4] */ + "movhps 16(%%eax), %%xmm0\n" /* x[2] | x[0] */ + "movhps 48(%%eax), %%xmm1\n" /* x[6] | x[4] */ + "movaps %%xmm0, %%xmm2\n" /* x[2] | x[0] */ + "xorps %%xmm3, %%xmm3\n" + "addps %%xmm1, %%xmm0\n" /* x[2] + x[6] | x[0] + x[4] */ + "subps %%xmm1, %%xmm2\n" /* x[2] - x[6] | x[0] - x[4] */ + "movhlps %%xmm0, %%xmm5\n" /* x[2] + x[6] */ + "movhlps %%xmm2, %%xmm4\n" /* x[2] - x[6] */ + "movlhps %%xmm2, %%xmm0\n" /* x[0] - x[4] | x[0] + x[4] */ + "subss %%xmm4, %%xmm3\n" /* (x[2]-x[6]).im | -(x[2]-x[6]).re */ + "movaps %%xmm0, %%xmm7\n" /* x[0] - x[4] | x[0] + x[4] */ + "movaps %%xmm3, %%xmm4\n" /* (x[2]-x[6]).im | -(x[2]-x[6]).re */ + "movlps 8(%%eax), %%xmm1\n" /* x[1] */ + "shufps $0x14, %%xmm4, %%xmm5\n" /* i*(x[2] - x[6]) | x[2] + x[6] */ + + "addps %%xmm5, %%xmm0\n" /* yt = i*(x2-x6)+x0-x4 | x2+x6+x0+x4 */ + "subps %%xmm5, %%xmm7\n" /* yb = i*(x6-x2)+x0-x4 | -x6-x2+x0+x4 */ + + "movhps 24(%%eax), %%xmm1\n" /* x[3] | x[1] */ + "movlps 40(%%eax), %%xmm2\n" /* x[5] */ + "movhps 56(%%eax), %%xmm2\n" /* x[7] | x[5] */ + "movaps %%xmm1, %%xmm3\n" /* x[3] | x[1] */ + "addps %%xmm2, %%xmm1\n" /* x[3] + x[7] | x[1] + x[5] */ + "subps %%xmm2, %%xmm3\n" /* x[3] - x[7] | x[1] - x[5] */ + "movaps (%%ecx), %%xmm4\n" /* -1/sqrt2 | -1/sqrt2 | 1/sqrt2 | 1/sqrt2 */ + "movaps %%xmm3, %%xmm6\n" /* x[3] - x[7] | x[1] - x[5] */ + "mulps %%xmm4, %%xmm3\n" /* -1/s2*(x[3] - x[7]) | 1/s2*(x[1] - x[5]) */ + "shufps $0xc8, %%xmm4, %%xmm4\n" /* -1/sqrt2 | 1/sqrt2 | -1/sqrt2 | 1/sqrt2 */ + "shufps $0xb1, %%xmm6, %%xmm6\n" /* (x3-x7).re|(x3-x7).im|(x1-x5).re|(x1-x5).im */ + "mulps %%xmm4, %%xmm6\n" /* (x7-x3).re/s2|(x3-x7).im/s2|(x5-x1).re/s2|(x1-x5).im/s2 */ + "addps %%xmm3, %%xmm6\n" /* (-1-i)/sqrt2 * (x[3]-x[7]) | (1-i)/sqrt2 * (x[1] - x[5]) */ + "movhlps %%xmm1, %%xmm5\n" /* x[3] + x[7] */ + "movlhps %%xmm6, %%xmm1\n" /* (1+i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ + "shufps $0xe4, %%xmm6, %%xmm5\n" /* (-1-i)/sqrt2 * (x[3]-x[7]) | x[3]+x[7] */ + "movaps %%xmm1, %%xmm3\n" /* (1-i)/sqrt2 * (x[1]-x[5]) | x[1]+x[5] */ + "addps %%xmm5, %%xmm1\n" /* u */ + "subps %%xmm5, %%xmm3\n" /* v */ + "movaps %%xmm0, %%xmm2\n" /* yb */ + "movaps %%xmm7, %%xmm4\n" /* yt */ + "movaps (%%edx), %%xmm5\n" + "mulps %%xmm5, %%xmm3\n" + "addps %%xmm1, %%xmm0\n" /* yt + u */ + "subps %%xmm1, %%xmm2\n" /* yt - u */ + "shufps $0xb1, %%xmm3, %%xmm3\n" /* -i * v */ + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm2, 32(%%eax)\n" + "addps %%xmm3, %%xmm4\n" /* yb - i*v */ + "subps %%xmm3, %%xmm7\n" /* yb + i*v */ + "movaps %%xmm4, 16(%%eax)\n" + "movaps %%xmm7, 48(%%eax)\n" + + : "=a" (x) + : "a" (x), "c" (hsqrt2_sse), "d" (C_1_sse)); +} + +static void fft_asmb_sse (ck_sse_t * ck, int k, complex_t *x, complex_t *wTB, + const complex_t *d, const complex_t *d_3) +{ + ck->k = k; + + __asm__ __volatile__ ( + ".align 16\n" + "pushl %%ebp\n" + "movl %%esp, %%ebp\n" + + "subl $8, %%esp\n" + + "pushl %%eax\n" + "pushl %%ebx\n" + "pushl %%ecx\n" + "pushl %%edx\n" + "pushl %%esi\n" + "pushl %%edi\n" + + "movl 4(%%ecx), %%ebx\n" + "movl %%ebx, -4(%%ebp)\n" + "movl (%%ecx), %%ecx\n" + + "movl %%ecx, -8(%%ebp)\n" /* k */ + "addl $8, %%edx\n" + "addl $8, %%esi\n" + "shll $4, %%ecx\n" /* 16k */ + + /* TRANSZERO and TRANS */ + ".align 16\n" + "movaps (%%eax), %%xmm0\n" /* x[1] | x[0] */ + "movaps (%%edi), %%xmm1\n" /* wT[1] | wT[0] */ + "movaps (%%edi, %%ecx), %%xmm2\n" /* wB[1] | wB[0] */ + "movlps (%%edx), %%xmm3\n" /* d */ + "movlps (%%esi), %%xmm4\n" /* d3 */ + "movhlps %%xmm1, %%xmm5\n" /* wT[1] */ + "movhlps %%xmm2, %%xmm6\n" /* wB[1] */ + "shufps $0x50, %%xmm3, %%xmm3\n" /* d[1].im | d[1].im | d[1].re | d[1].re */ + "shufps $0x50, %%xmm4, %%xmm4\n" /* d3[1].im | d3[1].im | d3[i].re | d3[i].re */ + "movlhps %%xmm5, %%xmm5\n" /* wT[1] | wT[1] */ + "movlhps %%xmm6, %%xmm6\n" /* wB[1] | wB[1] */ + "mulps %%xmm3, %%xmm5\n" + "mulps %%xmm4, %%xmm6\n" + "movhlps %%xmm5, %%xmm7\n" /* wT[1].im * d[1].im | wT[1].re * d[1].im */ + "movlhps %%xmm6, %%xmm5\n" /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wT[1].im * d[1].re | wT[1].re * d[1].re */ + "shufps $0xb1, %%xmm6, %%xmm7\n" /* wB[1].re * d3[1].im | wB[i].im * d3[1].im | wT[1].re * d[1].im | wT[1].im * d[1].im */ + "movl -4(%%ebp), %%ebx\n" + "movaps (%%ebx), %%xmm4\n" + "mulps %%xmm4, %%xmm7\n" + "addps %%xmm7, %%xmm5\n" /* wB[1] * d3[1] | wT[1] * d[1] */ + "movlhps %%xmm5, %%xmm1\n" /* d[1] * wT[1] | wT[0] */ + "shufps $0xe4, %%xmm5, %%xmm2\n" /* d3[1] * wB[1] | wB[0] */ + "movaps %%xmm1, %%xmm3\n" /* d[1] * wT[1] | wT[0] */ + "leal (%%eax, %%ecx, 2), %%ebx\n" + "addps %%xmm2, %%xmm1\n" /* u */ + "subps %%xmm2, %%xmm3\n" /* v */ + "mulps %%xmm4, %%xmm3\n" + "movaps (%%eax, %%ecx), %%xmm5\n" /* xk[1] | xk[0] */ + "shufps $0xb1, %%xmm3, %%xmm3\n" /* -i * v */ + "movaps %%xmm0, %%xmm2\n" /* x[1] | x[0] */ + "movaps %%xmm5, %%xmm6\n" /* xk[1] | xk[0] */ + "addps %%xmm1, %%xmm0\n" + "subps %%xmm1, %%xmm2\n" + "addps %%xmm3, %%xmm5\n" + "subps %%xmm3, %%xmm6\n" + "movaps %%xmm0, (%%eax)\n" + "movaps %%xmm2, (%%ebx)\n" + "movaps %%xmm5, (%%eax, %%ecx)\n" + "movaps %%xmm6, (%%ebx, %%ecx)\n" + "addl $16, %%eax\n" + "addl $16, %%edi\n" + "addl $8, %%edx\n" + "addl $8, %%esi\n" + "decl -8(%%ebp)\n" + + ".align 16\n" +"0:\n" + "movaps (%%edi), %%xmm0\n" /* wT[1] | wT[0] */ + "movaps (%%edx), %%xmm1\n" /* d[1] | d[0] */ + + "movaps (%%edi, %%ecx), %%xmm4\n" /* wB[1] | wB[0] */ + "movaps (%%esi), %%xmm5\n" /* d3[1] | d3[0] */ + + "movhlps %%xmm0, %%xmm2\n" /* wT[1] */ + "movhlps %%xmm1, %%xmm3\n" /* d[1] */ + + "movhlps %%xmm4, %%xmm6\n" /* wB[1] */ + "movhlps %%xmm5, %%xmm7\n" /* d3[1] */ + + "shufps $0x50, %%xmm1, %%xmm1\n" /* d[0].im | d[0].im | d[0].re | d[0].re */ + "shufps $0x50, %%xmm3, %%xmm3\n" /* d[1].im | d[1].im | d[1].re | d[1].re */ + + "movlhps %%xmm0, %%xmm0\n" /* wT[0] | wT[0] */ + "shufps $0x50, %%xmm5, %%xmm5\n" /* d3[0].im | d3[0].im | d3[0].re | d3[0].re */ + "movlhps %%xmm2, %%xmm2\n" /* wT[1] | wT[1] */ + "shufps $0x50, %%xmm7, %%xmm7\n" /* d3[1].im | d3[1].im | d3[1].re | d3[1].re */ + + "mulps %%xmm1, %%xmm0\n" /* d[0].im * wT[0].im | d[0].im * wT[0].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ + "mulps %%xmm3, %%xmm2\n" /* d[1].im * wT[1].im | d[1].im * wT[1].re | d[1].re * wT[1].im | d[1].re * wT[1].re */ + "movlhps %%xmm4, %%xmm4\n" /* wB[0] | wB[0] */ + "movlhps %%xmm6, %%xmm6\n" /* wB[1] | wB[1] */ + + "movhlps %%xmm0, %%xmm1\n" /* d[0].im * wT[0].im | d[0].im * wT[0].re */ + "movlhps %%xmm2, %%xmm0\n" /* d[1].re * wT[1].im | d[1].re * wT[1].re | d[0].re * wT[0].im | d[0].re * wT[0].re */ + "mulps %%xmm5, %%xmm4\n" /* wB[0].im * d3[0].im | wB[0].re * d3[0].im | wB[0].im * d3[0].re | wB[0].re * d3[0].re */ + "mulps %%xmm7, %%xmm6\n" /* wB[1].im * d3[1].im | wB[1].re * d3[1].im | wB[1].im * d3[1].re | wB[1].re * d3[1].re */ + "shufps $0xb1, %%xmm2, %%xmm1\n" /* d[1].im * wT[1].re | d[1].im * wT[1].im | d[0].im * wT[0].re | d[0].im * wT[0].im */ + "movl -4(%%ebp), %%ebx\n" + "movaps (%%ebx), %%xmm3\n" /* 1.0 | -1.0 | 1.0 | -1.0 */ + + "movhlps %%xmm4, %%xmm5\n" /* wB[0].im * d3[0].im | wB[0].re * d3[0].im */ + "mulps %%xmm3, %%xmm1\n" /* d[1].im * wT[1].re | -d[1].im * wT[1].im | d[0].im * wT[0].re | -d[0].im * wT[0].im */ + "movlhps %%xmm6, %%xmm4\n" /* wB[1].im * d3[1].re | wB[1].re * d3[1].re | wB[0].im * d3[0].re | wB[0].im * d3[0].re */ + "addps %%xmm1, %%xmm0\n" /* wT[1] * d[1] | wT[0] * d[0] */ + + "shufps $0xb1, %%xmm6, %%xmm5\n" /* wB[1].re * d3[1].im | wB[1].im * d3[1].im | wB[0].re * d3[0].im | wB[0].im * d3[0].im */ + "mulps %%xmm3, %%xmm5\n" /* wB[1].re * d3[1].im | -wB[1].im * d3[1].im | wB[0].re * d3[0].im | -wB[0].im * d3[0].im */ + "addps %%xmm5, %%xmm4\n" /* wB[1] * d3[1] | wB[0] * d3[0] */ + + "movaps %%xmm0, %%xmm1\n" /* wT[1] * d[1] | wT[0] * d[0] */ + "addps %%xmm4, %%xmm0\n" /* u */ + "subps %%xmm4, %%xmm1\n" /* v */ + "movaps (%%eax), %%xmm6\n" /* x[1] | x[0] */ + "leal (%%eax, %%ecx, 2), %%ebx\n" + "mulps %%xmm3, %%xmm1\n" + "addl $16, %%edi\n" + "addl $16, %%esi\n" + "shufps $0xb1, %%xmm1, %%xmm1\n" /* -i * v */ + "movaps (%%eax, %%ecx), %%xmm7\n" /* xk[1] | xk[0] */ + "movaps %%xmm6, %%xmm2\n" + "movaps %%xmm7, %%xmm4\n" + "addps %%xmm0, %%xmm6\n" + "subps %%xmm0, %%xmm2\n" + "movaps %%xmm6, (%%eax)\n" + "movaps %%xmm2, (%%ebx)\n" + "addps %%xmm1, %%xmm7\n" + "subps %%xmm1, %%xmm4\n" + "addl $16, %%edx\n" + "movaps %%xmm7, (%%eax, %%ecx)\n" + "movaps %%xmm4, (%%ebx, %%ecx)\n" + + "addl $16, %%eax\n" + "decl -8(%%ebp)\n" + "jnz 0b\n" + + ".align 16\n" +"1:\n" + "popl %%edi\n" + "popl %%esi\n" + "popl %%edx\n" + "popl %%ecx\n" + "popl %%ebx\n" + "popl %%eax\n" + + "addl $8, %%esp\n" + + "leave\n" + : "=a" (x), "=D" (wTB) + : "c" (ck), "a" (x), "D" (wTB), "d" (d), "S" (d_3) ); +} diff --git a/modules/codec/a52old/internal.h b/modules/codec/a52old/internal.h new file mode 100644 index 0000000000..b3086bbe8f --- /dev/null +++ b/modules/codec/a52old/internal.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * internals.h: needed by the A52 decoder + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * $Id: internal.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Lespinasse + * + * 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. + *****************************************************************************/ + +/* Exponent strategy constants */ +#define EXP_REUSE (0) +#define EXP_D15 (1) +#define EXP_D25 (2) +#define EXP_D45 (3) + +/* Delta bit allocation constants */ +#define DELTA_BIT_REUSE (0) +#define DELTA_BIT_NEW (1) +#define DELTA_BIT_NONE (2) +#define DELTA_BIT_RESERVED (3) + +/* bit_allocate.c */ +void bit_allocate (a52dec_t *); + +/* exponent.c */ +int exponent_unpack (a52dec_t *); + +/* imdct.c */ +void E_( imdct_init )(imdct_t * p_imdct); +void imdct (a52dec_t * p_a52dec, s16 * buffer); + +/* mantissa.c */ +void mantissa_unpack (a52dec_t *); + +/* parse.c */ +int parse_bsi (a52dec_t *); +int parse_audblk (a52dec_t *, int); +void parse_auxdata (a52dec_t *); + +/* rematrix.c */ +void rematrix (a52dec_t *); + diff --git a/modules/codec/a52old/mantissa.c b/modules/codec/a52old/mantissa.c new file mode 100644 index 0000000000..713d7a82a8 --- /dev/null +++ b/modules/codec/a52old/mantissa.c @@ -0,0 +1,81 @@ +/***************************************************************************** + * mantissa.c: A52 mantissa computation + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: mantissa.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Aaron Holtzman + * Renaud Dartus + * + * 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 /* memcpy() */ + +#include +#include + +#include "imdct.h" +#include "downmix.h" +#include "adec.h" + +#include "mantissa.h" + +void mantissa_unpack (a52dec_t * p_a52dec) +{ + int i, j; + u32 done_cpl = 0; + + p_a52dec->mantissa.q_1_pointer = -1; + p_a52dec->mantissa.q_2_pointer = -1; + p_a52dec->mantissa.q_4_pointer = -1; + + for (i=0; i< p_a52dec->bsi.nfchans; i++) { + for (j=0; j < p_a52dec->audblk.endmant[i]; j++) + *(p_a52dec->samples+i*256+j) = coeff_get_float(p_a52dec, p_a52dec->audblk.fbw_bap[i][j], + p_a52dec->audblk.dithflag[i], p_a52dec->audblk.fbw_exp[i][j]); + + if (p_a52dec->audblk.cplinu && p_a52dec->audblk.chincpl[i] && !(done_cpl)) { + /* ncplmant is equal to 12 * ncplsubnd + * Don't dither coupling channel until channel + * separation so that interchannel noise is uncorrelated + */ + for (j=p_a52dec->audblk.cplstrtmant; j < p_a52dec->audblk.cplendmant; j++) + p_a52dec->audblk.cpl_flt[j] = coeff_get_float(p_a52dec, p_a52dec->audblk.cpl_bap[j], + 0, p_a52dec->audblk.cpl_exp[j]); + done_cpl = 1; + } + } + + /* uncouple the channel if necessary */ + if (p_a52dec->audblk.cplinu) { + for (i=0; i< p_a52dec->bsi.nfchans; i++) { + if (p_a52dec->audblk.chincpl[i]) + uncouple_channel(p_a52dec, i); + } + } + + if (p_a52dec->bsi.lfeon) { + /* There are always 7 mantissas for lfe, no dither for lfe */ + for (j=0; j < 7 ; j++) + *(p_a52dec->samples+5*256+j) = coeff_get_float(p_a52dec, p_a52dec->audblk.lfe_bap[j], + 0, p_a52dec->audblk.lfe_exp[j]); + } +} + diff --git a/modules/codec/a52old/mantissa.h b/modules/codec/a52old/mantissa.h new file mode 100644 index 0000000000..7018a7d524 --- /dev/null +++ b/modules/codec/a52old/mantissa.h @@ -0,0 +1,404 @@ +/***************************************************************************** + * mantissa.h: A52 mantissa computation + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: mantissa.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Aaron Holtzman + * Renaud Dartus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define Q0 ((-2 << 15) / 3.0) +#define Q1 (0) +#define Q2 ((2 << 15) / 3.0) +static const float q_1_0[ 32 ] = +{ + Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, + Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, + Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, + 0, 0, 0, 0, 0 +}; +static const float q_1_1[ 32 ] = +{ + Q0, Q0, Q0, Q1, Q1, Q1, Q2, Q2, Q2, + Q0, Q0, Q0, Q1, Q1, Q1, Q2, Q2, Q2, + Q0, Q0, Q0, Q1, Q1, Q1, Q2, Q2, Q2, + 0, 0, 0, 0, 0 +}; +static const float q_1_2[ 32 ] = +{ + Q0, Q1, Q2, Q0, Q1, Q2, Q0, Q1, Q2, + Q0, Q1, Q2, Q0, Q1, Q2, Q0, Q1, Q2, + Q0, Q1, Q2, Q0, Q1, Q2, Q0, Q1, Q2, + 0, 0, 0, 0, 0 +}; +#undef Q0 +#undef Q1 +#undef Q2 + +#define Q0 ((-4 << 15) / 5.0) +#define Q1 ((-2 << 15) / 5.0) +#define Q2 (0) +#define Q3 ((2 << 15) / 5.0) +#define Q4 ((4 << 15) / 5.0) +static const float q_2_0[ 128 ] = +{ + Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0, + Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1, + Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2, + Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3,Q3, + Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4,Q4, + 0, 0, 0 +}; +static const float q_2_1[ 128 ] = +{ + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4, + 0, 0, 0 +}; +static const float q_2_2[ 128 ] = +{ + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4, + 0, 0, 0 +}; +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 + +#define Q0 ((-10 << 15) / 11.0) +#define Q1 ((-8 << 15) / 11.0) +#define Q2 ((-6 << 15) / 11.0) +#define Q3 ((-4 << 15) / 11.0) +#define Q4 ((-2 << 15) / 11.0) +#define Q5 (0) +#define Q6 ((2 << 15) / 11.0) +#define Q7 ((4 << 15) / 11.0) +#define Q8 ((6 << 15) / 11.0) +#define Q9 ((8 << 15) / 11.0) +#define QA ((10 << 15) / 11.0) +static const float q_4_0[ 128 ] = +{ + Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, + Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, + Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, + Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, Q3, + Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, Q4, + Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, Q5, + Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, Q6, + Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, Q7, + Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, Q8, + Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, Q9, + QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, QA, + 0, 0, 0, 0, 0, 0, 0 +}; +static const float q_4_1[ 128 ] = +{ + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA, + 0, 0, 0, 0, 0, 0, 0 +}; +#undef Q0 +#undef Q1 +#undef Q2 +#undef Q3 +#undef Q4 +#undef Q5 +#undef Q6 +#undef Q7 +#undef Q8 +#undef Q9 +#undef QA + +/* Lookup tables of 0.16 two's complement quantization values */ + +static const float q_3[8] = +{ + (-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, + 0 , (2 << 15)/7.0, (4 << 15)/7.0, + (6 << 15)/7.0, 0 +}; + +static const float q_5[16] = +{ + (-14 << 15)/15.0, (-12 << 15)/15.0, (-10 << 15)/15.0, + (-8 << 15)/15.0, (-6 << 15)/15.0, (-4 << 15)/15.0, + (-2 << 15)/15.0, 0 , (2 << 15)/15.0, + (4 << 15)/15.0, (6 << 15)/15.0, (8 << 15)/15.0, + (10 << 15)/15.0, (12 << 15)/15.0, (14 << 15)/15.0, + 0 +}; + +/* Conversion from bap to number of bits in the mantissas + * zeros account for cases 0,1,2,4 which are special cased */ +static const u16 qnttztab[16] = +{ + 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 +}; + +static const float scale_factor[25] = +{ + 6.10351562500000000000000000e-05, + 3.05175781250000000000000000e-05, + 1.52587890625000000000000000e-05, + 7.62939453125000000000000000e-06, + 3.81469726562500000000000000e-06, + 1.90734863281250000000000000e-06, + 9.53674316406250000000000000e-07, + 4.76837158203125000000000000e-07, + 2.38418579101562500000000000e-07, + 1.19209289550781250000000000e-07, + 5.96046447753906250000000000e-08, + 2.98023223876953125000000000e-08, + 1.49011611938476562500000000e-08, + 7.45058059692382812500000000e-09, + 3.72529029846191406250000000e-09, + 1.86264514923095703125000000e-09, + 9.31322574615478515625000000e-10, + 4.65661287307739257812500000e-10, + 2.32830643653869628906250000e-10, + 1.16415321826934814453125000e-10, + 5.82076609134674072265625000e-11, + 2.91038304567337036132812500e-11, + 1.45519152283668518066406250e-11, + 7.27595761418342590332031250e-12, + 3.63797880709171295166015625e-12, +}; + +static const u16 dither_lut[256] = +{ + 0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055, + 0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb, + 0x21cd, 0x81dc, 0xc1fe, 0x61ef, 0x41ba, 0xe1ab, 0xa189, 0x0198, + 0xe123, 0x4132, 0x0110, 0xa101, 0x8154, 0x2145, 0x6167, 0xc176, + 0x439a, 0xe38b, 0xa3a9, 0x03b8, 0x23ed, 0x83fc, 0xc3de, 0x63cf, + 0x8374, 0x2365, 0x6347, 0xc356, 0xe303, 0x4312, 0x0330, 0xa321, + 0x6257, 0xc246, 0x8264, 0x2275, 0x0220, 0xa231, 0xe213, 0x4202, + 0xa2b9, 0x02a8, 0x428a, 0xe29b, 0xc2ce, 0x62df, 0x22fd, 0x82ec, + 0x8734, 0x2725, 0x6707, 0xc716, 0xe743, 0x4752, 0x0770, 0xa761, + 0x47da, 0xe7cb, 0xa7e9, 0x07f8, 0x27ad, 0x87bc, 0xc79e, 0x678f, + 0xa6f9, 0x06e8, 0x46ca, 0xe6db, 0xc68e, 0x669f, 0x26bd, 0x86ac, + 0x6617, 0xc606, 0x8624, 0x2635, 0x0660, 0xa671, 0xe653, 0x4642, + 0xc4ae, 0x64bf, 0x249d, 0x848c, 0xa4d9, 0x04c8, 0x44ea, 0xe4fb, + 0x0440, 0xa451, 0xe473, 0x4462, 0x6437, 0xc426, 0x8404, 0x2415, + 0xe563, 0x4572, 0x0550, 0xa541, 0x8514, 0x2505, 0x6527, 0xc536, + 0x258d, 0x859c, 0xc5be, 0x65af, 0x45fa, 0xe5eb, 0xa5c9, 0x05d8, + 0xae79, 0x0e68, 0x4e4a, 0xee5b, 0xce0e, 0x6e1f, 0x2e3d, 0x8e2c, + 0x6e97, 0xce86, 0x8ea4, 0x2eb5, 0x0ee0, 0xaef1, 0xeed3, 0x4ec2, + 0x8fb4, 0x2fa5, 0x6f87, 0xcf96, 0xefc3, 0x4fd2, 0x0ff0, 0xafe1, + 0x4f5a, 0xef4b, 0xaf69, 0x0f78, 0x2f2d, 0x8f3c, 0xcf1e, 0x6f0f, + 0xede3, 0x4df2, 0x0dd0, 0xadc1, 0x8d94, 0x2d85, 0x6da7, 0xcdb6, + 0x2d0d, 0x8d1c, 0xcd3e, 0x6d2f, 0x4d7a, 0xed6b, 0xad49, 0x0d58, + 0xcc2e, 0x6c3f, 0x2c1d, 0x8c0c, 0xac59, 0x0c48, 0x4c6a, 0xec7b, + 0x0cc0, 0xacd1, 0xecf3, 0x4ce2, 0x6cb7, 0xcca6, 0x8c84, 0x2c95, + 0x294d, 0x895c, 0xc97e, 0x696f, 0x493a, 0xe92b, 0xa909, 0x0918, + 0xe9a3, 0x49b2, 0x0990, 0xa981, 0x89d4, 0x29c5, 0x69e7, 0xc9f6, + 0x0880, 0xa891, 0xe8b3, 0x48a2, 0x68f7, 0xc8e6, 0x88c4, 0x28d5, + 0xc86e, 0x687f, 0x285d, 0x884c, 0xa819, 0x0808, 0x482a, 0xe83b, + 0x6ad7, 0xcac6, 0x8ae4, 0x2af5, 0x0aa0, 0xaab1, 0xea93, 0x4a82, + 0xaa39, 0x0a28, 0x4a0a, 0xea1b, 0xca4e, 0x6a5f, 0x2a7d, 0x8a6c, + 0x4b1a, 0xeb0b, 0xab29, 0x0b38, 0x2b6d, 0x8b7c, 0xcb5e, 0x6b4f, + 0x8bf4, 0x2be5, 0x6bc7, 0xcbd6, 0xeb83, 0x4b92, 0x0bb0, 0xaba1 +}; + +static inline u16 dither_gen (mantissa_t * p_mantissa) +{ + s16 state; + + state = dither_lut[p_mantissa->lfsr_state >> 8] ^ + (p_mantissa->lfsr_state << 8); + p_mantissa->lfsr_state = (u16) state; + return ( (state * (s32) (0.707106 * 256.0)) >> 8 ); +} + + +/* Fetch an unpacked, left justified, and properly biased/dithered mantissa value */ +static inline float coeff_get_float( a52dec_t * p_a52dec, u16 bap, u16 dithflag, + u16 exp ) +{ + u16 group_code = 0; + + /* If the bap is 0-5 then we have special cases to take care of */ + switch (bap) + { + case 0: + if (dithflag) + { + return ( dither_gen(&p_a52dec->mantissa) * scale_factor[exp] ); + } + return (0); + + case 1: + if (p_a52dec->mantissa.q_1_pointer >= 0) + { + return (p_a52dec->mantissa.q_1[p_a52dec->mantissa.q_1_pointer--] * + scale_factor[exp]); + } + + p_a52dec->total_bits_read += 5; + if ((group_code = GetBits (&p_a52dec->bit_stream,5)) > 26) + { + msg_Warn( p_a52dec->p_fifo, "invalid mantissa (1)" ); + return 0; + } + + p_a52dec->mantissa.q_1[ 1 ] = q_1_1[ group_code ]; + p_a52dec->mantissa.q_1[ 0 ] = q_1_2[ group_code ]; + + p_a52dec->mantissa.q_1_pointer = 1; + + return (q_1_0[group_code] * scale_factor[exp]); + + case 2: + if (p_a52dec->mantissa.q_2_pointer >= 0) + { + return (p_a52dec->mantissa.q_2[p_a52dec->mantissa.q_2_pointer--] * + scale_factor[exp]); + } + + p_a52dec->total_bits_read += 7; + if ((group_code = GetBits (&p_a52dec->bit_stream,7)) > 124) + { + msg_Warn( p_a52dec->p_fifo, "invalid mantissa (2)" ); + return 0; + } + + p_a52dec->mantissa.q_2[ 1 ] = q_2_1[ group_code ]; + p_a52dec->mantissa.q_2[ 0 ] = q_2_2[ group_code ]; + + p_a52dec->mantissa.q_2_pointer = 1; + + return (q_2_0[group_code] * scale_factor[exp]); + + case 3: + p_a52dec->total_bits_read += 3; + if ((group_code = GetBits (&p_a52dec->bit_stream,3)) > 6) + { + msg_Warn( p_a52dec->p_fifo, "invalid mantissa (3)" ); + return 0; + } + + return (q_3[group_code] * scale_factor[exp]); + + case 4: + if (p_a52dec->mantissa.q_4_pointer >= 0) + { + return (p_a52dec->mantissa.q_4[p_a52dec->mantissa.q_4_pointer--] * + scale_factor[exp]); + } + + p_a52dec->total_bits_read += 7; + if ((group_code = GetBits (&p_a52dec->bit_stream,7)) > 120) + { + msg_Warn( p_a52dec->p_fifo, "invalid mantissa (4)" ); + return 0; + } + + p_a52dec->mantissa.q_4[ 0 ] = q_4_1[group_code]; + + p_a52dec->mantissa.q_4_pointer = 0; + + return (q_4_0[group_code] * scale_factor[exp]); + + case 5: + p_a52dec->total_bits_read += 4; + if ((group_code = GetBits (&p_a52dec->bit_stream,4)) > 14) + { + msg_Warn( p_a52dec->p_fifo, "invalid mantissa (5)" ); + return 0; + } + + return (q_5[group_code] * scale_factor[exp]); + + default: + group_code = GetBits (&p_a52dec->bit_stream,qnttztab[bap]); + group_code <<= 16 - qnttztab[bap]; + p_a52dec->total_bits_read += qnttztab[bap]; + + return ((s16)(group_code) * scale_factor[exp]); + } +} + +/* Uncouple the coupling channel into a fbw channel */ +static inline void uncouple_channel (a52dec_t * p_a52dec, u32 ch) +{ + u32 bnd = 0; + u32 sub_bnd = 0; + u32 i,j; + float cpl_coord = 1.0; + u32 cpl_exp_tmp; + u32 cpl_mant_tmp; + + for (i = p_a52dec->audblk.cplstrtmant; i < p_a52dec->audblk.cplendmant;) + { + if (!p_a52dec->audblk.cplbndstrc[sub_bnd++]) + { + cpl_exp_tmp = p_a52dec->audblk.cplcoexp[ch][bnd] + + 3 * p_a52dec->audblk.mstrcplco[ch]; + if (p_a52dec->audblk.cplcoexp[ch][bnd] == 15) + { + cpl_mant_tmp = (p_a52dec->audblk.cplcomant[ch][bnd]) << 11; + } + else + { + cpl_mant_tmp = ((0x10) | p_a52dec->audblk.cplcomant[ch][bnd]) << 10; + } + cpl_coord = (cpl_mant_tmp) * scale_factor[cpl_exp_tmp] * 8.0f; + + /* Invert the phase for the right channel if necessary */ + if (p_a52dec->bsi.acmod == 0x02 && p_a52dec->audblk.phsflginu && + ch == 1 && p_a52dec->audblk.phsflg[bnd]) + { + cpl_coord *= -1; + } + bnd++; + } + + for (j=0;j < 12; j++) + { + /* Get new dither values for each channel if necessary, + * so the channels are uncorrelated */ + if (p_a52dec->audblk.dithflag[ch] && !p_a52dec->audblk.cpl_bap[i]) + { + *(p_a52dec->samples+ch*256+i) = cpl_coord * dither_gen(&p_a52dec->mantissa) * + scale_factor[p_a52dec->audblk.cpl_exp[i]]; + } else { + *(p_a52dec->samples+ch*256+i) = cpl_coord * p_a52dec->audblk.cpl_flt[i]; + } + i++; + } + } +} + diff --git a/modules/codec/a52old/parse.c b/modules/codec/a52old/parse.c new file mode 100644 index 0000000000..7d8919f06a --- /dev/null +++ b/modules/codec/a52old/parse.c @@ -0,0 +1,862 @@ +/***************************************************************************** + * parse.c: A52 parsing procedures + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: parse.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Aaron Holtzman + * Renaud Dartus + * + * 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 /* memset() */ + +#include +#include + +#include "imdct.h" +#include "downmix.h" +#include "adec.h" + +#include "internal.h" /* EXP_REUSE */ + +/* Misc LUT */ +static const u16 nfchans[] = { 2, 1, 2, 3, 3, 4, 4, 5 }; + +struct frmsize_s +{ + u16 bit_rate; + u16 frm_size[3]; +}; + +static const struct frmsize_s frmsizecod_tbl[] = +{ + { 32 ,{64 ,69 ,96 } }, + { 32 ,{64 ,70 ,96 } }, + { 40 ,{80 ,87 ,120 } }, + { 40 ,{80 ,88 ,120 } }, + { 48 ,{96 ,104 ,144 } }, + { 48 ,{96 ,105 ,144 } }, + { 56 ,{112 ,121 ,168 } }, + { 56 ,{112 ,122 ,168 } }, + { 64 ,{128 ,139 ,192 } }, + { 64 ,{128 ,140 ,192 } }, + { 80 ,{160 ,174 ,240 } }, + { 80 ,{160 ,175 ,240 } }, + { 96 ,{192 ,208 ,288 } }, + { 96 ,{192 ,209 ,288 } }, + { 112 ,{224 ,243 ,336 } }, + { 112 ,{224 ,244 ,336 } }, + { 128 ,{256 ,278 ,384 } }, + { 128 ,{256 ,279 ,384 } }, + { 160 ,{320 ,348 ,480 } }, + { 160 ,{320 ,349 ,480 } }, + { 192 ,{384 ,417 ,576 } }, + { 192 ,{384 ,418 ,576 } }, + { 224 ,{448 ,487 ,672 } }, + { 224 ,{448 ,488 ,672 } }, + { 256 ,{512 ,557 ,768 } }, + { 256 ,{512 ,558 ,768 } }, + { 320 ,{640 ,696 ,960 } }, + { 320 ,{640 ,697 ,960 } }, + { 384 ,{768 ,835 ,1152 } }, + { 384 ,{768 ,836 ,1152 } }, + { 448 ,{896 ,975 ,1344 } }, + { 448 ,{896 ,976 ,1344 } }, + { 512 ,{1024 ,1114 ,1536 } }, + { 512 ,{1024 ,1115 ,1536 } }, + { 576 ,{1152 ,1253 ,1728 } }, + { 576 ,{1152 ,1254 ,1728 } }, + { 640 ,{1280 ,1393 ,1920 } }, + { 640 ,{1280 ,1394 ,1920 } }}; + +static const int fscod_tbl[] = {48000, 44100, 32000}; + +/* Some internal functions */ +static void parse_bsi_stats (a52dec_t * p_a52dec); +static void parse_audblk_stats (a52dec_t * p_a52dec); + +/* Parse a syncinfo structure */ +int sync_frame (a52dec_t * p_a52dec, sync_info_t * p_sync_info) +{ + p_a52dec->total_bits_read = 0; + p_a52dec->i_available = 0; + + /* sync word - should be 0x0b77 */ + RealignBits(&p_a52dec->bit_stream); + while( (ShowBits (&p_a52dec->bit_stream,16)) != 0x0b77 && + (!p_a52dec->p_fifo->b_die) && (!p_a52dec->p_fifo->b_error)) + { + RemoveBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + RemoveBits (&p_a52dec->bit_stream,16); + p_a52dec->total_bits_read += 16; + + + /* Get crc1 - we don't actually use this data though */ + GetBits (&p_a52dec->bit_stream,16); + + /* Get the sampling rate */ + p_a52dec->syncinfo.fscod = GetBits (&p_a52dec->bit_stream,2); + + if (p_a52dec->syncinfo.fscod >= 3) + { + p_a52dec->total_bits_read += 34; + return 1; + } + + /* Get the frame size code */ + p_a52dec->syncinfo.frmsizecod = GetBits (&p_a52dec->bit_stream,6); + p_a52dec->total_bits_read += 40; + + if (p_a52dec->syncinfo.frmsizecod >= 38) + { + return 1; + } + + p_sync_info->bit_rate = frmsizecod_tbl[p_a52dec->syncinfo.frmsizecod].bit_rate; + + p_a52dec->syncinfo.frame_size = frmsizecod_tbl[p_a52dec->syncinfo.frmsizecod].frm_size[p_a52dec->syncinfo.fscod]; + p_sync_info->frame_size = 2 * p_a52dec->syncinfo.frame_size; + + p_sync_info->sample_rate = fscod_tbl[p_a52dec->syncinfo.fscod]; + + return 0; +} + +/* + * This routine fills a bsi struct from the A52 stream + */ +int parse_bsi (a52dec_t * p_a52dec) +{ + /* Check the AC-3 version number */ + p_a52dec->bsi.bsid = GetBits (&p_a52dec->bit_stream,5); + + if (p_a52dec->bsi.bsid > 8) + { + return 1; + } + + /* Get the audio service provided by the stream */ + p_a52dec->bsi.bsmod = GetBits (&p_a52dec->bit_stream,3); + + /* Get the audio coding mode (ie how many channels)*/ + p_a52dec->bsi.acmod = GetBits (&p_a52dec->bit_stream,3); + + /* Predecode the number of full bandwidth channels as we use this + * number a lot */ + p_a52dec->bsi.nfchans = nfchans[p_a52dec->bsi.acmod]; + + /* If it is in use, get the centre channel mix level */ + if ((p_a52dec->bsi.acmod & 0x1) && (p_a52dec->bsi.acmod != 0x1)) + { + p_a52dec->bsi.cmixlev = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + } + + /* If it is in use, get the surround channel mix level */ + if (p_a52dec->bsi.acmod & 0x4) + { + p_a52dec->bsi.surmixlev = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + } + + /* Get the dolby surround mode if in 2/0 mode */ + if (p_a52dec->bsi.acmod == 0x2) + { + p_a52dec->bsi.dsurmod = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + } + + /* Is the low frequency effects channel on? */ + p_a52dec->bsi.lfeon = GetBits (&p_a52dec->bit_stream,1); + + /* Get the dialogue normalization level */ + p_a52dec->bsi.dialnorm = GetBits (&p_a52dec->bit_stream,5); + + /* Does compression gain exist? */ + if ((p_a52dec->bsi.compre = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get compression gain */ + p_a52dec->bsi.compr = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + + /* Does language code exist? */ + if ((p_a52dec->bsi.langcode = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get langauge code */ + p_a52dec->bsi.langcod = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + + /* Does audio production info exist? */ + if ((p_a52dec->bsi.audprodie = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get mix level */ + p_a52dec->bsi.mixlevel = GetBits (&p_a52dec->bit_stream,5); + + /* Get room type */ + p_a52dec->bsi.roomtyp = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 7; + } + + /* If we're in dual mono mode then get some extra info */ + if (p_a52dec->bsi.acmod == 0) + { + /* Get the dialogue normalization level two */ + p_a52dec->bsi.dialnorm2 = GetBits (&p_a52dec->bit_stream,5); + + /* Does compression gain two exist? */ + if ((p_a52dec->bsi.compr2e = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get compression gain two */ + p_a52dec->bsi.compr2 = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + + /* Does language code two exist? */ + if ((p_a52dec->bsi.langcod2e = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get langauge code two */ + p_a52dec->bsi.langcod2 = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + + /* Does audio production info two exist? */ + if ((p_a52dec->bsi.audprodi2e = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get mix level two */ + p_a52dec->bsi.mixlevel2 = GetBits (&p_a52dec->bit_stream,5); + + /* Get room type two */ + p_a52dec->bsi.roomtyp2 = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 7; + } + p_a52dec->total_bits_read += 8; + } + + /* Get the copyright bit */ + p_a52dec->bsi.copyrightb = GetBits (&p_a52dec->bit_stream,1); + + /* Get the original bit */ + p_a52dec->bsi.origbs = GetBits (&p_a52dec->bit_stream,1); + + /* Does timecode one exist? */ + if ((p_a52dec->bsi.timecod1e = GetBits (&p_a52dec->bit_stream,1))) + { + p_a52dec->bsi.timecod1 = GetBits (&p_a52dec->bit_stream,14); + p_a52dec->total_bits_read += 14; + } + + /* Does timecode two exist? */ + if ((p_a52dec->bsi.timecod2e = GetBits (&p_a52dec->bit_stream,1))) + { + p_a52dec->bsi.timecod2 = GetBits (&p_a52dec->bit_stream,14); + p_a52dec->total_bits_read += 14; + } + + /* Does addition info exist? */ + if ((p_a52dec->bsi.addbsie = GetBits (&p_a52dec->bit_stream,1))) + { + u32 i; + + /* Get how much info is there */ + p_a52dec->bsi.addbsil = GetBits (&p_a52dec->bit_stream,6); + + /* Get the additional info */ + for (i=0;i<(p_a52dec->bsi.addbsil + 1);i++) + { + p_a52dec->bsi.addbsi[i] = GetBits (&p_a52dec->bit_stream,8); + } + p_a52dec->total_bits_read += 6 + 8 * (p_a52dec->bsi.addbsil + 1); + } + p_a52dec->total_bits_read += 25; + + parse_bsi_stats (p_a52dec); + + return 0; +} + +/* More pain inducing parsing */ +int parse_audblk (a52dec_t * p_a52dec, int blknum) +{ + int i, j; + + for (i=0; i < p_a52dec->bsi.nfchans; i++) + { + /* Is this channel an interleaved 256 + 256 block ? */ + p_a52dec->audblk.blksw[i] = GetBits (&p_a52dec->bit_stream,1); + } + + for (i=0; i < p_a52dec->bsi.nfchans; i++) + { + /* Should we dither this channel? */ + p_a52dec->audblk.dithflag[i] = GetBits (&p_a52dec->bit_stream,1); + } + + /* Does dynamic range control exist? */ + if ((p_a52dec->audblk.dynrnge = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get dynamic range info */ + p_a52dec->audblk.dynrng = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + + /* If we're in dual mono mode then get the second channel DR info */ + if (p_a52dec->bsi.acmod == 0) + { + /* Does dynamic range control two exist? */ + if ((p_a52dec->audblk.dynrng2e = GetBits (&p_a52dec->bit_stream,1))) + { + /* Get dynamic range info */ + p_a52dec->audblk.dynrng2 = GetBits (&p_a52dec->bit_stream,8); + p_a52dec->total_bits_read += 8; + } + p_a52dec->total_bits_read += 1; + } + + /* Does coupling strategy exist? */ + p_a52dec->audblk.cplstre = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 2 + 2 * p_a52dec->bsi.nfchans; + + if ((!blknum) && (!p_a52dec->audblk.cplstre)) + { + return 1; + } + + if (p_a52dec->audblk.cplstre) + { + /* Is coupling turned on? */ + if ((p_a52dec->audblk.cplinu = GetBits (&p_a52dec->bit_stream,1))) + { + int nb_coupled_channels; + + nb_coupled_channels = 0; + for (i=0; i < p_a52dec->bsi.nfchans; i++) + { + p_a52dec->audblk.chincpl[i] = GetBits (&p_a52dec->bit_stream,1); + if (p_a52dec->audblk.chincpl[i]) + { + nb_coupled_channels++; + } + } + p_a52dec->total_bits_read += p_a52dec->bsi.nfchans; + + if (nb_coupled_channels < 2) + { + return 1; + } + + if (p_a52dec->bsi.acmod == 0x2) + { + p_a52dec->audblk.phsflginu = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + } + p_a52dec->audblk.cplbegf = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.cplendf = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->total_bits_read += 8; + + if (p_a52dec->audblk.cplbegf > p_a52dec->audblk.cplendf + 2) + { + return 1; + } + + p_a52dec->audblk.ncplsubnd = (p_a52dec->audblk.cplendf + 2) - p_a52dec->audblk.cplbegf + 1; + + /* Calculate the start and end bins of the coupling channel */ + p_a52dec->audblk.cplstrtmant = (p_a52dec->audblk.cplbegf * 12) + 37 ; + p_a52dec->audblk.cplendmant = ((p_a52dec->audblk.cplendf + 3) * 12) + 37; + + /* The number of combined subbands is ncplsubnd minus each combined + * band */ + p_a52dec->audblk.ncplbnd = p_a52dec->audblk.ncplsubnd; + + for (i=1; i< p_a52dec->audblk.ncplsubnd; i++) + { + p_a52dec->audblk.cplbndstrc[i] = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->audblk.ncplbnd -= p_a52dec->audblk.cplbndstrc[i]; + } + p_a52dec->total_bits_read += p_a52dec->audblk.ncplsubnd - 1; + } + p_a52dec->total_bits_read += 1; + } + + if (p_a52dec->audblk.cplinu) + { + /* Loop through all the channels and get their coupling co-ords */ + for (i=0; i < p_a52dec->bsi.nfchans;i++) + { + if (!p_a52dec->audblk.chincpl[i]) + { + continue; + } + + /* Is there new coupling co-ordinate info? */ + p_a52dec->audblk.cplcoe[i] = GetBits (&p_a52dec->bit_stream,1); + + if ((!blknum) && (!p_a52dec->audblk.cplcoe[i])) + { + return 1; + } + + if (p_a52dec->audblk.cplcoe[i]) + { + p_a52dec->audblk.mstrcplco[i] = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + for (j=0;j < p_a52dec->audblk.ncplbnd; j++) + { + p_a52dec->audblk.cplcoexp[i][j] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.cplcomant[i][j] = GetBits (&p_a52dec->bit_stream,4); + } + p_a52dec->total_bits_read += 8 * p_a52dec->audblk.ncplbnd; + } + } + p_a52dec->total_bits_read += p_a52dec->bsi.nfchans; + + /* If we're in dual mono mode, there's going to be some phase info */ + if ((p_a52dec->bsi.acmod == 0x2) && p_a52dec->audblk.phsflginu && + (p_a52dec->audblk.cplcoe[0] || p_a52dec->audblk.cplcoe[1])) + { + for (j=0; j < p_a52dec->audblk.ncplbnd; j++) + { + p_a52dec->audblk.phsflg[j] = GetBits (&p_a52dec->bit_stream,1); + } + p_a52dec->total_bits_read += p_a52dec->audblk.ncplbnd; + + } + } + + /* If we're in dual mono mode, there may be a rematrix strategy */ + if (p_a52dec->bsi.acmod == 0x2) + { + p_a52dec->audblk.rematstr = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + + if ((!blknum) && (!p_a52dec->audblk.rematstr)) + { + return 1; + } + + if (p_a52dec->audblk.rematstr) + { + if (p_a52dec->audblk.cplinu == 0) + { + for (i = 0; i < 4; i++) + { + p_a52dec->audblk.rematflg[i] = GetBits (&p_a52dec->bit_stream,1); + } + p_a52dec->total_bits_read += 4; + } + if ((p_a52dec->audblk.cplbegf > 2) && p_a52dec->audblk.cplinu) + { + for (i = 0; i < 4; i++) + { + p_a52dec->audblk.rematflg[i] = GetBits (&p_a52dec->bit_stream,1); + } + p_a52dec->total_bits_read += 4; + } + if ((p_a52dec->audblk.cplbegf <= 2) && p_a52dec->audblk.cplinu) + { + for (i = 0; i < 3; i++) + { + p_a52dec->audblk.rematflg[i] = GetBits (&p_a52dec->bit_stream,1); + } + p_a52dec->total_bits_read += 3; + } + if ((p_a52dec->audblk.cplbegf == 0) && p_a52dec->audblk.cplinu) + { + for (i = 0; i < 2; i++) + { + p_a52dec->audblk.rematflg[i] = GetBits (&p_a52dec->bit_stream,1); + } + p_a52dec->total_bits_read += 2; + } + } + } + + if (p_a52dec->audblk.cplinu) + { + /* Get the coupling channel exponent strategy */ + p_a52dec->audblk.cplexpstr = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + + if ((!blknum) && (p_a52dec->audblk.cplexpstr == EXP_REUSE)) + { + return 1; + } + + if (p_a52dec->audblk.cplexpstr==0) + { + p_a52dec->audblk.ncplgrps = 0; + } + else + { + p_a52dec->audblk.ncplgrps = (p_a52dec->audblk.cplendmant - p_a52dec->audblk.cplstrtmant) / + (3 << (p_a52dec->audblk.cplexpstr-1)); + } + + } + + for (i = 0; i < p_a52dec->bsi.nfchans; i++) + { + p_a52dec->audblk.chexpstr[i] = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + + if ((!blknum) && (p_a52dec->audblk.chexpstr[i] == EXP_REUSE)) + { + return 1; + } + } + + /* Get the exponent strategy for lfe channel */ + if (p_a52dec->bsi.lfeon) + { + p_a52dec->audblk.lfeexpstr = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + + if ((!blknum) && (p_a52dec->audblk.lfeexpstr == EXP_REUSE)) + { + return 1; + } + } + + /* Determine the bandwidths of all the fbw channels */ + for (i = 0; i < p_a52dec->bsi.nfchans; i++) + { + u16 grp_size; + + if (p_a52dec->audblk.chexpstr[i] != EXP_REUSE) + { + if (p_a52dec->audblk.cplinu && p_a52dec->audblk.chincpl[i]) + { + p_a52dec->audblk.endmant[i] = p_a52dec->audblk.cplstrtmant; + } + else + { + p_a52dec->audblk.chbwcod[i] = GetBits (&p_a52dec->bit_stream,6); + p_a52dec->total_bits_read += 6; + + if (p_a52dec->audblk.chbwcod[i] > 60) + { + return 1; + } + + p_a52dec->audblk.endmant[i] = ((p_a52dec->audblk.chbwcod[i] + 12) * 3) + 37; + } + + /* Calculate the number of exponent groups to fetch */ + grp_size = 3 * (1 << (p_a52dec->audblk.chexpstr[i] - 1)); + p_a52dec->audblk.nchgrps[i] = (p_a52dec->audblk.endmant[i] - 1 + (grp_size - 3)) / grp_size; + } + } + + /* Get the coupling exponents if they exist */ + if (p_a52dec->audblk.cplinu && (p_a52dec->audblk.cplexpstr != EXP_REUSE)) + { + p_a52dec->audblk.cplabsexp = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->total_bits_read += 4; + for (i=0; i< p_a52dec->audblk.ncplgrps;i++) + { + p_a52dec->audblk.cplexps[i] = GetBits (&p_a52dec->bit_stream,7); + p_a52dec->total_bits_read += 7; + + if (p_a52dec->audblk.cplexps[i] >= 125) + { + return 1; + } + } + } + + /* Get the fwb channel exponents */ + for (i=0; i < p_a52dec->bsi.nfchans; i++) + { + if (p_a52dec->audblk.chexpstr[i] != EXP_REUSE) + { + p_a52dec->audblk.exps[i][0] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->total_bits_read += 4; + for (j=1; j<=p_a52dec->audblk.nchgrps[i];j++) + { + p_a52dec->audblk.exps[i][j] = GetBits (&p_a52dec->bit_stream,7); + p_a52dec->total_bits_read += 7; + if (p_a52dec->audblk.exps[i][j] >= 125) + { + return 1; + } + } + p_a52dec->audblk.gainrng[i] = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + } + } + + /* Get the lfe channel exponents */ + if (p_a52dec->bsi.lfeon && (p_a52dec->audblk.lfeexpstr != EXP_REUSE)) + { + p_a52dec->audblk.lfeexps[0] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.lfeexps[1] = GetBits (&p_a52dec->bit_stream,7); + p_a52dec->total_bits_read += 11; + if (p_a52dec->audblk.lfeexps[1] >= 125) + { + return 1; + } + p_a52dec->audblk.lfeexps[2] = GetBits (&p_a52dec->bit_stream,7); + p_a52dec->total_bits_read += 7; + if (p_a52dec->audblk.lfeexps[2] >= 125) + { + return 1; + } + } + + /* Get the parametric bit allocation parameters */ + p_a52dec->audblk.baie = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + + if ((!blknum) && (!p_a52dec->audblk.baie)) + { + return 1; + } + + if (p_a52dec->audblk.baie) + { + p_a52dec->audblk.sdcycod = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->audblk.fdcycod = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->audblk.sgaincod = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->audblk.dbpbcod = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->audblk.floorcod = GetBits (&p_a52dec->bit_stream,3); + p_a52dec->total_bits_read += 11; + } + + /* Get the SNR off set info if it exists */ + p_a52dec->audblk.snroffste = GetBits (&p_a52dec->bit_stream,1); + if ((!blknum) && (!p_a52dec->audblk.snroffste)) + { + return 1; + } + + if (p_a52dec->audblk.snroffste) + { + p_a52dec->audblk.csnroffst = GetBits (&p_a52dec->bit_stream,6); + p_a52dec->total_bits_read += 6; + + if (p_a52dec->audblk.cplinu) + { + p_a52dec->audblk.cplfsnroffst = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.cplfgaincod = GetBits (&p_a52dec->bit_stream,3); + p_a52dec->total_bits_read += 7; + } + + for (i = 0;i < p_a52dec->bsi.nfchans; i++) + { + p_a52dec->audblk.fsnroffst[i] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.fgaincod[i] = GetBits (&p_a52dec->bit_stream,3); + } + p_a52dec->total_bits_read += 7 * p_a52dec->bsi.nfchans; + if (p_a52dec->bsi.lfeon) + { + p_a52dec->audblk.lfefsnroffst = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.lfefgaincod = GetBits (&p_a52dec->bit_stream,3); + p_a52dec->total_bits_read += 7; + } + } + + /* Get coupling leakage info if it exists */ + if (p_a52dec->audblk.cplinu) + { + p_a52dec->audblk.cplleake = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + if ((!blknum) && (!p_a52dec->audblk.cplleake)) + { + return 1; + } + + if (p_a52dec->audblk.cplleake) + { + p_a52dec->audblk.cplfleak = GetBits (&p_a52dec->bit_stream,3); + p_a52dec->audblk.cplsleak = GetBits (&p_a52dec->bit_stream,3); + p_a52dec->total_bits_read += 6; + } + } + + /* Get the delta bit alloaction info */ + p_a52dec->audblk.deltbaie = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + + if (p_a52dec->audblk.deltbaie) + { + if (p_a52dec->audblk.cplinu) + { + p_a52dec->audblk.cpldeltbae = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + if (p_a52dec->audblk.cpldeltbae == 3) + { + return 1; + } + } + + for (i = 0;i < p_a52dec->bsi.nfchans; i++) + { + p_a52dec->audblk.deltbae[i] = GetBits (&p_a52dec->bit_stream,2); + p_a52dec->total_bits_read += 2; + if (p_a52dec->audblk.deltbae[i] == 3) + { + return 1; + } + } + + if (p_a52dec->audblk.cplinu && (p_a52dec->audblk.cpldeltbae == DELTA_BIT_NEW)) + { + p_a52dec->audblk.cpldeltnseg = GetBits (&p_a52dec->bit_stream,3); + for (i = 0;i < p_a52dec->audblk.cpldeltnseg + 1; i++) + { + p_a52dec->audblk.cpldeltoffst[i] = GetBits (&p_a52dec->bit_stream,5); + p_a52dec->audblk.cpldeltlen[i] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.cpldeltba[i] = GetBits (&p_a52dec->bit_stream,3); + } + p_a52dec->total_bits_read += 12 * (p_a52dec->audblk.cpldeltnseg + 1) + 3; + } + + for (i = 0; i < p_a52dec->bsi.nfchans; i++) + { + if (p_a52dec->audblk.deltbae[i] == DELTA_BIT_NEW) + { + p_a52dec->audblk.deltnseg[i] = GetBits (&p_a52dec->bit_stream,3); +// if (p_a52dec->audblk.deltnseg[i] >= 8) +// fprintf (stderr, "parse debug: p_a52dec->audblk.deltnseg[%i] == %i\n", i, p_a52dec->audblk.deltnseg[i]); + for (j = 0; j < p_a52dec->audblk.deltnseg[i] + 1; j++) + { + p_a52dec->audblk.deltoffst[i][j] = GetBits (&p_a52dec->bit_stream,5); + p_a52dec->audblk.deltlen[i][j] = GetBits (&p_a52dec->bit_stream,4); + p_a52dec->audblk.deltba[i][j] = GetBits (&p_a52dec->bit_stream,3); + } + p_a52dec->total_bits_read += 12 * (p_a52dec->audblk.deltnseg[i] + 1) + 3; + } + } + } + + /* Check to see if there's any dummy info to get */ + p_a52dec->audblk.skiple = GetBits (&p_a52dec->bit_stream,1); + p_a52dec->total_bits_read += 1; + + if (p_a52dec->audblk.skiple) + { + p_a52dec->audblk.skipl = GetBits (&p_a52dec->bit_stream,9); + + for (i = 0; i < p_a52dec->audblk.skipl ; i++) + { + GetBits (&p_a52dec->bit_stream,8); + } + p_a52dec->total_bits_read += 8 * p_a52dec->audblk.skipl + 9; + } + + parse_audblk_stats(p_a52dec); + + return 0; +} + +void parse_auxdata (a52dec_t * p_a52dec) +{ + int i; + int skip_length; + + skip_length = (p_a52dec->syncinfo.frame_size * 16) - p_a52dec->total_bits_read - 17 - 1; + + for (i = 0; i < skip_length; i++) + { + RemoveBits (&p_a52dec->bit_stream,1); + } + + /* get the auxdata exists bit */ + RemoveBits (&p_a52dec->bit_stream,1); + + /* Skip the CRC reserved bit */ + RemoveBits (&p_a52dec->bit_stream,1); + + /* Get the crc */ + RemoveBits (&p_a52dec->bit_stream,16); +} + +static void parse_bsi_stats (a52dec_t * p_a52dec) /* Some stats */ +{ +#if 0 + struct mixlev_s + { + float clev; + char *desc; + }; + static const char *service_ids[8] = + { + "CM","ME","VI","HI", + "D", "C","E", "VO" + }; +/* + static const struct mixlev_s cmixlev_tbl[4] = + { + {0.707, "(-3.0 dB)"}, {0.595, "(-4.5 dB)"}, + {0.500, "(-6.0 dB)"}, {1.0, "Invalid"} + }; + static const struct mixlev_s smixlev_tbl[4] = + { + {0.707, "(-3.0 dB)"}, {0.500, "(-6.0 dB)"}, + { 0.0, "off "}, { 1.0, "Invalid"} + }; + */ + + static int i=0; + + if ( !i ) + { +/* if ((p_a52dec->bsi.acmod & 0x1) && (p_a52dec->bsi.acmod != 0x1)) + printf("CentreMixLevel %s ",cmixlev_tbl[p_a52dec->bsi.cmixlev].desc); + if (p_a52dec->bsi.acmod & 0x4) + printf("SurMixLevel %s",smixlev_tbl[p_a52dec->bsi.cmixlev].desc); + */ + intf_Msg ( "(a52dec_parsebsi) %s %d.%d Mode", + service_ids[p_a52dec->bsi.bsmod], + p_a52dec->bsi.nfchans,p_a52dec->bsi.lfeon); + } + i++; + + if ( i > 100 ) + i = 0; +#endif +} + +static void parse_audblk_stats (a52dec_t * p_a52dec) +{ +#if 0 + char *exp_strat_tbl[4] = {"R ","D15 ","D25 ","D45 "}; + u32 i; + intf_ErrMsg ("(a52dec_parseaudblk) "); + intf_ErrMsg ("%s ",p_a52dec->audblk.cplinu ? "cpl on" : "cpl off"); + intf_ErrMsg ("%s ",p_a52dec->audblk.baie? "bai" : " "); + intf_ErrMsg ("%s ",p_a52dec->audblk.snroffste? "snroffst" : " "); + intf_ErrMsg ("%s ",p_a52dec->audblk.deltbaie? "deltba" : " "); + intf_ErrMsg ("%s ",p_a52dec->audblk.phsflginu? "phsflg" : " "); + intf_ErrMsg ("(%s %s %s %s %s) ",exp_strat_tbl[p_a52dec->audblk.chexpstr[0]], + exp_strat_tbl[p_a52dec->audblk.chexpstr[1]],exp_strat_tbl[p_a52dec->audblk.chexpstr[2]], + exp_strat_tbl[p_a52dec->audblk.chexpstr[3]],exp_strat_tbl[p_a52dec->audblk.chexpstr[4]]); + intf_ErrMsg ("["); + for(i=0;ibsi.nfchans;i++) + intf_ErrMsg ("%1d",p_a52dec->audblk.blksw[i]); + intf_ErrMsg ("]"); +#endif +} + diff --git a/modules/codec/a52old/rematrix.c b/modules/codec/a52old/rematrix.c new file mode 100644 index 0000000000..af02d91ec1 --- /dev/null +++ b/modules/codec/a52old/rematrix.c @@ -0,0 +1,79 @@ +/***************************************************************************** + * rematrix.c: A52 audio rematrixing + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: rematrix.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Aaron Holtzman + * + * 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 +#include + +#include "imdct.h" +#include "downmix.h" +#include "adec.h" + +struct rematrix_band_s { + u32 start; + u32 end; +}; + +static const struct rematrix_band_s rematrix_band[] = { {13,24}, {25,36}, {37 ,60}, {61,252}}; + +static inline u32 min_value (u32 a, u32 b) +{ + return (a < b ? a : b); +} + +/* This routine simply does stereo rematixing for the 2 channel + * stereo mode */ +void rematrix (a52dec_t * p_a52dec) +{ + u32 num_bands; + u32 start; + u32 end; + u32 i,j; + float left,right; + + if (p_a52dec->audblk.cplinu || p_a52dec->audblk.cplbegf > 2) + num_bands = 4; + else if (p_a52dec->audblk.cplbegf > 0) + num_bands = 3; + else + num_bands = 2; + + for (i=0;i < num_bands; i++) { + if (!p_a52dec->audblk.rematflg[i]) + continue; + + start = rematrix_band[i].start; + end = min_value(rematrix_band[i].end ,12 * p_a52dec->audblk.cplbegf + 36); + + for (j=start;j < end; j++) { + left = 0.5f * ( *(p_a52dec->samples+j) + *(p_a52dec->samples+256+j) ); + right = 0.5f * ( *(p_a52dec->samples+j) - *(p_a52dec->samples+256+j) ); + *(p_a52dec->samples+j) = left; + *(p_a52dec->samples+256+j) = right; + } + } +} + diff --git a/modules/codec/cinepak/.cvsignore b/modules/codec/cinepak/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/cinepak/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/cinepak/Makefile b/modules/codec/cinepak/Makefile new file mode 100644 index 0000000000..e47caa07ed --- /dev/null +++ b/modules/codec/cinepak/Makefile @@ -0,0 +1 @@ +cinepak_SOURCES = cinepak.c diff --git a/modules/codec/cinepak/cinepak.c b/modules/codec/cinepak/cinepak.c new file mode 100644 index 0000000000..74ff13cb48 --- /dev/null +++ b/modules/codec/cinepak/cinepak.c @@ -0,0 +1,966 @@ +/***************************************************************************** + * cinepak.c: cinepak video decoder + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: cinepak.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ + +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include /* getpid() */ +#endif + +#include +#include + +#ifdef HAVE_SYS_TIMES_H +# include +#endif + +#include "vdec_ext-plugins.h" +#include "cinepak.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( videodec_thread_t * ); +static void EndThread ( videodec_thread_t * ); +static void DecodeThread ( videodec_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( "Cinepak video decoder" ); + set_capability( "decoder", 70 ); + 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 chose. + *****************************************************************************/ +static int OpenDecoder( vlc_object_t *p_this ) +{ + decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; + + switch( p_fifo->i_fourcc ) + { + case VLC_FOURCC('c','v','i','d'): + case VLC_FOURCC('C','V','I','D'): + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; + } + + return VLC_EGENERIC; +} + +/***************************************************************************** + * RunDecoder: this function is called just after the thread is created + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t *p_fifo ) +{ + videodec_thread_t *p_vdec; + int b_error; + + if ( !(p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + memset( p_vdec, 0, sizeof( videodec_thread_t ) ); + + p_vdec->p_fifo = p_fifo; + + if( InitThread( p_vdec ) != 0 ) + { + DecoderError( p_fifo ); + return( -1 ); + } + + while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) ) + { + DecodeThread( p_vdec ); + } + + if( ( b_error = p_vdec->p_fifo->b_error ) ) + { + DecoderError( p_vdec->p_fifo ); + } + + EndThread( p_vdec ); + + if( b_error ) + { + return( -1 ); + } + + return( 0 ); +} + + +/***************************************************************************** + * locales Functions + *****************************************************************************/ + +static inline u16 GetWBE( u8 *p_buff ) +{ + return( (p_buff[0]<<8) + p_buff[1] ); +} + +static inline u32 GetDWBE( u8 *p_buff ) +{ + return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) + + ( p_buff[2] <<8 ) + p_buff[3] ); +} + +#define GET2BYTES( p ) \ + GetWBE( p ); p+= 2; +/* FIXME */ +#define GET3BYTES( p ) \ + (GetDWBE( p ) >> 8); p+= 3; + +#define GET4BYTES( p ) \ + GetDWBE( p ); p+= 4; + +#define FREE( p ) \ + if( p ) free( p ) + +/* get the first pes from fifo */ +static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo ) +{ + pes_packet_t *p_pes; + + vlc_mutex_lock( &p_fifo->data_lock ); + + /* if fifo is emty wait */ + while( !p_fifo->p_first ) + { + if( p_fifo->b_die ) + { + vlc_mutex_unlock( &p_fifo->data_lock ); + return( NULL ); + } + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + p_pes = p_fifo->p_first; + + vlc_mutex_unlock( &p_fifo->data_lock ); + + return( p_pes ); +} + +/* free the first pes and go to next */ +static void __PES_NEXT( decoder_fifo_t *p_fifo ) +{ + pes_packet_t *p_next; + + vlc_mutex_lock( &p_fifo->data_lock ); + + p_next = p_fifo->p_first->p_next; + p_fifo->p_first->p_next = NULL; + input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first ); + p_fifo->p_first = p_next; + p_fifo->i_depth--; + + if( !p_fifo->p_first ) + { + /* No PES in the fifo */ + /* pp_last no longer valid */ + p_fifo->pp_last = &p_fifo->p_first; + while( !p_fifo->p_first ) + { + vlc_cond_signal( &p_fifo->data_wait ); + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + } + vlc_mutex_unlock( &p_fifo->data_lock ); +} + +static inline void __GetFrame( videodec_thread_t *p_vdec ) +{ + pes_packet_t *p_pes; + data_packet_t *p_data; + byte_t *p_buffer; + + p_pes = __PES_GET( p_vdec->p_fifo ); + p_vdec->i_pts = p_pes->i_pts; + + while( ( !p_pes->i_nb_data )||( !p_pes->i_pes_size ) ) + { + __PES_NEXT( p_vdec->p_fifo ); + p_pes = __PES_GET( p_vdec->p_fifo ); + } + p_vdec->i_framesize = p_pes->i_pes_size; + if( p_pes->i_nb_data == 1 ) + { + p_vdec->p_framedata = p_pes->p_first->p_payload_start; + return; + } + /* get a buffer and gather all data packet */ + p_vdec->p_framedata = p_buffer = malloc( p_pes->i_pes_size ); + p_data = p_pes->p_first; + do + { + p_vdec->p_fifo->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, + p_data->p_payload_end - p_data->p_payload_start ); + p_buffer += p_data->p_payload_end - p_data->p_payload_start; + p_data = p_data->p_next; + } while( p_data ); +} + +static inline void __NextFrame( videodec_thread_t *p_vdec ) +{ + pes_packet_t *p_pes; + + p_pes = __PES_GET( p_vdec->p_fifo ); + if( p_pes->i_nb_data != 1 ) + { + free( p_vdec->p_framedata ); /* FIXME keep this buffer */ + } + __PES_NEXT( p_vdec->p_fifo ); +} + +static int cinepak_CheckVout( vout_thread_t *p_vout, + int i_width, + int i_height ) +{ + if( !p_vout ) + { + return( 0 ); + } + + if( ( p_vout->render.i_width != i_width )|| + ( p_vout->render.i_height != i_height )|| + ( p_vout->render.i_chroma != VLC_FOURCC('I','4','2','0') )|| + ( p_vout->render.i_aspect != VOUT_ASPECT_FACTOR * i_width / i_height) ) + { + return( 0 ); + } + else + { + return( 1 ); + } +} + +/* Return a Vout */ + +static vout_thread_t *cinepak_CreateVout( videodec_thread_t *p_vdec, + int i_width, + int i_height ) +{ + vout_thread_t *p_vout; + + if( (!i_width)||(!i_height) ) + { + return( NULL ); /* Can't create a new vout without display size */ + } + + /* Spawn a video output if there is none. First we look for our children, + * then we look for any other vout that might be available. */ + p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT, + FIND_CHILD ); + if( !p_vout ) + { + p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT, + FIND_ANYWHERE ); + } + + if( p_vout ) + { + if( !cinepak_CheckVout( p_vout, i_width, i_height ) ) + { + /* We are not interested in this format, close this vout */ + vlc_object_detach_all( p_vout ); + vlc_object_release( p_vout ); + vout_DestroyThread( p_vout ); + p_vout = NULL; + } + else + { + /* This video output is cool! Hijack it. */ + vlc_object_detach_all( p_vout ); + vlc_object_attach( p_vout, p_vdec->p_fifo ); + vlc_object_release( p_vout ); + } + } + + if( p_vout == NULL ) + { + msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" ); + + p_vout = vout_CreateThread( p_vdec->p_fifo, + i_width, + i_height, + VLC_FOURCC('I','4','2','0'), + VOUT_ASPECT_FACTOR * i_width / i_height ); + } + + return( p_vout ); +} + +void cinepak_LoadCodebook( cinepak_codebook_t *p_codebook, + u8 *p_data, + int b_grayscale ) +{ + int i, i_y[4], i_u, i_v, i_Cb, i_Cr; + int i_uv; +#define SCALEBITS 12 +#define FIX( x ) ( (int)( (x) * ( 1L << SCALEBITS ) + 0.5 ) ) + + for( i = 0; i < 4; i++ ) + { + i_y[i] = (u8)( *(p_data++) ); + } + if( b_grayscale ) + { + i_u = (s8)( *(p_data++) ); + i_v = (s8)( *(p_data++) ); + } + else + { + i_u = 0; + i_v = 0; + } + + /* + | Y | | 1 -0.0655 0.0110 | | CY | + | Cb | = | 0 1.1656 -0.0062 | | CU | + | Cr | | 0 0.0467 1.4187 | | CV | + */ + i_uv = ( FIX( -0.0655 ) * i_u + FIX( 0.0110 ) * i_v ) >> SCALEBITS; + for( i = 0; i < 4; i++ ) + { + i_y[i] += i_uv; + } + i_Cb = ( FIX( 1.1656 ) * i_u + FIX( -0.0062 ) * i_v ) >> SCALEBITS; + i_Cr = ( FIX( 0.0467 ) * i_u + FIX( 1.4187 ) * i_v ) >> SCALEBITS; + + for( i = 0; i < 4; i++ ) + { + p_codebook->i_y[i] = __MIN( __MAX( 0, i_y[i] ), 255 ); + } + p_codebook->i_u = __MIN( __MAX( 0, i_Cb + 128 ), 255 ); + p_codebook->i_v = __MIN( __MAX( 0, i_Cr + 128 ), 255 ); + +#undef FIX +#undef SCALEBITS +} + +void cinepak_Getv4( cinepak_context_t *p_context, + int i_strip, + int i_x, int i_y, + int i_x2, int i_y2, + u8 *p_data ) +{ + u8 i_index[4]; + int i,j; + + u8 *p_dst_y, *p_dst_u, *p_dst_v; +#define PIX_SET_Y( x, y, v ) \ + p_dst_y[(x) + (y)* p_context->i_stride[0]] = (v); + +#define PIX_SET_UV( i, p, x, y, v ) \ + p[(x) + (y)* (p_context->i_stride[i])] = (v); + + for( i = 0; i < 4; i++ ) + { + i_index[i] = *(p_data++); + } + + /* y plane */ + p_dst_y = p_context->p_pix[0] + p_context->i_stride[0] * i_y + i_x; + p_dst_u = p_context->p_pix[1] + p_context->i_stride[1] * (i_y/2) + (i_x/2); + p_dst_v = p_context->p_pix[2] + p_context->i_stride[2] * (i_y/2) + (i_x/2); + + for( i = 0; i < 2; i++ ) + { + for( j = 0; j < 2; j ++ ) + { + PIX_SET_Y( 2*j + 0, 2*i + 0, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_y[0]); + PIX_SET_Y( 2*j + 1, 2*i + 0, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_y[1]); + PIX_SET_Y( 2*j + 0, 2*i + 1, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_y[2]); + PIX_SET_Y( 2*j + 1, 2*i + 1, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_y[3]); + + PIX_SET_UV( 1, p_dst_u, j, i, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_u ); + PIX_SET_UV( 2, p_dst_v, j, i, + p_context->codebook_v4[i_strip][i_index[j+2*i]].i_v ); + } + } +#undef PIX_SET_Y +#undef PIX_SET_UV +} + +void cinepak_Getv1( cinepak_context_t *p_context, + int i_strip, + int i_x, int i_y, + int i_x2, int i_y2, + u8 *p_data ) +{ + u8 i_index; + int i,j; + + u8 *p_dst_y, *p_dst_u, *p_dst_v; +#define PIX_SET_Y( x, y, v ) \ + p_dst_y[(x) + (y)* p_context->i_stride[0]] = (v); + +#define PIX_SET_UV( i,p, x, y, v ) \ + p[(x) + (y)* (p_context->i_stride[i])] = (v); + + i_index = *(p_data++); + + /* y plane */ + p_dst_y = p_context->p_pix[0] + p_context->i_stride[0] * i_y + i_x; + p_dst_u = p_context->p_pix[1] + p_context->i_stride[1] * (i_y/2) + (i_x/2); + p_dst_v = p_context->p_pix[2] + p_context->i_stride[2] * (i_y/2) + (i_x/2); + + for( i = 0; i < 2; i++ ) + { + for( j = 0; j < 2; j ++ ) + { + PIX_SET_Y( 2*j + 0, 2*i + 0, + p_context->codebook_v1[i_strip][i_index].i_y[0] ); + PIX_SET_Y( 2*j + 1, 2*i + 0, + p_context->codebook_v1[i_strip][i_index].i_y[1] ); + PIX_SET_Y( 2*j + 0, 2*i + 1, + p_context->codebook_v1[i_strip][i_index].i_y[2] ); + PIX_SET_Y( 2*j + 1, 2*i + 1, + p_context->codebook_v1[i_strip][i_index].i_y[3] ); + + PIX_SET_UV( 1,p_dst_u, j, i, + p_context->codebook_v1[i_strip][i_index].i_u ); + PIX_SET_UV( 2,p_dst_v, j, i, + p_context->codebook_v1[i_strip][i_index].i_v ); + } + } + +#undef PIX_SET_Y +#undef PIX_SET_UV +} + +/***************************************************************************** + * The function that decode one frame + *****************************************************************************/ +int cinepak_decode_frame( cinepak_context_t *p_context, + int i_length, u8 *p_data ) +{ + int i_strip; + + int i_frame_flags; + int i_frame_size; + int i_width, i_height; + int i_frame_strips; + int i_index; + int i_strip_x1 =0, i_strip_y1=0; + int i_strip_x2 =0, i_strip_y2=0; + + if( i_length <= 10 ) + { + /* Broken header or no data */ + return( -1 ); + } + + /* get header */ + i_frame_flags = *(p_data++); + i_frame_size = GET3BYTES( p_data ); + i_width = GET2BYTES( p_data ); + i_height = GET2BYTES( p_data ); + i_frame_strips = GET2BYTES( p_data ); + + /* Check if we have a picture buffer with good size */ + if( ( p_context->i_width != i_width )|| + ( p_context->i_height != i_height ) ) + { + int i; + for( i = 0; i < 3; i++ ) + { + FREE( p_context->p_pix[i] ); + } + + p_context->i_width = i_width; + p_context->i_height = i_height; + + p_context->i_stride[0] = ( i_width + 3)&0xfffc; + p_context->i_stride[1] = p_context->i_stride[2] = + p_context->i_stride[0] / 2; + + p_context->i_lines[0] = ( i_height + 3 )&0xfffc; + p_context->i_lines[1] = p_context->i_lines[2] = + p_context->i_lines[0] /2; + + for( i = 0; i < 3; i++ ) + { + p_context->p_pix[i] = malloc( p_context->i_stride[i] * + p_context->i_lines[i] ); + } + } + + if( i_frame_size != i_length ) + { + i_length = __MIN( i_length, i_frame_size ); + } + i_length -= 10; + + if( i_frame_strips >= CINEPAK_MAXSTRIP ) + { + i_frame_strips = CINEPAK_MAXSTRIP; + } + + /* Now decode each strip */ + + for( i_strip = 0; i_strip < i_frame_strips; i_strip++ ) + { + int i_strip_id; + int i_strip_size; + + if( i_length <= 12 ) + { + break; + } + + + i_strip_id = GET2BYTES( p_data ); + i_strip_size = GET2BYTES( p_data ); + i_strip_size = __MIN( i_strip_size, i_length ); + /* FIXME I don't really understand how it's work; */ + i_strip_y1 = i_strip_y2 + GET2BYTES( p_data ); + i_strip_x1 = GET2BYTES( p_data ); + i_strip_y2 = i_strip_y2 + GET2BYTES( p_data ); + i_strip_x2 = GET2BYTES( p_data ); + + i_length -= i_strip_size; + + i_strip_size -= 12; + /* init codebook , if needed */ + if( ( i_strip > 0 )&&( !(i_frame_flags&0x01) ) ) + { + memcpy( &p_context->codebook_v1[i_strip], + &p_context->codebook_v1[i_strip-1], + sizeof(cinepak_codebook_t[256] ) ); + + memcpy( &p_context->codebook_v4[i_strip], + &p_context->codebook_v4[i_strip-1], + sizeof(cinepak_codebook_t[256] ) ); + } + + /* Now parse all chunk in this strip */ + while( i_strip_size > 0 ) + { + cinepak_codebook_t (*p_codebook)[CINEPAK_MAXSTRIP][256]; + int i_mode; + + int i_chunk_id; + int i_chunk_size; + u32 i_vector_flags; + int i_count; + int i; + int i_x, i_y; /* (0,0) begin in fact at (x1,y1) ... */ + + i_chunk_id = GET2BYTES( p_data ); + i_chunk_size = GET2BYTES( p_data ); + i_chunk_size = __MIN( i_chunk_size, i_strip_size ); + i_strip_size -= i_chunk_size; + + i_chunk_size -= 4; + + i_x = 0; + i_y = 0; + if( i_chunk_size < 0 ) + { + break; + } + + switch( i_chunk_id ) + { + case( 0x2000 ): /* 12bits v4 Intra*/ + case( 0x2200 ): /* 12bits v1 Intra*/ + case( 0x2400 ): /* 8bits v4 Intra*/ + case( 0x2600 ): /* 8bits v1 Intra */ + i_mode = ( ( i_chunk_id&0x0400 ) == 0 ); + p_codebook = ( i_chunk_id&0x0200 ) ? + &p_context->codebook_v1 : + &p_context->codebook_v4; + + i_count = __MIN( i_chunk_size / ( i_mode ? 6 : 4 ), 256 ); + + for( i = 0; i < i_count; i++ ) + { + cinepak_LoadCodebook( &((*p_codebook)[i_strip][i]), + p_data, + i_mode&~p_context->b_grayscale ); + p_data += i_mode ? 6 : 4; + i_chunk_size -= i_mode ? 6 : 4; + } + break; + + case( 0x2100 ): /* selective 12bits v4 Inter*/ + case( 0x2300 ): /* selective 12bits v1 Inter*/ + case( 0x2500 ): /* selective 8bits v4 Inter*/ + case( 0x2700 ): /* selective 8bits v1 Inter*/ + i_mode = ( ( i_chunk_id&0x0400 ) == 0 ); + p_codebook = ( i_chunk_id&0x0200 ) ? + &p_context->codebook_v1 : + &p_context->codebook_v4; + + i_index = 0; + while( (i_chunk_size > 4)&&(i_index<256)) + { + i_vector_flags = GET4BYTES( p_data ); + i_chunk_size -= 4; + for( i = 0; i < 32; i++ ) + { + if( ( i_chunk_size < ( i_mode ? 6 : 4 ) )||(i_index >= 256 )) + { + break; + } + if( i_vector_flags&0x80000000UL ) + { + cinepak_LoadCodebook( &((*p_codebook)[i_strip][i_index]), + p_data, + i_mode&~p_context->b_grayscale ); + + p_data += i_mode ? 6 : 4; + i_chunk_size -= i_mode ? 6 : 4; + } + i_index++; + i_vector_flags <<= 1; + } + } + break; + + case( 0x3000 ): /* load image Intra */ + while( (i_chunk_size >= 4 )&&(i_y= i_strip_y2 - i_strip_y1)|| + ( i_chunk_size<=0) ) + { + break; + } + if( i_vector_flags&0x80000000UL ) + { + cinepak_Getv4( p_context, + i_strip, + i_strip_x1 + i_x, + i_strip_y1 + i_y, + i_strip_x2, i_strip_y2, + p_data ); + p_data += 4; + i_chunk_size -= 4; + } + else + { + cinepak_Getv1( p_context, + i_strip, + i_strip_x1 + i_x, + i_strip_y1 + i_y, + i_strip_x2, i_strip_y2, + p_data ); + p_data++; + i_chunk_size--; + } + + i_x += 4; + if( i_x >= i_strip_x2 - i_strip_x1 ) + { + i_x = 0; + i_y += 4; + } + i_vector_flags <<= 1; + } + } + break; + + case( 0x3100 ): /* load image Inter */ + while( ( i_chunk_size > 4 )&&( i_y < i_strip_y2 - i_strip_y1) ) + { + u32 i_mask; + i_vector_flags = GET4BYTES( p_data ); + i_chunk_size -= 4; + i_mask = 0x80000000UL; + + while((i_chunk_size > 0 )&&( i_mask )&&( i_y < i_strip_y2 - i_strip_y1 )) + { + if( i_vector_flags&i_mask) + { + i_mask >>= 1; + if( !i_mask ) + { + if( i_chunk_size < 4 ) + { + break; + } + i_vector_flags = GET4BYTES( p_data ); + i_chunk_size -= 4; + i_mask = 0x80000000UL; + } + if( i_vector_flags&i_mask ) + { + if( i_chunk_size < 4 ) break; + cinepak_Getv4( p_context, + i_strip, + i_strip_x1 + i_x, + i_strip_y1 + i_y, + i_strip_x2, i_strip_y2, + p_data ); + p_data += 4; + i_chunk_size -= 4; + } + else + { + if( i_chunk_size < 1 ) break; + cinepak_Getv1( p_context, + i_strip, + i_strip_x1 + i_x, + i_strip_y1 + i_y, + i_strip_x2, i_strip_y2, + p_data ); + p_data++; + i_chunk_size--; + } + } + i_mask >>= 1; + + i_x += 4; + if( i_x >= i_strip_x2 - i_strip_x1 ) + { + i_x = 0; + i_y += 4; + } + } + } + break; + + case( 0x3200 ): /* load intra picture but all v1*/ + while( ( i_chunk_size > 0 )&& + ( i_y < i_strip_y2 - i_strip_y1) ) + { + cinepak_Getv1( p_context, + i_strip, + i_strip_x1 + i_x, + i_strip_y1 + i_y, + i_strip_x2, i_strip_y2, + p_data ); + p_data++; + i_chunk_size--; + + i_x += 4; + if( i_x >= i_strip_x2 - i_strip_x1 ) + { + i_x = 0; + i_y += 4; + } + + } + break; + + + + default: + break; + + } + p_data += i_chunk_size ; /* skip remains bytes */ + + } + } + + + return( 0 ); +} + + +/***************************************************************************** + * + * Functions that initialize, decode and end the decoding process + * + *****************************************************************************/ + +/***************************************************************************** + * InitThread: initialize vdec output thread + ***************************************************************************** + * This function is called from decoder_Run and performs the second step + * of the initialization. It returns 0 on success. Note that the thread's + * flag are not modified inside this function. + *****************************************************************************/ + +static int InitThread( videodec_thread_t *p_vdec ) +{ + + /* This will be created after the first decoded frame */ + if( !(p_vdec->p_context = malloc( sizeof( cinepak_context_t ) ) ) ) + { + msg_Err( p_vdec->p_fifo, "out of memory" ); + } + memset( p_vdec->p_context, 0, sizeof( cinepak_context_t ) ); + + if( config_GetInt( p_vdec->p_fifo, "grayscale" ) ) + { + p_vdec->p_context->b_grayscale = 1; + } + else + { + p_vdec->p_context->b_grayscale = 0; + } + + p_vdec->p_vout = NULL; + msg_Dbg( p_vdec->p_fifo, "cinepak decoder started" ); + return( 0 ); +} + + +/***************************************************************************** + * DecodeThread: Called for decode one frame + *****************************************************************************/ +static void DecodeThread( videodec_thread_t *p_vdec ) +{ + int i_status; + + int i_plane; + u8 *p_dst, *p_src; + picture_t *p_pic; /* videolan picture */ + + __GetFrame( p_vdec ); + + i_status = cinepak_decode_frame( p_vdec->p_context, + p_vdec->i_framesize, + p_vdec->p_framedata ); + __NextFrame( p_vdec ); + + if( i_status < 0 ) + { + msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)", + p_vdec->i_framesize ); + return; + } + + /* Check our vout */ + if( !cinepak_CheckVout( p_vdec->p_vout, + p_vdec->p_context->i_width, + p_vdec->p_context->i_height ) ) + { + p_vdec->p_vout = + cinepak_CreateVout( p_vdec, + p_vdec->p_context->i_width, + p_vdec->p_context->i_height ); + + if( !p_vdec->p_vout ) + { + msg_Err( p_vdec->p_fifo, "cannot create vout" ); + p_vdec->p_fifo->b_error = 1; /* abort */ + return; + } + } + + /* Send decoded frame to vout */ + while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) ) + { + if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + for( i_plane = 0; i_plane < 3; i_plane++ ) + { + int i_line, i_lines; + + p_dst = p_pic->p[i_plane].p_pixels; + p_src = p_vdec->p_context->p_pix[i_plane]; + + i_lines = __MIN( p_vdec->p_context->i_lines[i_plane], + p_pic->p[i_plane].i_lines ); + for( i_line = 0; i_line < i_lines; i_line++ ) + { + memcpy( p_dst, + p_src, + __MIN( p_pic->p[i_plane].i_pitch, + p_vdec->p_context->i_stride[i_plane] ) ); + p_dst += p_pic->p[i_plane].i_pitch; + p_src += p_vdec->p_context->i_stride[i_plane]; + } + } + + vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts); + vout_DisplayPicture( p_vdec->p_vout, p_pic ); + + return; +} + + +/***************************************************************************** + * EndThread: thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +static void EndThread( videodec_thread_t *p_vdec ) +{ + int i; + + if( !p_vdec ) + { + return; + } + msg_Dbg( p_vdec->p_fifo, "cinepak decoder stopped" ); + + for( i = 0; i < 3; i++ ) + { + FREE( p_vdec->p_context->p_pix[i] ); + } + + free( p_vdec->p_context ); + + if( p_vdec->p_vout != NULL ) + { + /* We are about to die. Reattach video output to p_vlc. */ + vlc_object_detach( p_vdec->p_vout, p_vdec->p_fifo ); + vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc ); + } + + free( p_vdec ); +} + + diff --git a/modules/codec/cinepak/cinepak.h b/modules/codec/cinepak/cinepak.h new file mode 100644 index 0000000000..df73d3c864 --- /dev/null +++ b/modules/codec/cinepak/cinepak.h @@ -0,0 +1,67 @@ +/***************************************************************************** + * cinepak.h: Cinepak video decoder + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: cinepak.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define CINEPAK_MAXSTRIP 32 + +typedef struct cinepak_codebook_s +{ + u8 i_y[4]; + u8 i_u, i_v; + +} cinepak_codebook_t; + + +typedef struct cinepak_context_s +{ + int b_grayscale; /* force to grayscale */ + + int i_width; + int i_height; + + int i_stride_x; + int i_stride_y; + + u8 *p_y, *p_u, *p_v; + + int i_stride[3]; /* our 3 planes */ + int i_lines[3]; + u8 *p_pix[3]; + + cinepak_codebook_t codebook_v1[CINEPAK_MAXSTRIP][256]; + cinepak_codebook_t codebook_v4[CINEPAK_MAXSTRIP][256]; + +} cinepak_context_t; + +typedef struct videodec_thread_s +{ + decoder_fifo_t *p_fifo; + + vout_thread_t *p_vout; + + cinepak_context_t *p_context; + + /* private */ + mtime_t i_pts; + int i_framesize; + byte_t *p_framedata; +} videodec_thread_t; diff --git a/modules/codec/ffmpeg/.cvsignore b/modules/codec/ffmpeg/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/ffmpeg/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/ffmpeg/Makefile b/modules/codec/ffmpeg/Makefile new file mode 100644 index 0000000000..0630428f24 --- /dev/null +++ b/modules/codec/ffmpeg/Makefile @@ -0,0 +1 @@ +ffmpeg_SOURCES = ffmpeg.c diff --git a/modules/codec/ffmpeg/ffmpeg.c b/modules/codec/ffmpeg/ffmpeg.c new file mode 100644 index 0000000000..c303e2e715 --- /dev/null +++ b/modules/codec/ffmpeg/ffmpeg.c @@ -0,0 +1,869 @@ +/***************************************************************************** + * ffmpeg.c: video decoder using ffmpeg library + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: ffmpeg.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ + +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include /* getpid() */ +#endif + +#include +#include + +#ifdef HAVE_SYS_TIMES_H +# include +#endif + +#include "vdec_ext-plugins.h" +#include "avcodec.h" /* ffmpeg */ +#include "ffmpeg.h" + +/* + * Local prototypes + */ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( videodec_thread_t * ); +static void EndThread ( videodec_thread_t * ); +static void DecodeThread ( videodec_thread_t * ); + + +static int b_ffmpeginit = 0; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +#define ERROR_RESILIENCE_LONGTEXT \ + "ffmpeg can make errors resiliences. \n"\ + "Nevertheless, with buggy encoder (like ISO MPEG-4 encoder from M$) " \ + "this will produce a lot of errors.\n" \ + "Valid range is -1 to 99 (-1 disable all errors resiliences)." + +#define HURRY_UP_LONGTEXT \ + "Allow the decoder to partially decode or skip frame(s) " \ + "when there not enough time.\n It's usefull with low CPU power " \ + "but it could produce broken pictures." + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); +#if LIBAVCODEC_BUILD >= 4611 + add_integer ( "ffmpeg-error-resilience", 0, NULL, + "error resilience", ERROR_RESILIENCE_LONGTEXT ); + add_integer ( "ffmpeg-workaround-bugs", 0, NULL, + "workaround bugs", "0-99, seems to be for msmpeg v3\n" ); +#endif + add_bool( "ffmpeg-hurry-up", 0, NULL, "hurry up", HURRY_UP_LONGTEXT ); + set_description( _("ffmpeg video decoder((MS)MPEG4,SVQ1,H263)") ); + set_capability( "decoder", 70 ); + 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 chose. + *****************************************************************************/ +static int OpenDecoder( vlc_object_t *p_this ) +{ + decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; + + if( ffmpeg_GetFfmpegCodec( p_fifo->i_fourcc, NULL, NULL ) ) + { + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; + } + + return VLC_EGENERIC; +} + +/***************************************************************************** + * RunDecoder: this function is called just after the thread is created + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t *p_fifo ) +{ + videodec_thread_t *p_vdec; + int b_error; + + if ( !(p_vdec = (videodec_thread_t*)malloc( sizeof(videodec_thread_t))) ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + memset( p_vdec, 0, sizeof( videodec_thread_t ) ); + + p_vdec->p_fifo = p_fifo; + + if( InitThread( p_vdec ) != 0 ) + { + DecoderError( p_fifo ); + return( -1 ); + } + + while( (!p_vdec->p_fifo->b_die) && (!p_vdec->p_fifo->b_error) ) + { + DecodeThread( p_vdec ); + } + + if( ( b_error = p_vdec->p_fifo->b_error ) ) + { + DecoderError( p_vdec->p_fifo ); + } + + EndThread( p_vdec ); + + if( b_error ) + { + return( -1 ); + } + + return( 0 ); +} + + +/***************************************************************************** + * locales Functions + *****************************************************************************/ + +#define GetWLE( p ) \ + ( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) ) + +#define GetDWLE( p ) \ + ( *(u8*)(p) + ( *((u8*)(p)+1) << 8 ) + \ + ( *((u8*)(p)+2) << 16 ) + ( *((u8*)(p)+3) << 24 ) ) + +static void ffmpeg_ParseBitMapInfoHeader( bitmapinfoheader_t *p_bh, + u8 *p_data ) +{ + p_bh->i_size = GetDWLE( p_data ); + p_bh->i_width = GetDWLE( p_data + 4 ); + p_bh->i_height = GetDWLE( p_data + 8 ); + p_bh->i_planes = GetWLE( p_data + 12 ); + p_bh->i_bitcount = GetWLE( p_data + 14 ); + p_bh->i_compression = GetDWLE( p_data + 16 ); + p_bh->i_sizeimage = GetDWLE( p_data + 20 ); + p_bh->i_xpelspermeter = GetDWLE( p_data + 24 ); + p_bh->i_ypelspermeter = GetDWLE( p_data + 28 ); + p_bh->i_clrused = GetDWLE( p_data + 32 ); + p_bh->i_clrimportant = GetDWLE( p_data + 36 ); + + if( p_bh->i_size > 40 ) + { + p_bh->i_data = p_bh->i_size - 40; + p_bh->p_data = malloc( p_bh->i_data ); + memcpy( p_bh->p_data, p_data + 40, p_bh->i_data ); + } + else + { + p_bh->i_data = 0; + p_bh->p_data = NULL; + } + +} +/* get the first pes from fifo */ +static pes_packet_t *__PES_GET( decoder_fifo_t *p_fifo ) +{ + pes_packet_t *p_pes; + + vlc_mutex_lock( &p_fifo->data_lock ); + + /* if fifo is emty wait */ + while( !p_fifo->p_first ) + { + if( p_fifo->b_die ) + { + vlc_mutex_unlock( &p_fifo->data_lock ); + return( NULL ); + } + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + p_pes = p_fifo->p_first; + + vlc_mutex_unlock( &p_fifo->data_lock ); + + return( p_pes ); +} + +/* free the first pes and go to next */ +static void __PES_NEXT( decoder_fifo_t *p_fifo ) +{ + pes_packet_t *p_next; + + vlc_mutex_lock( &p_fifo->data_lock ); + + p_next = p_fifo->p_first->p_next; + p_fifo->p_first->p_next = NULL; + input_DeletePES( p_fifo->p_packets_mgt, p_fifo->p_first ); + p_fifo->p_first = p_next; + p_fifo->i_depth--; + + if( !p_fifo->p_first ) + { + /* No PES in the fifo */ + /* pp_last no longer valid */ + p_fifo->pp_last = &p_fifo->p_first; + while( !p_fifo->p_first ) + { + vlc_cond_signal( &p_fifo->data_wait ); + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + } + vlc_mutex_unlock( &p_fifo->data_lock ); +} + +static inline void __GetFrame( videodec_thread_t *p_vdec ) +{ + pes_packet_t *p_pes; + data_packet_t *p_data; + byte_t *p_buffer; + + p_pes = __PES_GET( p_vdec->p_fifo ); + p_vdec->i_pts = p_pes->i_pts; + + while( ( !p_pes->i_nb_data )||( !p_pes->i_pes_size ) ) + { + __PES_NEXT( p_vdec->p_fifo ); + p_pes = __PES_GET( p_vdec->p_fifo ); + } + p_vdec->i_framesize = p_pes->i_pes_size; + if( p_pes->i_nb_data == 1 ) + { + p_vdec->p_framedata = p_pes->p_first->p_payload_start; + return; + } + /* get a buffer and gather all data packet */ + p_vdec->p_framedata = p_buffer = malloc( p_pes->i_pes_size ); + p_data = p_pes->p_first; + do + { + p_vdec->p_fifo->p_vlc->pf_memcpy( p_buffer, p_data->p_payload_start, + p_data->p_payload_end - p_data->p_payload_start ); + p_buffer += p_data->p_payload_end - p_data->p_payload_start; + p_data = p_data->p_next; + } while( p_data ); +} + +static inline void __NextFrame( videodec_thread_t *p_vdec ) +{ + pes_packet_t *p_pes; + + p_pes = __PES_GET( p_vdec->p_fifo ); + if( p_pes->i_nb_data != 1 ) + { + free( p_vdec->p_framedata ); /* FIXME keep this buffer */ + } + __PES_NEXT( p_vdec->p_fifo ); +} + +/* FIXME FIXME some of them are wrong */ +static int i_ffmpeg_PixFmtToChroma[] = +{ +/* PIX_FMT_ANY = -1,PIX_FMT_YUV420P, PIX_FMT_YUV422, + PIX_FMT_RGB24, PIX_FMT_BGR24, PIX_FMT_YUV422P, + PIX_FMT_YUV444P, PIX_FMT_YUV410P */ + + 0, VLC_FOURCC('I','4','2','0'), VLC_FOURCC('I','4','2','0'), + VLC_FOURCC('R','V','2','4'), 0, VLC_FOURCC('Y','4','2','2'), + VLC_FOURCC('I','4','4','4'), 0 +}; + +static inline u32 ffmpeg_PixFmtToChroma( int i_ffmpegchroma ) +{ + if( ++i_ffmpegchroma > 7 ) + { + return( 0 ); + } + else + { + return( i_ffmpeg_PixFmtToChroma[i_ffmpegchroma] ); + } +} + +static inline int ffmpeg_FfAspect( int i_width, int i_height, int i_ffaspect ) +{ + switch( i_ffaspect ) + { + case( FF_ASPECT_4_3_625 ): + case( FF_ASPECT_4_3_525 ): + return( VOUT_ASPECT_FACTOR * 4 / 3); + case( FF_ASPECT_16_9_625 ): + case( FF_ASPECT_16_9_525 ): + return( VOUT_ASPECT_FACTOR * 16 / 9 ); + case( FF_ASPECT_SQUARE ): + default: + return( VOUT_ASPECT_FACTOR * i_width / i_height ); + } +} + +static int ffmpeg_CheckVout( vout_thread_t *p_vout, + int i_width, + int i_height, + int i_aspect, + int i_chroma ) +{ + if( !p_vout ) + { + return( 0 ); + } + if( !i_chroma ) + { + /* we will try to make conversion */ + i_chroma = VLC_FOURCC('I','4','2','0'); + } + + if( ( p_vout->render.i_width != i_width )|| + ( p_vout->render.i_height != i_height )|| + ( p_vout->render.i_chroma != i_chroma )|| + ( p_vout->render.i_aspect != + ffmpeg_FfAspect( i_width, i_height, i_aspect ) ) ) + { + return( 0 ); + } + else + { + return( 1 ); + } +} + +/* Return a Vout */ + +static vout_thread_t *ffmpeg_CreateVout( videodec_thread_t *p_vdec, + int i_width, + int i_height, + int i_aspect, + int i_chroma ) +{ + vout_thread_t *p_vout; + + if( (!i_width)||(!i_height) ) + { + return( NULL ); /* Can't create a new vout without display size */ + } + + if( !i_chroma ) + { + /* we make conversion if possible*/ + i_chroma = VLC_FOURCC('I','4','2','0'); + msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)"); + /* It's mainly for I410 -> I420 conversion that I've made, + it's buggy and very slow */ + } + + i_aspect = ffmpeg_FfAspect( i_width, i_height, i_aspect ); + + /* Spawn a video output if there is none. First we look for our children, + * then we look for any other vout that might be available. */ + p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT, + FIND_CHILD ); + if( !p_vout ) + { + p_vout = vlc_object_find( p_vdec->p_fifo, VLC_OBJECT_VOUT, + FIND_ANYWHERE ); + } + + if( p_vout ) + { + if( !ffmpeg_CheckVout( p_vout, + i_width, i_height, i_aspect,i_chroma ) ) + { + /* We are not interested in this format, close this vout */ + vlc_object_detach_all( p_vout ); + vlc_object_release( p_vout ); + vout_DestroyThread( p_vout ); + p_vout = NULL; + } + else + { + /* This video output is cool! Hijack it. */ + vlc_object_detach_all( p_vout ); + vlc_object_attach( p_vout, p_vdec->p_fifo ); + vlc_object_release( p_vout ); + } + } + + if( p_vout == NULL ) + { + msg_Dbg( p_vdec->p_fifo, "no vout present, spawning one" ); + + p_vout = vout_CreateThread( p_vdec->p_fifo, + i_width, + i_height, + i_chroma, + i_aspect ); + } + + return( p_vout ); +} + +/* FIXME FIXME FIXME this is a big shit + does someone want to rewrite this function ? + or said to me how write a better thing + FIXME FIXME FIXME +*/ + +static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic, + AVPicture *p_avpicture, + videodec_thread_t *p_vdec ) +{ + u8 *p_src, *p_dst; + u8 *p_plane[3]; + int i_plane; + + int i_stride, i_lines; + int i_height, i_width; + int i_y, i_x; + + i_height = p_vdec->p_context->height; + i_width = p_vdec->p_context->width; + + p_dst = p_pic->p[0].p_pixels; + p_src = p_avpicture->data[0]; + + /* copy first plane */ + for( i_y = 0; i_y < i_height; i_y++ ) + { + p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width); + p_dst += p_pic->p[0].i_pitch; + p_src += p_avpicture->linesize[0]; + } + + /* process each plane in a temporary buffer */ + for( i_plane = 1; i_plane < 3; i_plane++ ) + { + i_stride = p_avpicture->linesize[i_plane]; + i_lines = i_height / 4; + + p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 ); + p_src = p_avpicture->data[i_plane]; + + /* for each source line */ + for( i_y = 0; i_y < i_lines; i_y++ ) + { + for( i_x = 0; i_x < i_stride - 1; i_x++ ) + { + p_dst[2 * i_x ] = p_src[i_x]; + p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2; + + } + p_dst[2 * i_stride - 2] = p_src[i_x]; + p_dst[2 * i_stride - 1] = p_src[i_x]; + + p_dst += 4 * i_stride; /* process the next even lines */ + p_src += i_stride; + } + + + } + + for( i_plane = 1; i_plane < 3; i_plane++ ) + { + i_stride = p_avpicture->linesize[i_plane]; + i_lines = i_height / 4; + + p_dst = p_plane[i_plane] + 2*i_stride; + p_src = p_plane[i_plane]; + + for( i_y = 0; i_y < i_lines - 1; i_y++ ) + { + for( i_x = 0; i_x < 2 * i_stride ; i_x++ ) + { + p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2; + } + + p_dst += 4 * i_stride; /* process the next odd lines */ + p_src += 4 * i_stride; + } + /* last line */ + p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride ); + } + /* copy to p_pic, by block + if I do pixel per pixel it segfault. It's why I use + temporaries buffers */ + for( i_plane = 1; i_plane < 3; i_plane++ ) + { + + int i_size; + p_src = p_plane[i_plane]; + p_dst = p_pic->p[i_plane].p_pixels; + + i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch); + for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ ) + { + p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size ); + p_src += 2 * i_stride; + p_dst += p_pic->p[i_plane].i_pitch; + } + free( p_plane[i_plane] ); + } + +} + +static void ffmpeg_ConvertPicture( picture_t *p_pic, + AVPicture *p_avpicture, + videodec_thread_t *p_vdec ) +{ + int i_plane; + int i_size; + int i_line; + + u8 *p_dst; + u8 *p_src; + int i_src_stride; + int i_dst_stride; + + if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) ) + { + /* convert ffmpeg picture to our format */ + for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) + { + p_src = p_avpicture->data[i_plane]; + p_dst = p_pic->p[i_plane].p_pixels; + i_src_stride = p_avpicture->linesize[i_plane]; + i_dst_stride = p_pic->p[i_plane].i_pitch; + + i_size = __MIN( i_src_stride, i_dst_stride ); + for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ ) + { + p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size ); + p_src += i_src_stride; + p_dst += i_dst_stride; + } + } + return; + } + + /* we need to convert to I420 */ + switch( p_vdec->p_context->pix_fmt ) + { +#if LIBAVCODEC_BUILD >= 4615 + case( PIX_FMT_YUV410P ): + ffmpeg_ConvertPictureI410toI420( p_pic, p_avpicture, p_vdec ); + break; +#endif + default: + p_vdec->p_fifo->b_error =1; + break; + } +} + + +/***************************************************************************** + * + * Functions that initialize, decode and end the decoding process + * + *****************************************************************************/ + +/***************************************************************************** + * InitThread: initialize vdec output thread + ***************************************************************************** + * This function is called from RunDecoderoder and performs the second step + * of the initialization. It returns 0 on success. Note that the thread's + * flag are not modified inside this function. + *****************************************************************************/ + +static int InitThread( videodec_thread_t *p_vdec ) +{ + int i_ffmpeg_codec; + int i_tmp; + + if( p_vdec->p_fifo->p_demux_data ) + { + ffmpeg_ParseBitMapInfoHeader( &p_vdec->format, + (u8*)p_vdec->p_fifo->p_demux_data ); + } + else + { + msg_Warn( p_vdec->p_fifo, "display informations missing" ); + } + + /*init ffmpeg */ + if( !b_ffmpeginit ) + { + avcodec_init(); + avcodec_register_all(); + b_ffmpeginit = 1; + msg_Dbg( p_vdec->p_fifo, "library ffmpeg initialized" ); + } + else + { + msg_Dbg( p_vdec->p_fifo, "library ffmpeg already initialized" ); + } + ffmpeg_GetFfmpegCodec( p_vdec->p_fifo->i_fourcc, + &i_ffmpeg_codec, + &p_vdec->psz_namecodec ); + p_vdec->p_codec = + avcodec_find_decoder( i_ffmpeg_codec ); + + if( !p_vdec->p_codec ) + { + msg_Err( p_vdec->p_fifo, "codec not found (%s)", + p_vdec->psz_namecodec ); + return( -1 ); + } + + p_vdec->p_context = &p_vdec->context; + memset( p_vdec->p_context, 0, sizeof( AVCodecContext ) ); + + p_vdec->p_context->width = p_vdec->format.i_width; + p_vdec->p_context->height = p_vdec->format.i_height; + +/* XXX + p_vdec->p_context->workaround_bugs + --> seems to be for msmpeg 3 but can't know what is supposed to do + + p_vdec->p_context->strict_std_compliance + --> strictly follow mpeg4 standard for decoder or encoder ?? + + p_vdec->p_context->error_resilience + --> don't make error resilience, because of some ms encoder witch + use some wrong VLC code. +*/ + +#if LIBAVCODEC_BUILD >= 4611 + i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" ); + p_vdec->p_context->workaround_bugs = __MAX( __MIN( i_tmp, 99 ), 0 ); + + i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" ); + p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 ); +#endif +#if LIBAVCODEC_BUILD >= 4614 + if( config_GetInt( p_vdec->p_fifo, "grayscale" ) ) + { + p_vdec->p_context->flags|= CODEC_FLAG_GRAY; + } +#endif + + if (avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0) + { + msg_Err( p_vdec->p_fifo, "cannot open codec (%s)", + p_vdec->psz_namecodec ); + return( -1 ); + } + else + { + msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started", + p_vdec->psz_namecodec ); + } + + /* first give init data */ + if( p_vdec->format.i_data ) + { + AVPicture avpicture; + int b_gotpicture; + + switch( i_ffmpeg_codec ) + { + case( CODEC_ID_MPEG4 ): + avcodec_decode_video( p_vdec->p_context, &avpicture, + &b_gotpicture, + p_vdec->format.p_data, + p_vdec->format.i_data ); + break; + default: + break; + } + } + + /* This will be created after the first decoded frame */ + p_vdec->p_vout = NULL; + + return( 0 ); +} + +/***************************************************************************** + * DecodeThread: Called for decode one frame + *****************************************************************************/ +static void DecodeThread( videodec_thread_t *p_vdec ) +{ + int i_status; + int b_drawpicture; + int b_gotpicture; + AVPicture avpicture; /* ffmpeg picture */ + picture_t *p_pic; /* videolan picture */ + /* we have to get a frame stored in a pes + give it to ffmpeg decoder + and send the image to the output */ + + /* TODO implement it in a better way */ + + if( ( config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up") )&& + ( p_vdec->i_frame_late > 4 ) ) + { +#if LIBAVCODEC_BUILD > 4603 + b_drawpicture = 0; + if( p_vdec->i_frame_late < 8 ) + { + p_vdec->p_context->hurry_up = 2; + } + else + { + /* too much late picture, won't decode + but break picture until a new I, and for mpeg4 ...*/ + p_vdec->i_frame_late--; /* needed else it will never be decrease */ + __PES_NEXT( p_vdec->p_fifo ); + return; + } +#else + if( p_vdec->i_frame_late < 8 ) + { + b_drawpicture = 0; /* not really good but .. */ + } + else + { + /* too much late picture, won't decode + but break picture until a new I, and for mpeg4 ...*/ + p_vdec->i_frame_late--; /* needed else it will never be decrease */ + __PES_NEXT( p_vdec->p_fifo ); + return; + } +#endif + } + else + { + b_drawpicture = 1; +#if LIBAVCODEC_BUILD > 4603 + p_vdec->p_context->hurry_up = 0; +#endif + } + + __GetFrame( p_vdec ); + + i_status = avcodec_decode_video( p_vdec->p_context, + &avpicture, + &b_gotpicture, + p_vdec->p_framedata, + p_vdec->i_framesize); + + __NextFrame( p_vdec ); + + if( i_status < 0 ) + { + msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)", + p_vdec->i_framesize ); + p_vdec->i_frame_error++; + return; + } + /* Update frame late count*/ + /* I don't make statistic on decoding time */ + if( p_vdec->i_pts <= mdate()) + { + p_vdec->i_frame_late++; + } + else + { + p_vdec->i_frame_late = 0; + } + + if( !b_gotpicture || avpicture.linesize[0] == 0 || !b_drawpicture) + { + return; + } + + /* Check our vout */ + if( !ffmpeg_CheckVout( p_vdec->p_vout, + p_vdec->p_context->width, + p_vdec->p_context->height, + p_vdec->p_context->aspect_ratio_info, + ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)) ) + { + p_vdec->p_vout = + ffmpeg_CreateVout( p_vdec, + p_vdec->p_context->width, + p_vdec->p_context->height, + p_vdec->p_context->aspect_ratio_info, + ffmpeg_PixFmtToChroma(p_vdec->p_context->pix_fmt)); + if( !p_vdec->p_vout ) + { + msg_Err( p_vdec->p_fifo, "cannot create vout" ); + p_vdec->p_fifo->b_error = 1; /* abort */ + return; + } + } + + /* Send decoded frame to vout */ + while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) ) + { + if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + ffmpeg_ConvertPicture( p_pic, + &avpicture, + p_vdec ); + + + /* FIXME correct avi and use i_dts */ + vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->i_pts); + vout_DisplayPicture( p_vdec->p_vout, p_pic ); + + return; +} + + +/***************************************************************************** + * EndThread: thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +static void EndThread( videodec_thread_t *p_vdec ) +{ + if( !p_vdec ) + { + return; + } + + if( p_vdec->p_context != NULL) + { + avcodec_close( p_vdec->p_context ); + msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) stopped", + p_vdec->psz_namecodec ); + } + + if( p_vdec->p_vout != NULL ) + { + /* We are about to die. Reattach video output to p_vlc. */ + vlc_object_detach( p_vdec->p_vout, p_vdec->p_fifo ); + vlc_object_attach( p_vdec->p_vout, p_vdec->p_fifo->p_vlc ); + } + + if( p_vdec->format.p_data != NULL) + { + free( p_vdec->format.p_data ); + } + + free( p_vdec ); +} diff --git a/modules/codec/ffmpeg/ffmpeg.h b/modules/codec/ffmpeg/ffmpeg.h new file mode 100644 index 0000000000..09b3a7e83b --- /dev/null +++ b/modules/codec/ffmpeg/ffmpeg.h @@ -0,0 +1,220 @@ +/***************************************************************************** + * ffmpeg_vdec.h: video decoder using ffmpeg library + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: ffmpeg.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Laurent Aimar + * + * 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. + *****************************************************************************/ + +/* Pour un flux video */ +typedef struct bitmapinfoheader_s +{ + u32 i_size; /* size of header */ + u32 i_width; + u32 i_height; + u16 i_planes; + u16 i_bitcount; + u32 i_compression; + u32 i_sizeimage; + u32 i_xpelspermeter; + u32 i_ypelspermeter; + u32 i_clrused; + u32 i_clrimportant; + + int i_data; + u8 *p_data; + +} bitmapinfoheader_t; + +/* MPEG4 video */ +#define FOURCC_DIVX VLC_FOURCC('D','I','V','X') +#define FOURCC_divx VLC_FOURCC('d','i','v','x') +#define FOURCC_DIV1 VLC_FOURCC('D','I','V','1') +#define FOURCC_div1 VLC_FOURCC('d','i','v','1') +#define FOURCC_MP4S VLC_FOURCC('M','P','4','S') +#define FOURCC_mp4s VLC_FOURCC('m','p','4','s') +#define FOURCC_M4S2 VLC_FOURCC('M','4','S','2') +#define FOURCC_m4s2 VLC_FOURCC('m','4','s','2') +#define FOURCC_xvid VLC_FOURCC('x','v','i','d') +#define FOURCC_XVID VLC_FOURCC('X','V','I','D') +#define FOURCC_XviD VLC_FOURCC('X','v','i','D') +#define FOURCC_DX50 VLC_FOURCC('D','X','5','0') +#define FOURCC_mp4v VLC_FOURCC('m','p','4','v') +#define FOURCC_4 VLC_FOURCC( 4, 0, 0, 0 ) + +/* MSMPEG4 v2 */ +#define FOURCC_MPG4 VLC_FOURCC('M','P','G','4') +#define FOURCC_mpg4 VLC_FOURCC('m','p','g','4') +#define FOURCC_DIV2 VLC_FOURCC('D','I','V','2') +#define FOURCC_div2 VLC_FOURCC('d','i','v','2') +#define FOURCC_MP42 VLC_FOURCC('M','P','4','2') +#define FOURCC_mp42 VLC_FOURCC('m','p','4','2') + +/* MSMPEG4 v3 / M$ mpeg4 v3 */ +#define FOURCC_MPG3 VLC_FOURCC('M','P','G','3') +#define FOURCC_mpg3 VLC_FOURCC('m','p','g','3') +#define FOURCC_div3 VLC_FOURCC('d','i','v','3') +#define FOURCC_MP43 VLC_FOURCC('M','P','4','3') +#define FOURCC_mp43 VLC_FOURCC('m','p','4','3') + +/* DivX 3.20 */ +#define FOURCC_DIV3 VLC_FOURCC('D','I','V','3') +#define FOURCC_DIV4 VLC_FOURCC('D','I','V','4') +#define FOURCC_div4 VLC_FOURCC('d','i','v','4') +#define FOURCC_DIV5 VLC_FOURCC('D','I','V','5') +#define FOURCC_div5 VLC_FOURCC('d','i','v','5') +#define FOURCC_DIV6 VLC_FOURCC('D','I','V','6') +#define FOURCC_div6 VLC_FOURCC('d','i','v','6') + +/* AngelPotion stuff */ +#define FOURCC_AP41 VLC_FOURCC('A','P','4','1') + +/* ?? */ +#define FOURCC_3IV1 VLC_FOURCC('3','I','V','1') +#define FOURCC_3IV2 VLC_FOURCC('3','I','V','2') + +/* H263 and H263i */ +#define FOURCC_H263 VLC_FOURCC('H','2','6','3') +#define FOURCC_h263 VLC_FOURCC('h','2','6','3') +#define FOURCC_U263 VLC_FOURCC('U','2','6','3') +#define FOURCC_I263 VLC_FOURCC('I','2','6','3') +#define FOURCC_i263 VLC_FOURCC('i','2','6','3') + +/* Sorenson v1 */ +#define FOURCC_SVQ1 VLC_FOURCC( 'S', 'V', 'Q', '1' ) + +static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc, + int *pi_ffmpeg_codec, + char **ppsz_name ) +{ + int i_codec = 0; + char *psz_name = NULL; + + switch( i_fourcc ) + { +#if LIBAVCODEC_BUILD >= 4608 + case FOURCC_DIV1: + case FOURCC_div1: + case FOURCC_MPG4: + case FOURCC_mpg4: + i_codec = CODEC_ID_MSMPEG4V1; + psz_name = "MS MPEG-4 v1"; + break; + + case FOURCC_DIV2: + case FOURCC_div2: + case FOURCC_MP42: + case FOURCC_mp42: + i_codec = CODEC_ID_MSMPEG4V2; + psz_name = "MS MPEG-4 v2"; + break; +#endif + + case FOURCC_MPG3: + case FOURCC_mpg3: + case FOURCC_div3: + case FOURCC_MP43: + case FOURCC_mp43: + case FOURCC_DIV3: + case FOURCC_DIV4: + case FOURCC_div4: + case FOURCC_DIV5: + case FOURCC_div5: + case FOURCC_DIV6: + case FOURCC_div6: + case FOURCC_AP41: + case FOURCC_3IV1: +#if LIBAVCODEC_BUILD >= 4608 + i_codec = CODEC_ID_MSMPEG4V3; +#else + i_codec = CODEC_ID_MSMPEG4; +#endif + psz_name = "MS MPEG-4 v3"; + break; + +#if LIBAVCODEC_BUILD >= 4615 + case FOURCC_SVQ1: + i_codec = CODEC_ID_SVQ1; + psz_name = "SVQ-1 (Sorenson Video v1)"; + break; +#endif + + case FOURCC_DIVX: + case FOURCC_divx: + case FOURCC_MP4S: + case FOURCC_mp4s: + case FOURCC_M4S2: + case FOURCC_m4s2: + case FOURCC_xvid: + case FOURCC_XVID: + case FOURCC_XviD: + case FOURCC_DX50: + case FOURCC_mp4v: + case FOURCC_4: + case FOURCC_3IV2: + + i_codec = CODEC_ID_MPEG4; + psz_name = "MPEG-4"; + break; + + case FOURCC_H263: + case FOURCC_h263: + case FOURCC_U263: + i_codec = CODEC_ID_H263; + psz_name = "H263"; + break; + + case FOURCC_I263: + case FOURCC_i263: + i_codec = CODEC_ID_H263I; + psz_name = "I263.I"; + break; + } + + if( i_codec ) + { + if( pi_ffmpeg_codec ) *pi_ffmpeg_codec = i_codec; + if( ppsz_name ) *ppsz_name = psz_name; + return VLC_TRUE; + } + + return VLC_FALSE; +} + + +typedef struct videodec_thread_s +{ + decoder_fifo_t *p_fifo; + + bitmapinfoheader_t format; + + AVCodecContext context, *p_context; + AVCodec *p_codec; + vout_thread_t *p_vout; + + char *psz_namecodec; + /* private */ + mtime_t i_pts; + int i_framesize; + byte_t *p_framedata; + + int i_frame_error; + int i_frame_skip; + int i_frame_late; /* how may frame decoded are in late */ + +} videodec_thread_t; diff --git a/modules/codec/lpcm/.cvsignore b/modules/codec/lpcm/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/lpcm/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/lpcm/Makefile b/modules/codec/lpcm/Makefile new file mode 100644 index 0000000000..aa3a2403d1 --- /dev/null +++ b/modules/codec/lpcm/Makefile @@ -0,0 +1 @@ +lpcm_SOURCES = lpcm.c diff --git a/modules/codec/lpcm/lpcm.c b/modules/codec/lpcm/lpcm.c new file mode 100644 index 0000000000..9c08d8f1ec --- /dev/null +++ b/modules/codec/lpcm/lpcm.c @@ -0,0 +1,227 @@ +/***************************************************************************** + * lpcm.c: lpcm decoder module + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: lpcm.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Samuel Hocevar + * Henri Fallon + * + * 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 /* memcpy(), memset() */ +#include /* malloc(), free() */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include /* getpid() */ +#endif + +#include "lpcm.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); + + void DecodeFrame ( lpcmdec_thread_t * ); +static int InitThread ( lpcmdec_thread_t * ); +static void EndThread ( lpcmdec_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("linear PCM audio decoder") ); + set_capability( "decoder", 100 ); + set_callbacks( OpenDecoder, NULL ); +vlc_module_end(); + +/***************************************************************************** + * OpenDecoder: probe the decoder and return score + *****************************************************************************/ +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('l','p','c','m') ) + { + return VLC_EGENERIC; + } + + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; +} + +/***************************************************************************** + * RunDecoder: the lpcm decoder + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t * p_fifo ) +{ + lpcmdec_thread_t * p_lpcmdec; + + /* Allocate the memory needed to store the thread's structure */ + if( (p_lpcmdec = (lpcmdec_thread_t *)malloc (sizeof(lpcmdec_thread_t)) ) + == NULL) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + + /* + * Initialize the thread properties + */ + p_lpcmdec->p_fifo = p_fifo; + + if( InitThread( p_lpcmdec ) ) + { + DecoderError( p_fifo ); + free( p_lpcmdec ); + return( -1 ); + } + + /* lpcm decoder thread's main loop */ + while ((!p_lpcmdec->p_fifo->b_die) && (!p_lpcmdec->p_fifo->b_error)) + { + DecodeFrame(p_lpcmdec); + } + + /* If b_error is set, the lpcm decoder thread enters the error loop */ + if (p_lpcmdec->p_fifo->b_error) + { + DecoderError( p_lpcmdec->p_fifo ); + } + + /* End of the lpcm decoder thread */ + EndThread (p_lpcmdec); + + return( 0 ); +} + +/***************************************************************************** + * InitThread : initialize an lpcm decoder thread + *****************************************************************************/ +static int InitThread (lpcmdec_thread_t * p_lpcmdec) +{ + + /* Init the BitStream */ + InitBitstream( &p_lpcmdec->bit_stream, p_lpcmdec->p_fifo, + NULL, NULL); + + /* Creating the audio output fifo */ + p_lpcmdec->p_aout_fifo = + aout_CreateFifo( p_lpcmdec->p_fifo, AOUT_FIFO_PCM, + 2, 48000, LPCMDEC_FRAME_SIZE / 2, NULL ); + if ( p_lpcmdec->p_aout_fifo == NULL ) + { + return( -1 ); + } + return( 0 ); +} + +/***************************************************************************** + * DecodeFrame: decodes a frame. + *****************************************************************************/ +void DecodeFrame( lpcmdec_thread_t * p_lpcmdec ) +{ + byte_t * buffer,p_temp[LPCMDEC_FRAME_SIZE]; + vlc_bool_t b_sync; + int i_loop; + + CurrentPTS( &p_lpcmdec->bit_stream, + &p_lpcmdec->p_aout_fifo->date[p_lpcmdec->p_aout_fifo->i_end_frame], + NULL ); + if( !p_lpcmdec->p_aout_fifo->date[p_lpcmdec->p_aout_fifo->i_end_frame] ) + { + p_lpcmdec->p_aout_fifo->date[p_lpcmdec->p_aout_fifo->i_end_frame] = + LAST_MDATE; + } + + buffer = ((byte_t *)p_lpcmdec->p_aout_fifo->buffer) + + (p_lpcmdec->p_aout_fifo->i_end_frame * LPCMDEC_FRAME_SIZE); + + RemoveBits32(&p_lpcmdec->bit_stream); +#if 0 + byte1 = GetBits(&p_lpcmdec->bit_stream, 8) ; + byte2 = GetBits(&p_lpcmdec->bit_stream, 8) ; + + /* I only have 2 test streams. As far as I understand + * after the RemoveBits and the 2 GetBits, we should be exactly + * where we whant : the sync word : 0x0180. + * If not, we got and find it. */ + while( ( byte1 != 0x01 || byte2 != 0x80 ) && (!p_lpcmdec->p_fifo->b_die) + && (!p_lpcmdec->p_fifo->b_error) ) + { + byte1 = byte2; + byte2 = GetBits(&p_lpcmdec->bit_stream, 8); + } +#else + b_sync = 0; + while( ( !p_lpcmdec->p_fifo->b_die ) && + ( !p_lpcmdec->p_fifo->b_error ) && + ( !b_sync ) ) + { + while( ( !p_lpcmdec->p_fifo->b_die ) && + ( !p_lpcmdec->p_fifo->b_error ) && + ( GetBits( &p_lpcmdec->bit_stream, 8 ) != 0x01 ) ); + b_sync = ( ShowBits( &p_lpcmdec->bit_stream, 8 ) == 0x80 ); + } + RemoveBits( &p_lpcmdec->bit_stream, 8 ); +#endif + + GetChunk( &p_lpcmdec->bit_stream, p_temp, LPCMDEC_FRAME_SIZE); + if( p_lpcmdec->p_fifo->b_die || p_lpcmdec->p_fifo->b_error ) return; + + for( i_loop = 0; i_loop < LPCMDEC_FRAME_SIZE/2; i_loop++ ) + { + buffer[2*i_loop]=p_temp[2*i_loop+1]; + buffer[2*i_loop+1]=p_temp[2*i_loop]; + } + + vlc_mutex_lock (&p_lpcmdec->p_aout_fifo->data_lock); + p_lpcmdec->p_aout_fifo->i_end_frame = + (p_lpcmdec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE; + vlc_cond_signal (&p_lpcmdec->p_aout_fifo->data_wait); + vlc_mutex_unlock (&p_lpcmdec->p_aout_fifo->data_lock); +} + +/***************************************************************************** + * EndThread : lpcm decoder thread destruction + *****************************************************************************/ +static void EndThread( lpcmdec_thread_t * p_lpcmdec ) +{ + /* If the audio output fifo was created, we destroy it */ + if( p_lpcmdec->p_aout_fifo != NULL ) + { + aout_DestroyFifo( p_lpcmdec->p_aout_fifo ); + + /* Make sure the output thread leaves the NextFrame() function */ + vlc_mutex_lock( &(p_lpcmdec->p_aout_fifo->data_lock) ); + vlc_cond_signal( &(p_lpcmdec->p_aout_fifo->data_wait) ); + vlc_mutex_unlock( &(p_lpcmdec->p_aout_fifo->data_lock) ); + } + + /* Destroy descriptor */ + free( p_lpcmdec ); +} diff --git a/modules/codec/lpcm/lpcm.h b/modules/codec/lpcm/lpcm.h new file mode 100644 index 0000000000..9d37ac96c8 --- /dev/null +++ b/modules/codec/lpcm/lpcm.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * lpcm.h : lpcm decoder module + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: lpcm.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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-1307, USA. + *****************************************************************************/ +#define LPCMDEC_FRAME_SIZE (2008) + +/***************************************************************************** + * lpcmdec_thread_t : lpcm decoder thread descriptor + *****************************************************************************/ +typedef struct lpcmdec_thread_s +{ + /* + * Thread properties + */ + vlc_thread_t thread_id; /* id for thread functions */ + + /* + * Input properties + */ + decoder_fifo_t * p_fifo; /* stores the PES stream data */ + int sync_ptr; /* sync ptr from lpcm magic header */ + + /* + * Output properties + */ + aout_fifo_t * p_aout_fifo; /* stores the decompressed audio frames */ + + /* The bit stream structure handles the PES stream at the bit level */ + bit_stream_t bit_stream; + +} lpcmdec_thread_t; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +vlc_thread_t lpcmdec_CreateThread( decoder_fifo_t * p_fifo ); diff --git a/modules/codec/mad/.cvsignore b/modules/codec/mad/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/mad/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/mad/Makefile b/modules/codec/mad/Makefile new file mode 100644 index 0000000000..c5692341a9 --- /dev/null +++ b/modules/codec/mad/Makefile @@ -0,0 +1 @@ +mad_SOURCES = decoder.c libmad.c diff --git a/modules/codec/mad/decoder.c b/modules/codec/mad/decoder.c new file mode 100644 index 0000000000..628e95094d --- /dev/null +++ b/modules/codec/mad/decoder.c @@ -0,0 +1,239 @@ +/*************************************************************************** + decoder.c - description + ------------------- + Plugin Module definition for using libmad audio decoder in vlc. The + libmad codec uses integer arithmic only. This makes it suitable for using + it on architectures without a hardware FPU unit, such as the StrongArm + CPU. + + begin : Mon Nov 5 2001 + copyright : (C) 2001 by Jean-Paul Saman + email : jpsaman@wxs.nl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ +#include /* strdup() */ + +#include +#include +#include + +/***************************************************************************** + * Libmad include files * + *****************************************************************************/ +#include +#include "decoder.h" +#include "libmad.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( mad_adec_thread_t * p_mad_adec ); +static void EndThread ( mad_adec_thread_t * p_mad_adec ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define DOWNSCALE_TEXT N_("Mad audio downscale routine (fast,mp321)") +#define DOWNSCALE_LONGTEXT N_( \ + "Specify the mad audio downscale routine you want to use. By default " \ + "the mad plugin will use the fastest routine.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "downscale", "fast", NULL, DOWNSCALE_TEXT, DOWNSCALE_LONGTEXT ); + set_description( _("libmad MPEG 1/2/3 audio decoder") ); + set_capability( "decoder", 100 ); + 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('m','p','g','a') ) + { + 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 ) +{ + mad_adec_thread_t * p_mad_adec; + + /* Allocate the memory needed to store the thread's structure */ + p_mad_adec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t)); + + if (p_mad_adec == NULL) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + + /* + * Initialize the thread properties + */ + p_mad_adec->p_fifo = p_fifo; + if( InitThread( p_mad_adec ) ) + { + msg_Err( p_fifo, "could not initialize thread" ); + DecoderError( p_fifo ); + free( p_mad_adec ); + return( -1 ); + } + + /* mad decoder thread's main loop */ + while ((!p_mad_adec->p_fifo->b_die) && (!p_mad_adec->p_fifo->b_error)) + { + msg_Dbg( p_mad_adec->p_fifo, "starting libmad decoder" ); + if (mad_decoder_run(p_mad_adec->libmad_decoder, MAD_DECODER_MODE_SYNC)==-1) + { + msg_Err( p_mad_adec->p_fifo, "libmad decoder returned abnormally" ); + DecoderError( p_mad_adec->p_fifo ); + EndThread(p_mad_adec); + return( -1 ); + } + } + + /* If b_error is set, the mad decoder thread enters the error loop */ + if (p_mad_adec->p_fifo->b_error) + { + DecoderError( p_mad_adec->p_fifo ); + } + + /* End of the mad decoder thread */ + EndThread (p_mad_adec); + + return( 0 ); +} + +/***************************************************************************** + * InitThread: initialize data before entering main loop + *****************************************************************************/ +static int InitThread( mad_adec_thread_t * p_mad_adec ) +{ + decoder_fifo_t * p_fifo = p_mad_adec->p_fifo; + char *psz_downscale = NULL; + + /* + * Properties of audio for libmad + */ + + /* Look what scaling method was requested by the user */ + psz_downscale = config_GetPsz( p_fifo, "downscale" ); + + if ( strncmp(psz_downscale,"fast",4)==0 ) + { + p_mad_adec->audio_scaling = FAST_SCALING; + msg_Dbg( p_fifo, "downscale fast selected" ); + } + else if ( strncmp(psz_downscale,"mpg321",7)==0 ) + { + p_mad_adec->audio_scaling = MPG321_SCALING; + msg_Dbg( p_fifo, "downscale mpg321 selected" ); + } + else + { + p_mad_adec->audio_scaling = FAST_SCALING; + msg_Dbg( p_fifo, "downscale default fast selected" ); + } + + if (psz_downscale) free(psz_downscale); + + /* Initialize the libmad decoder structures */ + p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder)); + if (p_mad_adec->libmad_decoder == NULL) + { + msg_Err( p_mad_adec->p_fifo, "out of memory" ); + return -1; + } + p_mad_adec->i_current_pts = p_mad_adec->i_next_pts = 0; + + mad_decoder_init( p_mad_adec->libmad_decoder, + p_mad_adec, /* vlc's thread structure and p_fifo playbuffer */ + libmad_input, /* input_func */ + 0, /* header_func */ + 0, /* filter */ + libmad_output, /* output_func */ + 0, /* error */ + 0); /* message */ + + mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC); +// mad_timer_reset(&p_mad_adec->libmad_timer); + + /* + * Initialize the output properties + */ + p_mad_adec->p_aout_fifo = NULL; + + /* + * Initialize the input properties + */ + /* Get the first data packet. */ + vlc_mutex_lock( &p_fifo->data_lock ); + while ( p_fifo->p_first == NULL ) + { + if ( p_fifo->b_die ) + { + vlc_mutex_unlock( &p_fifo->data_lock ); + return( -1 ); + } + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + vlc_mutex_unlock( &p_fifo->data_lock ); + p_mad_adec->p_data = p_fifo->p_first->p_first; + + return( 0 ); +} + +/***************************************************************************** + * EndThread : libmad decoder thread destruction + *****************************************************************************/ +static void EndThread (mad_adec_thread_t * p_mad_adec) +{ + /* If the audio output fifo was created, we destroy it */ + if (p_mad_adec->p_aout_fifo != NULL) + { + aout_DestroyFifo (p_mad_adec->p_aout_fifo); + + /* Make sure the output thread leaves the NextFrame() function */ + vlc_mutex_lock (&(p_mad_adec->p_aout_fifo->data_lock)); + vlc_cond_signal (&(p_mad_adec->p_aout_fifo->data_wait)); + vlc_mutex_unlock (&(p_mad_adec->p_aout_fifo->data_lock)); + } + + /* mad_decoder_finish releases the memory allocated inside the struct */ + mad_decoder_finish( p_mad_adec->libmad_decoder ); + + /* Unlock the modules, p_mad_adec->p_fifo is released by the decoder subsystem */ + free( p_mad_adec->libmad_decoder ); + free( p_mad_adec ); +} + diff --git a/modules/codec/mad/decoder.h b/modules/codec/mad/decoder.h new file mode 100644 index 0000000000..3112cc59fe --- /dev/null +++ b/modules/codec/mad/decoder.h @@ -0,0 +1,63 @@ +/*************************************************************************** + mad_adec.h - description + ------------------- + begin : Mon Nov 5 2001 + copyright : (C) 2001 by Jean-Paul Saman + email : jpsaman@wxs.nl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _VLC_MAD_ADEC_H_ +#define _VLC_MAD_ADEC_H_ + +/***************************************************************************** + * mad_adec_thread_t : mad decoder thread descriptor + *****************************************************************************/ + +enum mad_scaling { FAST_SCALING, MPG321_SCALING }; + +typedef struct mad_adec_thread_s +{ + /* + * Decoder properties + */ + struct mad_decoder *libmad_decoder; + mad_timer_t libmad_timer; + byte_t buffer[MAD_BUFFER_MDLEN]; + + /* + * Thread properties + */ + vlc_thread_t thread_id; /* id for thread functions */ + + /* + * Input properties + */ + decoder_fifo_t * p_fifo; /* stores the PES stream data */ + data_packet_t * p_data; + + /* Store i_pts for syncing audio frames */ + mtime_t i_current_pts, i_next_pts; + + /* + * Output properties + */ + aout_fifo_t * p_aout_fifo; /* stores the decompressed audio frames */ + enum mad_scaling audio_scaling; + +} mad_adec_thread_t; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +vlc_thread_t mad_adec_CreateThread( decoder_fifo_t * p_fifo ); + +#endif diff --git a/modules/codec/mad/libmad.c b/modules/codec/mad/libmad.c new file mode 100644 index 0000000000..fe397edb7c --- /dev/null +++ b/modules/codec/mad/libmad.c @@ -0,0 +1,567 @@ +/*************************************************************************** + libmad.c - description + ------------------- + Functions that are called by libmad to communicate with vlc decoder + infrastructure. + + begin : Mon Nov 5 2001 + copyright : (C) 2001 by Jean-Paul Saman + email : jpsaman@wxs.nl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ +#include /* strdup() */ + +#include +#include +#include + +/***************************************************************************** + * Libmad includes files + *****************************************************************************/ +#include +#include "decoder.h" +#include "libmad.h" + +static void PrintFrameInfo(struct mad_header *Header); + +/***************************************************************************** + * libmad_input: this function is called by libmad when the input buffer needs + * to be filled. + *****************************************************************************/ +enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream) +{ + mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data; + size_t ReadSize, Remaining; + unsigned char *ReadStart; + + if ( p_mad_adec->p_fifo->b_die == 1 ) { + msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" ); + return MAD_FLOW_STOP; + } + + if ( p_mad_adec->p_fifo->b_error == 1 ) { + msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" ); + return MAD_FLOW_IGNORE; + } + + /* libmad_stream_buffer does not consume the total buffer, it consumes only data + * for one frame only. So all data left in the buffer should be put back in front. + */ + if ((p_libmad_stream->buffer==NULL) || (p_libmad_stream->error==MAD_ERROR_BUFLEN)) + { + /* libmad does not consume all the buffer it's given. Some + * datas, part of a truncated frame, is left unused at the + * end of the buffer. Those datas must be put back at the + * beginning of the buffer and taken in account for + * refilling the buffer. This means that the input buffer + * must be large enough to hold a complete frame at the + * highest observable bit-rate (currently 448 kb/s). XXX=XXX + * Is 2016 bytes the size of the largest frame? + * (448000*(1152/32000))/8 + */ + if(p_libmad_stream->next_frame!=NULL) + { + Remaining=p_libmad_stream->bufend-p_libmad_stream->next_frame; + if( p_mad_adec->buffer != p_libmad_stream->next_frame ) + { + memcpy( p_mad_adec->buffer, + p_libmad_stream->next_frame, Remaining ); + } + ReadStart=p_mad_adec->buffer+Remaining; + ReadSize=(MAD_BUFFER_MDLEN)-Remaining; + + /* Store time stamp of next frame */ + p_mad_adec->i_current_pts = p_mad_adec->i_next_pts; + p_mad_adec->i_next_pts = p_mad_adec->p_fifo->p_first->i_pts; + } + else + { + ReadSize=(MAD_BUFFER_MDLEN); + ReadStart=p_mad_adec->buffer; + Remaining=0; + p_mad_adec->i_next_pts = 0; + p_mad_adec->i_current_pts = p_mad_adec->p_fifo->p_first->i_pts; + } + + /* Fill-in the buffer. If an error occurs print a message + * and leave the decoding loop. If the end of stream is + * reached we also leave the loop but the return status is + * left untouched. + */ + if( ReadSize > p_mad_adec->p_data->p_payload_end + - p_mad_adec->p_data->p_payload_start ) + { + ReadSize = p_mad_adec->p_data->p_payload_end + - p_mad_adec->p_data->p_payload_start; + memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize ); + NextDataPacket( p_mad_adec->p_fifo, &p_mad_adec->p_data ); + } + else + { + memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize ); + p_mad_adec->p_data->p_payload_start += ReadSize; + } + + if ( p_mad_adec->p_fifo->b_die == 1 ) + { + msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" ); + return MAD_FLOW_STOP; + } + + if ( p_mad_adec->p_fifo->b_error == 1 ) + { + msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" ); + return MAD_FLOW_IGNORE; + } + + /* Pipe the new buffer content to libmad's stream decoder facility. + * Libmad never copies the buffer, but just references it. So keep it in + * mad_adec_thread_t structure. + */ + mad_stream_buffer(p_libmad_stream,(unsigned char*) &p_mad_adec->buffer, + Remaining + ReadSize); + p_libmad_stream->error=0; + } + + return MAD_FLOW_CONTINUE; +} + +/***************************************************************************** + * libmad_header: this function is called just after the header of a frame is + * decoded + *****************************************************************************/ +/* + *enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header) + *{ + * mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data; + * + * msg_Err( p_mad_adec->p_fifo, "libmad_header samplerate %d", p_libmad_header->samplerate); + * + * PrintFrameInfo(p_limad_mad_header) + * return MAD_FLOW_CONTINUE; + *} + */ + +/***************************************************************************** + * lib_mad_filter: this function is called to filter data of a frame + *****************************************************************************/ +/* enum mad_flow libmad_filter(void *data, struct mad_stream const *p_libmad_stream, struct mad_frame *p_libmad_frame) + * { + * return MAD_FLOW_CONTINUE; + * } + */ + +/***************************************************************************** + * support routines borrowed from mpg321 (file: mad.c), which is distributed + * under GPL license + * + * mpg321 was written by Joe Drew , and based upon 'plaympeg' + * from the smpeg sources, which was written by various people from Loki Software + * (http://www.lokigames.com). + * + * It also incorporates some source from mad, written by Robert Leslie + *****************************************************************************/ + +/* The following two routines and data structure are from the ever-brilliant + Rob Leslie. +*/ + +struct audio_dither { + mad_fixed_t error[3]; + mad_fixed_t random; +}; + +/* +* NAME: prng() +* DESCRIPTION: 32-bit pseudo-random number generator +*/ +static inline unsigned long prng(unsigned long state) +{ + return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; +} + +/* +* NAME: mpg321_s24_to_s16_pcm() +* DESCRIPTION: generic linear sample quantize and dither routine +*/ +static inline signed int mpg321_s24_to_s16_pcm(unsigned int bits, mad_fixed_t sample, + struct audio_dither *dither) +{ + unsigned int scalebits; + mad_fixed_t output, mask, random; + + enum { + MIN = -MAD_F_ONE, + MAX = MAD_F_ONE - 1 + }; + + /* noise shape */ + sample += dither->error[0] - dither->error[1] + dither->error[2]; + + dither->error[2] = dither->error[1]; + dither->error[1] = dither->error[0] / 2; + + /* bias */ + output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1)); + + scalebits = MAD_F_FRACBITS + 1 - bits; + mask = (1L << scalebits) - 1; + + /* dither */ + random = prng(dither->random); + output += (random & mask) - (dither->random & mask); + + dither->random = random; + + /* clip */ + if (output > MAX) { + output = MAX; + + if (sample > MAX) + sample = MAX; + } + else if (output < MIN) { + output = MIN; + + if (sample < MIN) + sample = MIN; + } + + /* quantize */ + output &= ~mask; + + /* error feedback */ + dither->error[0] = sample - output; + + /* scale */ + return output >> scalebits; +} + +/***************************************************************************** + * s24_to_s16_pcm: Scale a 24 bit pcm sample to a 16 bit pcm sample. + *****************************************************************************/ +static inline mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample) +{ + /* round */ + sample += (1L << (MAD_F_FRACBITS - 16)); + + /* clip */ + if (sample >= MAD_F_ONE) + sample = MAD_F_ONE - 1; + else if (sample < -MAD_F_ONE) + sample = -MAD_F_ONE; + + /* quantize */ + return sample >> (MAD_F_FRACBITS + 1 - 16); +} + +/***************************************************************************** + * libmad_ouput: this function is called just after the frame is decoded + *****************************************************************************/ +enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm) +{ + mad_adec_thread_t *p_mad_adec= (mad_adec_thread_t *) data; + byte_t *buffer=NULL; + mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1]; + register int nsamples = p_libmad_pcm->length; + mad_fixed_t sample; + static struct audio_dither dither; + + /* Creating the audio output fifo. + * Assume the samplerate and nr of channels from the first decoded frame is right for the entire audio track. + */ + if (p_mad_adec->p_aout_fifo==NULL) + { + p_mad_adec->p_aout_fifo = aout_CreateFifo( + p_mad_adec->p_fifo, + AOUT_FIFO_PCM, /* fifo type */ + 2, /*p_libmad_pcm->channels,*/ /* nr. of channels */ + p_libmad_pcm->samplerate, /* frame rate in Hz ?*/ + p_libmad_pcm->length*2, /* length of output buffer *2 channels*/ + NULL ); /* buffer */ + + if ( p_mad_adec->p_aout_fifo == NULL ) + { + return MAD_FLOW_BREAK; + } + + msg_Dbg( p_mad_adec->p_fifo, "aout fifo created"); + } + + if (p_mad_adec->p_aout_fifo->i_rate != p_libmad_pcm->samplerate) + { + msg_Warn( p_mad_adec->p_fifo, "samplerate is changing from [%d] Hz " + "to [%d] Hz, sample size [%d], error_code [%0x]", + p_mad_adec->p_aout_fifo->i_rate, p_libmad_pcm->samplerate, + p_libmad_pcm->length, + p_mad_adec->libmad_decoder->sync->stream.error ); + p_mad_adec->p_aout_fifo->i_rate = p_libmad_pcm->samplerate; + } + + if( p_mad_adec->i_current_pts ) + { + p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame] + = p_mad_adec->i_current_pts; + } + else + { + p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame] + = LAST_MDATE; + } +// mad_timer_add(&p_mad_adec->libmad_timer,p_libmad_header->duration); + + buffer = ((byte_t *)p_mad_adec->p_aout_fifo->buffer) + (p_mad_adec->p_aout_fifo->i_end_frame * (p_libmad_pcm->length*4)); + + while (nsamples--) + { + switch (p_mad_adec->audio_scaling) + { + case MPG321_SCALING: + sample = mpg321_s24_to_s16_pcm(16, *left_ch++, &dither); + break; + case FAST_SCALING: /* intended fall through */ + default: + sample = s24_to_s16_pcm(*left_ch++); + break; + } + + /* left audio channel */ +#ifndef WORDS_BIGENDIAN + *buffer++ = (byte_t) (sample >> 0); + *buffer++ = (byte_t) (sample >> 8); +#else + *buffer++ = (byte_t) (sample >> 8); + *buffer++ = (byte_t) (sample >> 0); +#endif + if (p_libmad_pcm->channels == 2) + { + /* right audio channel */ + switch (p_mad_adec->audio_scaling) + { + case MPG321_SCALING: + sample = mpg321_s24_to_s16_pcm(16, *right_ch++, &dither); + break; + case FAST_SCALING: /* intended fall through */ + default: + sample = s24_to_s16_pcm(*right_ch++); + break; + } + } + /* else reuse left_ch */ +#ifndef WORDS_BIGENDIAN + *buffer++ = (byte_t) (sample >> 0); + *buffer++ = (byte_t) (sample >> 8); +#else + *buffer++ = (byte_t) (sample >> 8); + *buffer++ = (byte_t) (sample >> 0); +#endif + } + + /* DEBUG */ + /* + if (p_libmad_pcm->channels == 1) { + msg_Dbg( p_mad_adec->p_fifo, "libmad_output channels [%d]", p_libmad_pcm->channels); + } + */ + + vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock); + p_mad_adec->p_aout_fifo->i_end_frame = (p_mad_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE; + vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait); + vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock); + + return MAD_FLOW_CONTINUE; +} + +/***************************************************************************** + * libmad_error: this function is called when an error occurs during decoding + *****************************************************************************/ +enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struct mad_frame *p_libmad_frame) +{ + enum mad_flow result = MAD_FLOW_CONTINUE; + + switch (p_libmad_stream->error) + { + case MAD_ERROR_BUFLEN: /* input buffer too small (or EOF) */ +//X intf_ErrMsg("libmad error: input buffer too small (or EOF)"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BUFPTR: /* invalid (null) buffer pointer */ +//X intf_ErrMsg("libmad error: invalid (null) buffer pointer"); + result = MAD_FLOW_STOP; + break; + case MAD_ERROR_NOMEM: /* not enough memory */ +//X intf_ErrMsg("libmad error: invalid (null) buffer pointer"); + result = MAD_FLOW_STOP; + break; + case MAD_ERROR_LOSTSYNC: /* lost synchronization */ +//X intf_ErrMsg("libmad error: lost synchronization"); + mad_stream_sync(p_libmad_stream); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADLAYER: /* reserved header layer value */ +//X intf_ErrMsg("libmad error: reserved header layer value"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADBITRATE: /* forbidden bitrate value */ +//X intf_ErrMsg("libmad error: forbidden bitrate value"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADSAMPLERATE: /* reserved sample frequency value */ +//X intf_ErrMsg("libmad error: reserved sample frequency value"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADEMPHASIS: /* reserved emphasis value */ +//X intf_ErrMsg("libmad error: reserverd emphasis value"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADCRC: /* CRC check failed */ +//X intf_ErrMsg("libmad error: CRC check failed"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADBITALLOC: /* forbidden bit allocation value */ +//X intf_ErrMsg("libmad error: forbidden bit allocation value"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADSCALEFACTOR:/* bad scalefactor index */ +//X intf_ErrMsg("libmad error: bad scalefactor index"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADFRAMELEN: /* bad frame length */ +//X intf_ErrMsg("libmad error: bad frame length"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADBIGVALUES: /* bad big_values count */ +//X intf_ErrMsg("libmad error: bad big values count"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADBLOCKTYPE: /* reserved block_type */ +//X intf_ErrMsg("libmad error: reserverd block_type"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADSCFSI: /* bad scalefactor selection info */ +//X intf_ErrMsg("libmad error: bad scalefactor selection info"); + result = MAD_FLOW_CONTINUE; + break; + case MAD_ERROR_BADDATAPTR: /* bad main_data_begin pointer */ +//X intf_ErrMsg("libmad error: bad main_data_begin pointer"); + result = MAD_FLOW_STOP; + break; + case MAD_ERROR_BADPART3LEN: /* bad audio data length */ +//X intf_ErrMsg("libmad error: bad audio data length"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADHUFFTABLE: /* bad Huffman table select */ +//X intf_ErrMsg("libmad error: bad Huffman table select"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADHUFFDATA: /* Huffman data overrun */ +//X intf_ErrMsg("libmad error: Huffman data overrun"); + result = MAD_FLOW_IGNORE; + break; + case MAD_ERROR_BADSTEREO: /* incompatible block_type for JS */ +//X intf_ErrMsg("libmad error: incompatible block_type for JS"); + result = MAD_FLOW_IGNORE; + break; + default: +//X intf_ErrMsg("libmad error: unknown error occured stopping decoder"); + result = MAD_FLOW_STOP; + break; + } + + return (MAD_RECOVERABLE(p_libmad_stream->error)? result: MAD_FLOW_STOP); + //return (MAD_FLOW_CONTINUE); +} + +/***************************************************************************** + * libmad_message: this function is called to send a message + *****************************************************************************/ +/* enum mad_flow libmad_message(void *, void*, unsigned int*) + * { + * return MAD_FLOW_CONTINUE; + * } + */ + + + +/**************************************************************************** + * Print human readable informations about an audio MPEG frame. * + ****************************************************************************/ +static void PrintFrameInfo(struct mad_header *Header) +{ + const char *Layer, + *Mode, + *Emphasis; + + /* Convert the layer number to it's printed representation. */ + switch(Header->layer) + { + case MAD_LAYER_I: + Layer="I"; + break; + case MAD_LAYER_II: + Layer="II"; + break; + case MAD_LAYER_III: + Layer="III"; + break; + default: + Layer="(unexpected layer value)"; + break; + } + + /* Convert the audio mode to it's printed representation. */ + switch(Header->mode) + { + case MAD_MODE_SINGLE_CHANNEL: + Mode="single channel"; + break; + case MAD_MODE_DUAL_CHANNEL: + Mode="dual channel"; + break; + case MAD_MODE_JOINT_STEREO: + Mode="joint (MS/intensity) stereo"; + break; + case MAD_MODE_STEREO: + Mode="normal LR stereo"; + break; + default: + Mode="(unexpected mode value)"; + break; + } + + /* Convert the emphasis to it's printed representation. */ + switch(Header->emphasis) + { + case MAD_EMPHASIS_NONE: + Emphasis="no"; + break; + case MAD_EMPHASIS_50_15_US: + Emphasis="50/15 us"; + break; + case MAD_EMPHASIS_CCITT_J_17: + Emphasis="CCITT J.17"; + break; + default: + Emphasis="(unexpected emphasis value)"; + break; + } + +//X intf_ErrMsg("statistics: %lu kb/s audio mpeg layer %s stream %s crc, " +//X "%s with %s emphasis at %d Hz sample rate\n", +//X Header->bitrate,Layer, +//X Header->flags&MAD_FLAG_PROTECTION?"with":"without", +//X Mode,Emphasis,Header->samplerate); +} diff --git a/modules/codec/mad/libmad.h b/modules/codec/mad/libmad.h new file mode 100644 index 0000000000..20dbca9366 --- /dev/null +++ b/modules/codec/mad/libmad.h @@ -0,0 +1,51 @@ +/*************************************************************************** + mad_libmad.h - description + ------------------- + begin : Mon Nov 5 2001 + copyright : (C) 2001 by Jean-Paul Saman + email : jpsaman@wxs.nl + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef _VLC_MAD_LIBMAD_H_ +#define _VLC_MAD_LIBMAD_H_ + +/* + * Function prototypes for libmad callback functions. + */ + +/* + * Each of the following functions will return one of: + * MAD_FLOW_CONTINUE = continue normally + * MAD_FLOW_STOP = stop decoding normally + * MAD_FLOW_BREAK = stop decoding and signal an error + * MAD_FLOW_IGNORE = ignore the current frame + */ + +/* enum mad_flow (*input_func)(void *, struct mad_stream *);*/ +enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream); + +/* enum mad_flow (*header_func)(void *, struct mad_header const *);*/ +enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header); + +/* enum mad_flow (*filter_func)(void *, struct mad_stream const *, struct mad_frame *); */ +// enum mad_flow libmad_filter(void *data, struct mad_stream const *p_libmad_stream, struct mad_frame *p_libmad_frame); + +/* enum mad_flow (*output_func)(void *, struct mad_header const *, struct mad_pcm *); */ +enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm); + +/* enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); */ +enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struct mad_frame *p_libmad_frame); + +/* enum mad_flow (*message_func)(void *, void *, unsigned int *); */ +/* enum mad_flow libmad_message(void *, void*, unsigned int*); */ + +#endif diff --git a/modules/codec/mpeg_audio/.cvsignore b/modules/codec/mpeg_audio/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/mpeg_audio/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/mpeg_audio/Makefile b/modules/codec/mpeg_audio/Makefile new file mode 100644 index 0000000000..6a1d52a870 --- /dev/null +++ b/modules/codec/mpeg_audio/Makefile @@ -0,0 +1 @@ +mpeg_audio_SOURCES = decoder.c layer1.c layer2.c math.c generic.c diff --git a/modules/codec/mpeg_audio/decoder.c b/modules/codec/mpeg_audio/decoder.c new file mode 100644 index 0000000000..627c68180b --- /dev/null +++ b/modules/codec/mpeg_audio/decoder.c @@ -0,0 +1,235 @@ +/***************************************************************************** + * decoder.c: MPEG audio decoder thread + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: decoder.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * Samuel Hocevar + * Cyril Deguet + * + * 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 /* malloc(), free() */ +#include + +#include +#include +#include + +#include "generic.h" +#include "decoder.h" + +#define ADEC_FRAME_SIZE (2*1152) + +/***************************************************************************** + * Local Prototypes + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); + +static void EndThread ( adec_thread_t * ); +static void DecodeThread ( adec_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MPEG I/II layer 1/2 audio decoder") ); + set_capability( "decoder", 50 ); + add_requirement( FPU ); + add_shortcut( "builtin" ); + 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('m','p','g','a') ) + { + return VLC_EGENERIC; + } + + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; +} + +/***************************************************************************** + * RunDecoder: initialize, go inside main loop, destroy + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t *p_fifo ) +{ + adec_thread_t * p_adec; + + /* Allocate the memory needed to store the thread's structure */ + if ( (p_adec = (adec_thread_t *)malloc (sizeof(adec_thread_t))) == NULL ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return 0; + } + + /* + * Initialize the thread properties + */ + p_adec->p_fifo = p_fifo; + + /* + * Initilize the banks + */ + p_adec->bank_0.actual = p_adec->bank_0.v1; + p_adec->bank_0.pos = 0; + p_adec->bank_1.actual = p_adec->bank_1.v1; + p_adec->bank_1.pos = 0; + + /* + * Initialize bit stream + */ + InitBitstream( &p_adec->bit_stream, p_adec->p_fifo, NULL, NULL ); + + /* We do not create the audio output fifo now, but + it will be created when the first frame is received */ + p_adec->p_aout_fifo = NULL; + + p_adec->i_sync = 0; + + /* Audio decoder thread's main loop */ + while( (!p_adec->p_fifo->b_die) && (!p_adec->p_fifo->b_error) ) + { + DecodeThread( p_adec ); + } + + /* If b_error is set, the audio decoder thread enters the error loop */ + if( p_adec->p_fifo->b_error ) + { + DecoderError( p_adec->p_fifo ); + } + + /* End of the audio decoder thread */ + EndThread( p_adec ); + + return( 0 ); +} + +/* + * Following functions are local to this module + */ + +/***************************************************************************** + * DecodeThread: decodes a mpeg frame + *****************************************************************************/ +static void DecodeThread( adec_thread_t * p_adec ) +{ + s16 *p_buffer; + adec_sync_info_t sync_info; + + if( ! adec_SyncFrame (p_adec, &sync_info) ) + { + + /* TODO: check if audio type has changed */ + + /* Create the output fifo if it doesn't exist yet */ + if( p_adec->p_aout_fifo == NULL ) + { + int i_channels; + + if( !config_GetInt( p_adec->p_fifo, "mono" ) ) + { + msg_Dbg( p_adec->p_fifo, "setting stereo output" ); + i_channels = 2; + } + else if( sync_info.b_stereo ) + { + i_channels = 2; + } + else + { + i_channels = 1; + } + p_adec->p_aout_fifo = + aout_CreateFifo( p_adec->p_fifo, AOUT_FIFO_PCM, i_channels, + sync_info.sample_rate, ADEC_FRAME_SIZE, NULL ); + if( p_adec->p_aout_fifo == NULL) + { + msg_Err( p_adec->p_fifo, "failed to create aout fifo" ); + p_adec->p_fifo->b_error = 1; + return; + } + } + + p_adec->i_sync = 1; + + p_buffer = ((s16 *)p_adec->p_aout_fifo->buffer) + + (p_adec->p_aout_fifo->i_end_frame * ADEC_FRAME_SIZE); + + CurrentPTS( &p_adec->bit_stream, + &p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame], + NULL ); + if( !p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] ) + { + p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] = + LAST_MDATE; + } + + if( adec_DecodeFrame (p_adec, p_buffer) ) + { + /* Ouch, failed decoding... We'll have to resync */ + p_adec->i_sync = 0; + } + else + { + vlc_mutex_lock (&p_adec->p_aout_fifo->data_lock); + p_adec->p_aout_fifo->i_end_frame = + (p_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE; + vlc_cond_signal (&p_adec->p_aout_fifo->data_wait); + vlc_mutex_unlock (&p_adec->p_aout_fifo->data_lock); + } + } +} + +/***************************************************************************** + * EndThread : audio decoder thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +static void EndThread ( adec_thread_t *p_adec ) +{ + /* If the audio output fifo was created, we destroy it */ + if ( p_adec->p_aout_fifo != NULL ) + { + aout_DestroyFifo ( p_adec->p_aout_fifo ); + + /* Make sure the output thread leaves the NextFrame() function */ + vlc_mutex_lock (&(p_adec->p_aout_fifo->data_lock)); + vlc_cond_signal (&(p_adec->p_aout_fifo->data_wait)); + vlc_mutex_unlock (&(p_adec->p_aout_fifo->data_lock)); + } + /* Destroy descriptor */ + free( p_adec ); +} + diff --git a/modules/codec/mpeg_audio/decoder.h b/modules/codec/mpeg_audio/decoder.h new file mode 100644 index 0000000000..f7fb759248 --- /dev/null +++ b/modules/codec/mpeg_audio/decoder.h @@ -0,0 +1,65 @@ +/***************************************************************************** + * mpeg_adec.h : audio decoder thread interface + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: decoder.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * adec_thread_t : audio decoder thread descriptor + *****************************************************************************/ +typedef struct adec_thread_s +{ + /* + * Sync Information + */ + int i_sync; + /* + * 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_read_bits; + + /* + * Decoder properties + */ + u32 header; + int frame_size; + adec_bank_t bank_0; + adec_bank_t bank_1; + + /* + * Output properties + */ + aout_fifo_t * p_aout_fifo; /* stores the decompressed frames */ + +} adec_thread_t; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ + +/* + * From adec_generic.c + */ +int adec_SyncFrame( adec_thread_t *, adec_sync_info_t * ); +int adec_DecodeFrame( adec_thread_t * , s16 * ); + diff --git a/modules/codec/mpeg_audio/generic.c b/modules/codec/mpeg_audio/generic.c new file mode 100644 index 0000000000..17592fbd82 --- /dev/null +++ b/modules/codec/mpeg_audio/generic.c @@ -0,0 +1,252 @@ +/***************************************************************************** + * generic.c: MPEG audio decoder + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: generic.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * Cyril Deguet + * + * 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 /* memcpy(), memset() */ + +#include +#include + +#include "generic.h" +#include "decoder.h" +#include "math.h" /* DCT32(), PCM() */ +#include "layer1.h" +#include "layer2.h" + +int adec_Init( adec_thread_t * p_adec ) +{ + p_adec->bank_0.actual = p_adec->bank_0.v1; + p_adec->bank_0.pos = 0; + p_adec->bank_1.actual = p_adec->bank_1.v1; + p_adec->bank_1.pos = 0; + return 0; +} + +int adec_SyncFrame( adec_thread_t * p_adec, adec_sync_info_t * p_sync_info ) +{ + static int mpeg1_sample_rate[3] = {44100, 48000, 32000}; + static int mpeg1_layer1_bit_rate[15] = + { + 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 + }; + static int mpeg1_layer2_bit_rate[15] = + { + 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 + }; + static int mpeg2_layer1_bit_rate[15] = + { + 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 + }; + static int mpeg2_layer2_bit_rate[15] = + { + 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 + }; + static int * bit_rate_table[8] = + { + NULL, NULL, mpeg2_layer2_bit_rate, mpeg2_layer1_bit_rate, + NULL, NULL, mpeg1_layer2_bit_rate, mpeg1_layer1_bit_rate + }; + + u32 header; + int index; + int * bit_rates; + int sample_rate; + int bit_rate; + int frame_size; + + /* We read the whole header, but only really take 8 bits */ + header = GetBits( &p_adec->bit_stream, 8 ) << 24; + header |= ShowBits( &p_adec->bit_stream, 24 ); + + p_adec->header = header; + + /* basic header check : sync word */ + if( (header & 0xfff00000) != 0xfff00000 ) + { + return 1; + } + + /* calculate bit rate */ + index = ( header >> 17 ) & 7; /* mpeg ID + layer */ + bit_rates = bit_rate_table[ index ]; + if( bit_rates == NULL ) + { + return 1; /* invalid layer */ + } + + index = ( header >> 12 ) & 15; /* bit rate index */ + if (index > 14) + { + return 1; + } + bit_rate = bit_rates[ index ]; + + /* mpeg 1 layer 2 : check that bitrate per channel is valid */ + + if( bit_rates == mpeg1_layer2_bit_rate ) + { + if( (header & 0xc0) == 0xc0 ) + { /* mono */ + if( index > 10 ) + { + return 1; /* invalid bitrate per channel */ + } + } + else + { /* stereo */ + if( (1 << index) & 0x2e ) + { + return 1; /* invalid bitrate per channel */ + } + } + } + + /* calculate sample rate */ + + index = ( header >> 10 ) & 3; /* sample rate index */ + if( index > 2 ) + { + return 1; + } + + sample_rate = mpeg1_sample_rate[ index ]; + + if( ! (header & 0x80000) ) + { + sample_rate >>= 1; /* half sample rate for mpeg2 */ + } + + /* calculate frame length */ + + if( (header & 0x60000) == 0x60000 ) + { + /* layer 1 */ + frame_size = 48000 * bit_rate / sample_rate; + + /* padding */ + if( header & 0x200 ) + { + frame_size += 4; + } + } + else + { + /* layer >1 */ + frame_size = 144000 * bit_rate / sample_rate; + + /* padding */ + if( header & 0x200 ) + { + frame_size ++; + } + } + + /* Now we are sure we want this header, read it */ + RemoveBits( &p_adec->bit_stream, 24 ); + p_adec->i_read_bits = 32; + + if( ! (p_adec->header & 0x10000) ) + { + /* Error check, skip it */ + RemoveBits( &p_adec->bit_stream, 16 ); + p_adec->i_read_bits += 16; + } + + p_sync_info->b_stereo = ((p_adec->header & 0xc0) != 0xc0); + p_sync_info->sample_rate = sample_rate; + p_sync_info->bit_rate = bit_rate; + p_sync_info->frame_size = frame_size; + p_adec->frame_size = frame_size; + + return 0; +} + +int adec_DecodeFrame( adec_thread_t * p_adec, s16 * buffer ) +{ + int i_total_bytes_read; + + /* parse audio data */ + + switch( (p_adec->header >> 17) & 3 ) + { + case 2: + /* layer 2 */ + if( (p_adec->header & 0xc0) == 0xc0 ) + { + if( adec_layer2_mono (p_adec, buffer) ) + { + return 1; + } + } + else + { + if( adec_layer2_stereo (p_adec, buffer) ) + { + return 1; + } + } + break; + + case 3: + /* layer 1 */ + if( (p_adec->header & 0xc0) == 0xc0 ) + { + if( adec_layer1_mono (p_adec, buffer) ) + { + return 1; + } + } + else + { + if( adec_layer1_stereo (p_adec, buffer) ) + { + return 1; + } + } + break; + } + + /* Skip ancillary data */ + + if( (p_adec->header & 0xf000) == 0 ) /* free bitrate format */ + { + return 0; + } + + RealignBits( &p_adec->bit_stream ); + i_total_bytes_read = ( p_adec->i_read_bits + 7 ) / 8; + + if( i_total_bytes_read > p_adec->frame_size ) + { + return 1; /* overrun */ + } + + while( i_total_bytes_read++ < p_adec->frame_size ) + { + RemoveBits( &p_adec->bit_stream, 8 ); /* skip ancillary data */ + } + + return 0; +} + diff --git a/modules/codec/mpeg_audio/generic.h b/modules/codec/mpeg_audio/generic.h new file mode 100644 index 0000000000..b6f5dc35c8 --- /dev/null +++ b/modules/codec/mpeg_audio/generic.h @@ -0,0 +1,44 @@ +/***************************************************************************** + * audio_decoder.h : audio decoder interface + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: generic.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * + * 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. + *****************************************************************************/ + +/**** audio decoder API - public audio decoder structures */ + +typedef struct audiodec_s audiodec_t; + +typedef struct adec_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 */ + int b_stereo; /* mono/stereo */ +} adec_sync_info_t; + +typedef struct adec_bank_s +{ + float v1[512]; + float v2[512]; + float * actual; + int pos; + +} adec_bank_t; + + diff --git a/modules/codec/mpeg_audio/layer1.c b/modules/codec/mpeg_audio/layer1.c new file mode 100644 index 0000000000..18ebc77825 --- /dev/null +++ b/modules/codec/mpeg_audio/layer1.c @@ -0,0 +1,350 @@ +/***************************************************************************** + * layer1.c: MPEG Layer I audio decoder + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: layer1.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * + * 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 /* NULL */ +#include /* memcpy(), memset() */ + +#include +#include + +#include "generic.h" +#include "decoder.h" +#include "math.h" /* DCT32(), PCM() */ + +/**** wkn ****/ + +static float adec_scalefactor_table[64] = +{ /* 2 ^ (1 - i/3) */ + 2.0000000000000000, 1.5874010519681994, 1.2599210498948732, + 1.0000000000000000, 0.7937005259840998, 0.6299605249474366, + 0.5000000000000000, 0.3968502629920499, 0.3149802624737183, + 0.2500000000000000, 0.1984251314960249, 0.1574901312368591, + 0.1250000000000000, 0.0992125657480125, 0.0787450656184296, + 0.0625000000000000, 0.0496062828740062, 0.0393725328092148, + 0.0312500000000000, 0.0248031414370031, 0.0196862664046074, + 0.0156250000000000, 0.0124015707185016, 0.0098431332023037, + 0.0078125000000000, 0.0062007853592508, 0.0049215666011518, + 0.0039062500000000, 0.0031003926796254, 0.0024607833005759, + 0.0019531250000000, 0.0015501963398127, 0.0012303916502880, + 0.0009765625000000, 0.0007750981699063, 0.0006151958251440, + 0.0004882812500000, 0.0003875490849532, 0.0003075979125720, + 0.0002441406250000, 0.0001937745424766, 0.0001537989562860, + 0.0001220703125000, 0.0000968872712383, 0.0000768994781430, + 0.0000610351562500, 0.0000484436356191, 0.0000384497390715, + 0.0000305175781250, 0.0000242218178096, 0.0000192248695357, + 0.0000152587890625, 0.0000121109089048, 0.0000096124347679, + 0.0000076293945312, 0.0000060554544524, 0.0000048062173839, + 0.0000038146972656, 0.0000030277272262, 0.0000024031086920, + 0.0000019073486328, 0.0000015138636131, 0.0000012015543460, + 0.0000009536743164 /* last element is not in the standard... invalid ??? */ +}; + +static float adec_slope_table[15] = +{ + 0.6666666666666666, 0.2857142857142857, 0.1333333333333333, + 0.0645161290322581, 0.0317460317460317, 0.0157480314960630, + 0.0078431372549020, 0.0039138943248532, 0.0019550342130987, + 0.0009770395701026, 0.0004884004884005, 0.0002441704309608, + 0.0001220777635354, 0.0000610370189520, 0.0000305180437934 +}; + +static float adec_offset_table[15] = +{ + -0.6666666666666666, -0.8571428571428571, -0.9333333333333333, + -0.9677419354838710, -0.9841269841269841, -0.9921259842519685, + -0.9960784313725490, -0.9980430528375733, -0.9990224828934506, + -0.9995114802149487, -0.9997557997557998, -0.9998779147845196, + -0.9999389611182323, -0.9999694814905240, -0.9999847409781033 +}; + +static u8 adec_layer1_allocation_table[15] = +{ + 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +static int adec_bound_table[4] = { 4, 8, 12, 16 }; + +int adec_layer1_mono( adec_thread_t * p_adec, s16 * buffer ) +{ + u8 allocation[32]; + float slope[32]; + float offset[32]; + float sample[32]; + + int i_sb; + int s; + int i_read_bits = 0; + + /* + * Parse the allocation tables + */ + + for (i_sb = 0; i_sb < 32; i_sb += 2) + { + u8 tmp; + + /* i_read_bits will be updated at the end of the loop */ + tmp = GetBits ( &p_adec->bit_stream, 8 ); + + if ( (tmp >> 4) > 14 ) + { + return 1; + } + + allocation[i_sb] = adec_layer1_allocation_table [tmp >> 4]; + + if ((tmp & 15) > 14) + { + return 1; + } + + allocation[i_sb+1] = adec_layer1_allocation_table [tmp & 15]; + } + + i_read_bits += 8 * 16; /* we did 16 iterations */ + + /* + * Parse scalefactors + */ + + for ( i_sb = 0; i_sb < 32; i_sb++ ) + { + if ( allocation[i_sb] ) + { + int index; + float scalefactor; + + index = GetBits( &p_adec->bit_stream, 6); + + /* We also add the bits we'll take later in the sample parsing */ + i_read_bits += 6 + 12 * allocation[i_sb]; + + scalefactor = adec_scalefactor_table[index]; + + slope[i_sb] = adec_slope_table[allocation[i_sb]-2] * scalefactor; + offset[i_sb] = adec_offset_table[allocation[i_sb]-2] * scalefactor; + } + } + + /* + * Parse samples + */ + + for ( s = 0 ; s < 12; s++) + { + for (i_sb = 0; i_sb < 32; i_sb++) + { + if (!allocation[i_sb]) + { + sample[i_sb] = 0; + } + else + { + int code; + + /* The bits were already counted in the scalefactors parsing */ + code = GetBits( &p_adec->bit_stream, allocation[i_sb] ); + + sample[i_sb] = slope[i_sb] * code + offset[i_sb]; + } + } + + DCT32( &p_adec->bank_0, sample ); + PCM (&p_adec->bank_0, buffer, 1); + buffer += 32; + } + + p_adec->i_read_bits += i_read_bits; + + return 0; +} + +int adec_layer1_stereo( adec_thread_t * p_adec, s16 * buffer ) +{ + u8 allocation_0[32], allocation_1[32]; + float slope_0[32], slope_1[32]; + float offset_0[32], offset_1[32]; + float sample_0[32], sample_1[32]; + + int bound; + int i_sb; + int s; + int i_read_bits = 0; + + /* + * Calculate bound + */ + + bound = 32; + if ( (p_adec->header & 0xc0) == 0x40) + { + /* intensity stereo */ + int index; + index = (p_adec->header >> 4) & 3; + bound = adec_bound_table[index]; + } + + /* + * Parse allocation + */ + + for (i_sb = 0; i_sb < bound; i_sb++) + { + u8 tmp; + tmp = GetBits( &p_adec->bit_stream, 8 ); + if ((tmp >> 4) > 14) + { + return 1; + } + allocation_0[i_sb] = adec_layer1_allocation_table [tmp >> 4]; + if ((tmp & 15) > 14) + { + return 1; + } + allocation_1[i_sb] = adec_layer1_allocation_table [tmp & 15]; + } + + for (; i_sb < 32; i_sb += 2) + { + u8 tmp; + tmp = GetBits( &p_adec->bit_stream, 8 ); + + if ((tmp >> 4) > 14) + { + return 1; + } + allocation_0[i_sb] = allocation_1[i_sb] + = adec_layer1_allocation_table [tmp >> 4]; + + if ((tmp & 15) > 14) + { + return 1; + } + allocation_0[i_sb+1] = allocation_1[i_sb+1] + = adec_layer1_allocation_table [tmp & 15]; + } + + i_read_bits += 4 * ( 32 + bound ); /* we read 8*bound and 4*(32-bound) */ + + /* + * Parse scalefactors + */ + + for ( i_sb = 0; i_sb < 32; i_sb++ ) + { + if ( allocation_0[i_sb] ) + { + int index; + float scalefactor; + + index = GetBits( &p_adec->bit_stream, 6 ); + i_read_bits += 6; + + scalefactor = adec_scalefactor_table[index]; + + slope_0[i_sb] = adec_slope_table[allocation_0[i_sb]-2] * scalefactor; + offset_0[i_sb] = adec_offset_table[allocation_0[i_sb]-2] * scalefactor; + } + + if (allocation_1[i_sb]) + { + int index; + float scalefactor; + + index = GetBits( &p_adec->bit_stream, 6 ); + i_read_bits += 6; + + scalefactor = adec_scalefactor_table[index]; + + slope_1[i_sb] = adec_slope_table[allocation_1[i_sb]-2] * scalefactor; + offset_1[i_sb] = adec_offset_table[allocation_1[i_sb]-2] * scalefactor; + } + } + + /* parse samples */ + + for (s = 0; s < 12; s++) + { + for (i_sb = 0; i_sb < bound; i_sb++) + { + if (!allocation_0[i_sb]) + { + sample_0[i_sb] = 0; + } + else + { + int code; + + code = GetBits( &p_adec->bit_stream, allocation_0[i_sb] ); + i_read_bits += allocation_0[i_sb]; + + sample_0[i_sb] = slope_0[i_sb] * code + offset_0[i_sb]; + } + + if ( !allocation_1[i_sb] ) + { + sample_1[i_sb] = 0; + } + else + { + int code; + + code = GetBits( &p_adec->bit_stream, allocation_1[i_sb] ); + i_read_bits += allocation_1[i_sb]; + + sample_1[i_sb] = slope_1[i_sb] * code + offset_1[i_sb]; + } + } + + for (; i_sb < 32; i_sb++) + { + if (!allocation_0[i_sb]) + { + sample_0[i_sb] = 0; + sample_1[i_sb] = 0; + } + else + { + int code; + + code = GetBits( &p_adec->bit_stream, allocation_0[i_sb] ); + i_read_bits += allocation_0[i_sb]; + + sample_0[i_sb] = slope_0[i_sb] * code + offset_0[i_sb]; + sample_1[i_sb] = slope_1[i_sb] * code + offset_1[i_sb]; + } + } + + DCT32( &p_adec->bank_0, sample_0 ); + PCM (&p_adec->bank_0, buffer, 2); + DCT32( &p_adec->bank_1, sample_1 ); + PCM (&p_adec->bank_1, buffer + 1, 2); + buffer += 64; + } + + p_adec->i_read_bits += i_read_bits; + + return 0; +} + diff --git a/modules/codec/mpeg_audio/layer1.h b/modules/codec/mpeg_audio/layer1.h new file mode 100644 index 0000000000..0e446302bc --- /dev/null +++ b/modules/codec/mpeg_audio/layer1.h @@ -0,0 +1,26 @@ +/***************************************************************************** + * adec_layer1.h: MPEG Layer I audio decoder + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: layer1.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * + * 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 adec_layer1_mono( adec_thread_t * p_adec, s16 * buffer ); +int adec_layer1_stereo (adec_thread_t * p_adec, s16 * buffer); + diff --git a/modules/codec/mpeg_audio/layer2.c b/modules/codec/mpeg_audio/layer2.c new file mode 100644 index 0000000000..eb66972ca2 --- /dev/null +++ b/modules/codec/mpeg_audio/layer2.c @@ -0,0 +1,993 @@ +/***************************************************************************** + * layer2.c: MPEG Layer II audio decoder + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: layer2.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * + * 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 /* NULL */ +#include /* memcpy(), memset() */ + +#include +#include + +#include "generic.h" +#include "decoder.h" +#include "math.h" /* DCT32(), PCM() */ + +/**** wkn ****/ + +static float adec_scalefactor_table[64] = +{ /* 2 ^ (1 - i/3) */ + 2.0000000000000000, 1.5874010519681994, 1.2599210498948732, + 1.0000000000000000, 0.7937005259840998, 0.6299605249474366, + 0.5000000000000000, 0.3968502629920499, 0.3149802624737183, + 0.2500000000000000, 0.1984251314960249, 0.1574901312368591, + 0.1250000000000000, 0.0992125657480125, 0.0787450656184296, + 0.0625000000000000, 0.0496062828740062, 0.0393725328092148, + 0.0312500000000000, 0.0248031414370031, 0.0196862664046074, + 0.0156250000000000, 0.0124015707185016, 0.0098431332023037, + 0.0078125000000000, 0.0062007853592508, 0.0049215666011518, + 0.0039062500000000, 0.0031003926796254, 0.0024607833005759, + 0.0019531250000000, 0.0015501963398127, 0.0012303916502880, + 0.0009765625000000, 0.0007750981699063, 0.0006151958251440, + 0.0004882812500000, 0.0003875490849532, 0.0003075979125720, + 0.0002441406250000, 0.0001937745424766, 0.0001537989562860, + 0.0001220703125000, 0.0000968872712383, 0.0000768994781430, + 0.0000610351562500, 0.0000484436356191, 0.0000384497390715, + 0.0000305175781250, 0.0000242218178096, 0.0000192248695357, + 0.0000152587890625, 0.0000121109089048, 0.0000096124347679, + 0.0000076293945312, 0.0000060554544524, 0.0000048062173839, + 0.0000038146972656, 0.0000030277272262, 0.0000024031086920, + 0.0000019073486328, 0.0000015138636131, 0.0000012015543460, + 0.0000009536743164 /* last element is not in the standard... invalid ??? */ +}; + +static float adec_slope_table[15] = +{ + 0.6666666666666666, 0.2857142857142857, 0.1333333333333333, + 0.0645161290322581, 0.0317460317460317, 0.0157480314960630, + 0.0078431372549020, 0.0039138943248532, 0.0019550342130987, + 0.0009770395701026, 0.0004884004884005, 0.0002441704309608, + 0.0001220777635354, 0.0000610370189520, 0.0000305180437934 +}; + +static float adec_offset_table[15] = +{ + -0.6666666666666666, -0.8571428571428571, -0.9333333333333333, + -0.9677419354838710, -0.9841269841269841, -0.9921259842519685, + -0.9960784313725490, -0.9980430528375733, -0.9990224828934506, + -0.9995114802149487, -0.9997557997557998, -0.9998779147845196, + -0.9999389611182323, -0.9999694814905240, -0.9999847409781033 +}; + +static int adec_bound_table[4] = { 4, 8, 12, 16 }; + +typedef struct +{ + s8 nbal[32]; + u8 * alloc[32]; +} alloc_table_t; + +#define L3 -1 +#define L5 -2 +#define L9 -3 + +static void adec_layer2_get_table( u32 header, u8 freq_table[15], + alloc_table_t ** alloc, int * sblimit ) +{ + static s8 table_ab0[16] = + { + 0, L3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 + }; + static s8 table_ab3[16] = + { + 0, L3, L5, 3, L9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 + }; + static s8 table_ab11[8] = + { + 0, L3, L5, 3, L9, 4, 5, 16 + }; + static s8 table_ab23[8] = + { + 0, L3, L5, 16 + }; + static alloc_table_t mpeg1_ab = + { + {4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,0,0}, + {table_ab0, table_ab0, table_ab0, table_ab3, + table_ab3, table_ab3, table_ab3, table_ab3, + table_ab3, table_ab3, table_ab3, table_ab11, + table_ab11, table_ab11, table_ab11, table_ab11, + table_ab11, table_ab11, table_ab11, table_ab11, + table_ab11, table_ab11, table_ab11, table_ab23, + table_ab23, table_ab23, table_ab23, table_ab23, + table_ab23, table_ab23, NULL, NULL} + }; + + static s8 table_cd[16] = + { + 0, L3, L5, L9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + static alloc_table_t mpeg1_cd = + { + {4,4,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {table_cd, table_cd, table_cd, table_cd, + table_cd, table_cd, table_cd, table_cd, + table_cd, table_cd, table_cd, table_cd, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} + }; + + static s8 table_0[16] = + { + 0, L3, L5, 3, L9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + }; + static s8 table_4[8] = + { + 0, L3, L5, L9, 4, 5, 6, 7 + }; + static alloc_table_t mpeg2 = + { + {4,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0}, + {table_0, table_0, table_0, table_0, + table_4, table_4, table_4, table_4, + table_4, table_4, table_4, table_4, + table_4, table_4, table_4, table_4, + table_4, table_4, table_4, table_4, + table_4, table_4, table_4, table_4, + table_4, table_4, table_4, table_4, + table_4, table_4, NULL, NULL} + }; + + static alloc_table_t * alloc_table [4] = + { + &mpeg2, &mpeg1_cd, &mpeg1_ab, &mpeg1_ab + }; + static int sblimit_table[12] = + { + 30, 8, 27, 30, 30, 8, 27, 27, 30, 12, 27, 30 + }; + + int index; + + if (!(header & 0x80000)) + { + index = 0; /* mpeg2 */ + } + else + { + index = (header >> 12) & 15; /* mpeg1, bitrate */ + index = freq_table [index]; + } + + *alloc = alloc_table[index]; + index |= (header >> 8) & 12; + *sblimit = sblimit_table[index]; +} + +int adec_layer2_mono( adec_thread_t * p_adec, s16 * buffer ) +{ + static u8 freq_table[15] = {2, 1, 1, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2}; + static float L3_table[3] = {-2/3.0, 0, 2/3.0}; + static float L5_table[5] = {-4/5.0, -2/5.0, 0, 2/5.0, 4/5.0}; + static float L9_table[9] = {-8/9.0, -6/9.0, -4/9.0, -2/9.0, 0, + 2/9.0, 4/9.0, 6/9.0, 8/9.0}; + + s8 allocation[32]; + u8 scfsi[32]; + float slope[3][32]; + float offset[3][32]; + float sample[3][32]; + alloc_table_t * alloc_table; + + int sblimit; + int sb; + int gr0, gr1; + int s; + int i_read_bits = 0; + + /* get the right allocation table */ + adec_layer2_get_table (p_adec->header, freq_table, &alloc_table, &sblimit); + + /* parse allocation */ + //sblimit=27; + + for (sb = 0; sb < sblimit; sb++) + { + int index; + + index = GetBits( &p_adec->bit_stream, alloc_table->nbal[sb] ); + i_read_bits += alloc_table->nbal[sb]; + + allocation[sb] = alloc_table->alloc[sb][index]; + } + + /* parse scfsi */ + + for (sb = 0; sb < sblimit; sb++) + { + if (allocation[sb]) + { + scfsi[sb] = GetBits (&p_adec->bit_stream, 2); + i_read_bits += 2; + } + } + + /* parse scalefactors */ + + for (sb = 0; sb < sblimit; sb++) + { + if (allocation[sb]) + { + int index_0, index_1, index_2; + + switch (scfsi[sb]) + { + case 0: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + index_2 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 18; + + if (allocation[sb] < 0) + { + slope[0][sb] = adec_scalefactor_table[index_0]; + slope[1][sb] = adec_scalefactor_table[index_1]; + slope[2][sb] = adec_scalefactor_table[index_2]; + } + else + { + float r_scalefactor; + float r_slope, r_offset; + + r_slope = adec_slope_table[allocation[sb]-2]; + r_offset = adec_offset_table[allocation[sb]-2]; + + r_scalefactor = adec_scalefactor_table[index_0]; + slope[0][sb] = r_slope * r_scalefactor; + offset[0][sb] = r_offset * r_scalefactor; + + r_scalefactor = adec_scalefactor_table[index_1]; + slope[1][sb] = r_slope * r_scalefactor; + offset[1][sb] = r_offset * r_scalefactor; + + r_scalefactor = adec_scalefactor_table[index_2]; + slope[2][sb] = r_slope * r_scalefactor; + offset[2][sb] = r_offset * r_scalefactor; + } + break; + + case 1: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation[sb] < 0) + { + slope[0][sb] = slope[1][sb] = + adec_scalefactor_table[index_0]; + slope[2][sb] = adec_scalefactor_table[index_1]; + } + else + { + float r_scalefactor; + float r_slope, r_offset; + + r_slope = adec_slope_table[allocation[sb]-2]; + r_offset = adec_offset_table[allocation[sb]-2]; + + r_scalefactor = adec_scalefactor_table[index_0]; + slope[0][sb] = slope[1][sb] = r_slope * r_scalefactor; + offset[0][sb] = offset[1][sb] = + r_offset * r_scalefactor; + + r_scalefactor = adec_scalefactor_table[index_1]; + slope[2][sb] = r_slope * r_scalefactor; + offset[2][sb] = r_offset * r_scalefactor; + } + break; + + case 2: + index_0 = GetBits( &p_adec->bit_stream, 6 ); + i_read_bits += 6; + + if (allocation[sb] < 0) + { + slope[0][sb] = slope[1][sb] = slope[2][sb] = + adec_scalefactor_table[index_0]; + } + else + { + float r_scalefactor; + float r_slope, r_offset; + + r_slope = adec_slope_table[allocation[sb]-2]; + r_offset = adec_offset_table[allocation[sb]-2]; + + r_scalefactor = adec_scalefactor_table[index_0]; + slope[0][sb] = slope[1][sb] = slope[2][sb] = + r_slope * r_scalefactor; + offset[0][sb] = offset[1][sb] = offset[2][sb] = + r_offset * r_scalefactor; + } + break; + + case 3: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation[sb] < 0) + { + slope[0][sb] = adec_scalefactor_table[index_0]; + slope[1][sb] = slope[2][sb] = + adec_scalefactor_table[index_1]; + } + else + { + float r_scalefactor; + float r_slope, r_offset; + + r_slope = adec_slope_table[allocation[sb]-2]; + r_offset = adec_offset_table[allocation[sb]-2]; + + r_scalefactor = adec_scalefactor_table[index_0]; + slope[0][sb] = r_slope * r_scalefactor; + offset[0][sb] = r_offset * r_scalefactor; + + r_scalefactor = adec_scalefactor_table[index_1]; + slope[1][sb] = slope[2][sb] = r_slope * r_scalefactor; + offset[1][sb] = offset[2][sb] = + r_offset * r_scalefactor; + } + break; + } + } + } + + /* parse samples */ + + for (gr0 = 0; gr0 < 3; gr0++) + { + for (gr1 = 0; gr1 < 4; gr1++) + { + for (sb = 0; sb < sblimit; sb++) + { + int code; + + switch (allocation[sb]) + { + case 0: + sample[0][sb] = sample[1][sb] = sample[2][sb] = 0; + break; + + case L3: + code = GetBits( &p_adec->bit_stream, 5 ); + i_read_bits += 5; + + sample[0][sb] = slope[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample[1][sb] = slope[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample[2][sb] = slope[gr0][sb] * L3_table[code]; + break; + + case L5: + code = GetBits( &p_adec->bit_stream, 7 ); + i_read_bits += 7; + + sample[0][sb] = slope[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample[1][sb] = slope[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample[2][sb] = slope[gr0][sb] * L5_table[code]; + break; + + case L9: + code = GetBits( &p_adec->bit_stream, 10 ); + i_read_bits += 10; + + sample[0][sb] = slope[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample[1][sb] = slope[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample[2][sb] = slope[gr0][sb] * L9_table[code]; + break; + + default: + for (s = 0; s < 3; s++) + { + code = GetBits( &p_adec->bit_stream, + allocation[sb] ); + i_read_bits += allocation[sb]; + + sample[s][sb] = + slope[gr0][sb] * code + offset[gr0][sb]; + } + } + } + + for (; sb < 32; sb++) + { + sample[0][sb] = sample[1][sb] = sample[2][sb] = 0; + } + + for (s = 0; s < 3; s++) + { + DCT32( &p_adec->bank_0, sample[s] ); + PCM( &p_adec->bank_0, buffer, 2 ); + + /* FIXME: one shouldn't have to do it twice ! */ + DCT32( &p_adec->bank_1, sample[s] ); + PCM( &p_adec->bank_1, buffer + 1, 2 ); + + buffer += 64; + } + } + } + + p_adec->i_read_bits += i_read_bits; + + return 0; +} + +int adec_layer2_stereo( adec_thread_t * p_adec, s16 * buffer ) +{ + static u8 freq_table[15] = {3, 0, 0, 0, 1, 0, 1, 2, 2, 2, 3, 3, 3, 3, 3}; + static float L3_table[3] = {-2/3.0, 0, 2/3.0}; + static float L5_table[5] = {-4/5.0, -2/5.0, 0, 2/5.0, 4/5.0}; + static float L9_table[9] = {-8/9.0, -6/9.0, -4/9.0, -2/9.0, 0, + 2/9.0, 4/9.0, 6/9.0, 8/9.0}; + + s8 allocation_0[32], allocation_1[32]; + u8 scfsi_0[32], scfsi_1[32]; + float slope_0[3][32], slope_1[3][32]; + float offset_0[3][32], offset_1[3][32]; + float sample_0[3][32], sample_1[3][32]; + alloc_table_t * alloc_table; + + int sblimit; + int bound; + int sb; + int gr0, gr1; + int s; + int i_read_bits = 0; + + /* get the right allocation table */ + adec_layer2_get_table (p_adec->header, freq_table, &alloc_table, &sblimit); + + /* calculate bound */ + bound = sblimit; + if ((p_adec->header & 0xc0) == 0x40) { /* intensity stereo */ + int index; + index = (p_adec->header >> 4) & 3; + if (adec_bound_table[index] < sblimit) + { + bound = adec_bound_table[index]; + } + } + + /* parse allocation */ + + for (sb = 0; sb < bound; sb++) + { + int index; + + index = GetBits( &p_adec->bit_stream, alloc_table->nbal[sb] ); + allocation_0[sb] = alloc_table->alloc[sb][index]; + + index = GetBits( &p_adec->bit_stream, alloc_table->nbal[sb] ); + allocation_1[sb] = alloc_table->alloc[sb][index]; + + i_read_bits += alloc_table->nbal[sb] * 2; + } + + for (; sb < sblimit; sb++) + { + int index; + + index = GetBits( &p_adec->bit_stream, alloc_table->nbal[sb] ); + allocation_0[sb] = allocation_1[sb] = alloc_table->alloc[sb][index]; + i_read_bits += alloc_table->nbal[sb]; + } + + /* parse scfsi */ + + for (sb = 0; sb < sblimit; sb++) + { + if (allocation_0[sb]) + { + scfsi_0[sb] = GetBits (&p_adec->bit_stream, 2); + i_read_bits += 2; + } + + if (allocation_1[sb]) + { + scfsi_1[sb] = GetBits (&p_adec->bit_stream, 2); + i_read_bits += 2; + } + } + + /* parse scalefactors */ + + for (sb = 0; sb < sblimit; sb++) + { + if (allocation_0[sb]) + { + int index_0, index_1, index_2; + + switch (scfsi_0[sb]) + { + case 0: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + index_2 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 18; + + if (allocation_0[sb] < 0) + { + slope_0[0][sb] = adec_scalefactor_table[index_0]; + slope_0[1][sb] = adec_scalefactor_table[index_1]; + slope_0[2][sb] = adec_scalefactor_table[index_2]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_0[sb]-2]; + offset = adec_offset_table[allocation_0[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_0[0][sb] = slope * scalefactor; + offset_0[0][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_0[1][sb] = slope * scalefactor; + offset_0[1][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_2]; + slope_0[2][sb] = slope * scalefactor; + offset_0[2][sb] = offset * scalefactor; + } + break; + + case 1: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation_0[sb] < 0) + { + slope_0[0][sb] = slope_0[1][sb] = + adec_scalefactor_table[index_0]; + slope_0[2][sb] = adec_scalefactor_table[index_1]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_0[sb]-2]; + offset = adec_offset_table[allocation_0[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_0[0][sb] = slope_0[1][sb] = slope * scalefactor; + offset_0[0][sb] = offset_0[1][sb] = + offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_0[2][sb] = slope * scalefactor; + offset_0[2][sb] = offset * scalefactor; + } + break; + + case 2: + index_0 = GetBits( &p_adec->bit_stream, 6 ); + i_read_bits += 6; + + if (allocation_0[sb] < 0) + { + slope_0[0][sb] = slope_0[1][sb] = slope_0[2][sb] = + adec_scalefactor_table[index_0]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_0[sb]-2]; + offset = adec_offset_table[allocation_0[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_0[0][sb] = slope_0[1][sb] = slope_0[2][sb] = + slope * scalefactor; + offset_0[0][sb] = offset_0[1][sb] = offset_0[2][sb] = + offset * scalefactor; + } + break; + + case 3: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation_0[sb] < 0) + { + slope_0[0][sb] = adec_scalefactor_table[index_0]; + slope_0[1][sb] = slope_0[2][sb] = + adec_scalefactor_table[index_1]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_0[sb]-2]; + offset = adec_offset_table[allocation_0[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_0[0][sb] = slope * scalefactor; + offset_0[0][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_0[1][sb] = slope_0[2][sb] = slope * scalefactor; + offset_0[1][sb] = offset_0[2][sb] = + offset * scalefactor; + } + break; + } + } + + if (allocation_1[sb]) + { + int index_0, index_1, index_2; + + switch (scfsi_1[sb]) + { + case 0: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + index_2 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 18; + + if (allocation_1[sb] < 0) + { + slope_1[0][sb] = adec_scalefactor_table[index_0]; + slope_1[1][sb] = adec_scalefactor_table[index_1]; + slope_1[2][sb] = adec_scalefactor_table[index_2]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_1[sb]-2]; + offset = adec_offset_table[allocation_1[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_1[0][sb] = slope * scalefactor; + offset_1[0][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_1[1][sb] = slope * scalefactor; + offset_1[1][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_2]; + slope_1[2][sb] = slope * scalefactor; + offset_1[2][sb] = offset * scalefactor; + } + break; + + case 1: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation_1[sb] < 0) + { + slope_1[0][sb] = slope_1[1][sb] = + adec_scalefactor_table[index_0]; + slope_1[2][sb] = adec_scalefactor_table[index_1]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_1[sb]-2]; + offset = adec_offset_table[allocation_1[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_1[0][sb] = slope_1[1][sb] = slope * scalefactor; + offset_1[0][sb] = offset_1[1][sb] = + offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_1[2][sb] = slope * scalefactor; + offset_1[2][sb] = offset * scalefactor; + } + break; + + case 2: + index_0 = GetBits( &p_adec->bit_stream, 6 ); + i_read_bits += 6; + + if (allocation_1[sb] < 0) + { + slope_1[0][sb] = slope_1[1][sb] = slope_1[2][sb] = + adec_scalefactor_table[index_0]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_1[sb]-2]; + offset = adec_offset_table[allocation_1[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_1[0][sb] = slope_1[1][sb] = slope_1[2][sb] = + slope * scalefactor; + offset_1[0][sb] = offset_1[1][sb] = offset_1[2][sb] = + offset * scalefactor; + } + break; + + case 3: + index_0 = GetBits(&p_adec->bit_stream,6); + index_1 = GetBits(&p_adec->bit_stream,6); + i_read_bits += 12; + + if (allocation_1[sb] < 0) + { + slope_1[0][sb] = adec_scalefactor_table[index_0]; + slope_1[1][sb] = slope_1[2][sb] = + adec_scalefactor_table[index_1]; + } + else + { + float scalefactor; + float slope, offset; + + slope = adec_slope_table[allocation_1[sb]-2]; + offset = adec_offset_table[allocation_1[sb]-2]; + + scalefactor = adec_scalefactor_table[index_0]; + slope_1[0][sb] = slope * scalefactor; + offset_1[0][sb] = offset * scalefactor; + + scalefactor = adec_scalefactor_table[index_1]; + slope_1[1][sb] = slope_1[2][sb] = slope * scalefactor; + offset_1[1][sb] = offset_1[2][sb] = + offset * scalefactor; + } + break; + } + } + } + + /* parse samples */ + + for (gr0 = 0; gr0 < 3; gr0++) + { + for (gr1 = 0; gr1 < 4; gr1++) + { + for (sb = 0; sb < bound; sb++) + { + int code; + + switch (allocation_0[sb]) + { + case 0: + sample_0[0][sb] = sample_0[1][sb] = sample_0[2][sb] = 0; + break; + + case L3: + code = GetBits( &p_adec->bit_stream, 5 ); + i_read_bits += 5; + + sample_0[0][sb] = slope_0[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_0[1][sb] = slope_0[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_0[2][sb] = slope_0[gr0][sb] * L3_table[code]; + break; + + case L5: + code = GetBits( &p_adec->bit_stream, 7 ); + i_read_bits += 7; + + sample_0[0][sb] = slope_0[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_0[1][sb] = slope_0[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_0[2][sb] = slope_0[gr0][sb] * L5_table[code]; + break; + + case L9: + code = GetBits( &p_adec->bit_stream, 10 ); + i_read_bits += 10; + + sample_0[0][sb] = slope_0[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_0[1][sb] = slope_0[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_0[2][sb] = slope_0[gr0][sb] * L9_table[code]; + break; + + default: + for (s = 0; s < 3; s++) + { + code = GetBits( &p_adec->bit_stream, + allocation_0[sb] ); + i_read_bits += allocation_0[sb]; + + sample_0[s][sb] = + slope_0[gr0][sb] * code + offset_0[gr0][sb]; + } + } + + switch (allocation_1[sb]) + { + case 0: + sample_1[0][sb] = sample_1[1][sb] = sample_1[2][sb] = 0; + break; + + case L3: + code = GetBits( &p_adec->bit_stream, 5 ); + i_read_bits += 5; + + sample_1[0][sb] = slope_1[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_1[1][sb] = slope_1[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_1[2][sb] = slope_1[gr0][sb] * L3_table[code]; + break; + + case L5: + code = GetBits( &p_adec->bit_stream, 7 ); + i_read_bits += 7; + + sample_1[0][sb] = slope_1[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_1[1][sb] = slope_1[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_1[2][sb] = slope_1[gr0][sb] * L5_table[code]; + break; + + case L9: + code = GetBits( &p_adec->bit_stream, 10 ); + i_read_bits += 10; + + sample_1[0][sb] = slope_1[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_1[1][sb] = slope_1[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_1[2][sb] = slope_1[gr0][sb] * L9_table[code]; + break; + + default: + for (s = 0; s < 3; s++) + { + code = GetBits( &p_adec->bit_stream, + allocation_1[sb] ); + i_read_bits += allocation_1[sb]; + + sample_1[s][sb] = + slope_1[gr0][sb] * code + offset_1[gr0][sb]; + } + } + } + + for (; sb < sblimit; sb++) + { + int code; + + switch (allocation_0[sb]) + { + case 0: + sample_0[0][sb] = sample_0[1][sb] = sample_0[2][sb] = 0; + sample_1[0][sb] = sample_1[1][sb] = sample_1[2][sb] = 0; + break; + + case L3: + code = GetBits( &p_adec->bit_stream, 5 ); + i_read_bits += 5; + + sample_0[0][sb] = slope_0[gr0][sb] * L3_table[code % 3]; + sample_1[0][sb] = slope_1[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_0[1][sb] = slope_0[gr0][sb] * L3_table[code % 3]; + sample_1[1][sb] = slope_1[gr0][sb] * L3_table[code % 3]; + code /= 3; + sample_0[2][sb] = slope_0[gr0][sb] * L3_table[code]; + sample_1[2][sb] = slope_1[gr0][sb] * L3_table[code]; + break; + + case L5: + code = GetBits( &p_adec->bit_stream, 7 ); + i_read_bits += 7; + + sample_0[0][sb] = slope_0[gr0][sb] * L5_table[code % 5]; + sample_1[0][sb] = slope_1[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_0[1][sb] = slope_0[gr0][sb] * L5_table[code % 5]; + sample_1[1][sb] = slope_1[gr0][sb] * L5_table[code % 5]; + code /= 5; + sample_0[2][sb] = slope_0[gr0][sb] * L5_table[code]; + sample_1[2][sb] = slope_1[gr0][sb] * L5_table[code]; + break; + + case L9: + code = GetBits( &p_adec->bit_stream, 10 ); + i_read_bits += 10; + + sample_0[0][sb] = slope_0[gr0][sb] * L9_table[code % 9]; + sample_1[0][sb] = slope_1[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_0[1][sb] = slope_0[gr0][sb] * L9_table[code % 9]; + sample_1[1][sb] = slope_1[gr0][sb] * L9_table[code % 9]; + code /= 9; + sample_0[2][sb] = slope_0[gr0][sb] * L9_table[code]; + sample_1[2][sb] = slope_1[gr0][sb] * L9_table[code]; + break; + + default: + for (s = 0; s < 3; s++) + { + code = GetBits( &p_adec->bit_stream, + allocation_0[sb] ); + i_read_bits += allocation_0[sb]; + + sample_0[s][sb] = + slope_0[gr0][sb] * code + offset_0[gr0][sb]; + sample_1[s][sb] = + slope_1[gr0][sb] * code + offset_1[gr0][sb]; + } + } + } + + for (; sb < 32; sb++) + { + sample_0[0][sb] = sample_0[1][sb] = sample_0[2][sb] = 0; + sample_1[0][sb] = sample_1[1][sb] = sample_1[2][sb] = 0; + } + + for (s = 0; s < 3; s++) + { + DCT32( &p_adec->bank_0, sample_0[s] ); + PCM( &p_adec->bank_0, buffer, 2 ); + + DCT32( &p_adec->bank_1, sample_1[s] ); + PCM( &p_adec->bank_1, buffer + 1, 2 ); + + buffer += 64; + } + } + } + + p_adec->i_read_bits += i_read_bits; + + return 0; +} + diff --git a/modules/codec/mpeg_audio/layer2.h b/modules/codec/mpeg_audio/layer2.h new file mode 100644 index 0000000000..7df1c6be74 --- /dev/null +++ b/modules/codec/mpeg_audio/layer2.h @@ -0,0 +1,26 @@ +/***************************************************************************** + * adec_layer2.h: MPEG Layer II audio decoder + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: layer2.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * + * 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 adec_layer2_mono ( adec_thread_t * p_adec, s16 * buffer ); +int adec_layer2_stereo ( adec_thread_t * p_adec, s16 * buffer ); + diff --git a/modules/codec/mpeg_audio/math.c b/modules/codec/mpeg_audio/math.c new file mode 100644 index 0000000000..553339ac2f --- /dev/null +++ b/modules/codec/mpeg_audio/math.c @@ -0,0 +1,1044 @@ +/***************************************************************************** + * math.c: Inverse Discrete Cosine Transform and Pulse Code Modulation + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: math.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * + * 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 + +#include "generic.h" + +/***************************************************************************** + * DCT32: Fast 32 points Discrete Cosine Transform + ***************************************************************************** + * 289 additions and multiplications + * F(u)=alpha(u)*SUM(x=0, xactual + b->pos; + y = (b->actual == b->v1 ? b->v2 : b->v1) + b->pos; + x[0] = -(y[0] = c2 * (tt1 - tt2)); /* t17 */ + x[256] = 0; y[256] = tt1 + tt2; /* t1 */ + t25 = c2 * (tt3 - tt4); + t9 = tt3 + tt4; + t21 = c2 * (tt5 - tt6); + t5 = tt5 + tt6; + t29 = c2 * (tt7 - tt8); + t13 = tt7 + tt8; + t19 = c2 * (tt9 - tt10); + t3 = tt9 + tt10; + t27 = c2 * (tt11 - tt12); + t11 = tt11 + tt12; + t23 = c2 * (tt13 - tt14); + t7 = tt13 + tt14; + t31 = c2 * (tt15 - tt16); + t15 = tt15 + tt16; + t18 = c2 * (tt17 - tt18); + t2 = tt17 + tt18; + t26 = c2 * (tt19 - tt20); + t10 = tt19 + tt20; + t22 = c2 * (tt21 - tt22); + t6 = tt21 + tt22; + t30 = c2 * (tt23 - tt24); + t14 = tt23 + tt24; + t20 = c2 * (tt25 - tt26); + t4 = tt25 + tt26; + t28 = c2 * (tt27 - tt28); + t12 = tt27 + tt28; + t24 = c2 * (tt29 - tt30); + t8 = tt29 + tt30; + t32 = c2 * (tt31 - tt32); + t16 = tt31 + tt32; + /* Do the sums */ + /* Keep on splitting the result */ + y[384] = y[128] = t9 - (x[128] = -(x[384] = t25)); /* t25, t9 */ + t10 += t26; + t11 += t27; + t12 += t28; + t13 += t29; + t14 += t30; + t15 += t31; + t16 += t32; + y[320] = y[192] = t5 + t13; /* t5 */ + y[448] = y[64] = t13 + t21; /* t13 */ + x[64] = -(x[448] = t21 - (x[192] = -(x[320] = t29))); /* t29, t21 */ + t6 += t14; + t14 += t22; + t22 += t30; + t7 += t15; + t15 += t23; + t23 += t31; + t8 += t16; + t16 += t24; + t24 += t32; + y[288] = y[224] = t3 + t7; /* t3 */ + y[352] = y[160] = t7 + t11; /* t7 */ + y[416] = y[96] = t11 + t15; /* t11 */ + y[480] = y[32] = t15 + t19; /* t15 */ + x[32] = -(x[480] = t19 + t23); /* t19 */ + x[96] = -(x[416] = t23 + t27); /* t23 */ + x[160] = -(x[352] = t27 - (x[224] = -(x[288] = t31))); /* t31, t27 */ + t4 += t8 ; + t8 += t12; + t12 += t16; + t16 += t20; + t20 += t24; + t24 += t28; + t28 += t32; + y[272] = y[240] = t2 + t4; /* t2 */ + y[304] = y[208] = t4 + t6; /* t4 */ + y[336] = y[176] = t6 + t8; /* t6 */ + y[368] = y[144] = t8 + t10; /* t8 */ + y[400] = y[112] = t10 + t12; /* t10 */ + y[432] = y[80] = t12 + t14; /* t12 */ + y[464] = y[48] = t14 + t16; /* t14 */ + y[496] = y[16] = t16 + t18; /* t16 */ + x[16] = -(x[496] = t18 + t20); /* t18 */ + x[48] = -(x[464] = t20 + t22); /* t20 */ + x[80] = -(x[432] = t22 + t24); /* t22 */ + x[112] = -(x[400] = t24 + t26); /* t24 */ + x[144] = -(x[368] = t26 + t28); /* t26 */ + x[176] = -(x[336] = t28 + t30); /* t28 */ + x[208] = -(x[304] = t30 - (x[240] = -(x[272] = t32))); /* t32, t30 */ + /* Note that to be really complete, the DCT should multiply t1 by sqrt(2)/N + and t2 to t32 by 2/N, and would take 321 additions and multiplications. + But that's unuseful in this application. */ +} + + +/***************************************************************************** + * PCM: Pulse Code Modulation + ***************************************************************************** + * Compute 32 PCM samples with a convolution product + *****************************************************************************/ + +void PCM(adec_bank_t *b, s16 *p_pcm, int jump) +{ + /* scale factor */ +#define F -32768 + /* These values are not in the same order as in Annex 3-B.3 of the ISO/IEC + DIS 11172-3 */ + static const float c[512] = + { + 0.000000000 * F, -0.000442505 * F, 0.003250122 * F, -0.007003784 * F, + 0.031082153 * F, -0.078628540 * F, 0.100311279 * F, -0.572036743 * F, + 1.144989014 * F, 0.572036743 * F, 0.100311279 * F, 0.078628540 * F, + 0.031082153 * F, 0.007003784 * F, 0.003250122 * F, 0.000442505 * F, + -0.000015259 * F, -0.000473022 * F, 0.003326416 * F, -0.007919312 * F, + 0.030517578 * F, -0.084182739 * F, 0.090927124 * F, -0.600219727 * F, + 1.144287109 * F, 0.543823242 * F, 0.108856201 * F, 0.073059082 * F, + 0.031478882 * F, 0.006118774 * F, 0.003173828 * F, 0.000396729 * F, + -0.000015259 * F, -0.000534058 * F, 0.003387451 * F, -0.008865356 * F, + 0.029785156 * F, -0.089706421 * F, 0.080688477 * F, -0.628295898 * F, + 1.142211914 * F, 0.515609741 * F, 0.116577148 * F, 0.067520142 * F, + 0.031738281 * F, 0.005294800 * F, 0.003082275 * F, 0.000366211 * F, + -0.000015259 * F, -0.000579834 * F, 0.003433228 * F, -0.009841919 * F, + 0.028884888 * F, -0.095169067 * F, 0.069595337 * F, -0.656219482 * F, + 1.138763428 * F, 0.487472534 * F, 0.123474121 * F, 0.061996460 * F, + 0.031845093 * F, 0.004486084 * F, 0.002990723 * F, 0.000320435 * F, + -0.000015259 * F, -0.000625610 * F, 0.003463745 * F, -0.010848999 * F, + 0.027801514 * F, -0.100540161 * F, 0.057617188 * F, -0.683914185 * F, + 1.133926392 * F, 0.459472656 * F, 0.129577637 * F, 0.056533813 * F, + 0.031814575 * F, 0.003723145 * F, 0.002899170 * F, 0.000289917 * F, + -0.000015259 * F, -0.000686646 * F, 0.003479004 * F, -0.011886597 * F, + 0.026535034 * F, -0.105819702 * F, 0.044784546 * F, -0.711318970 * F, + 1.127746582 * F, 0.431655884 * F, 0.134887695 * F, 0.051132202 * F, + 0.031661987 * F, 0.003005981 * F, 0.002792358 * F, 0.000259399 * F, + -0.000015259 * F, -0.000747681 * F, 0.003479004 * F, -0.012939453 * F, + 0.025085449 * F, -0.110946655 * F, 0.031082153 * F, -0.738372803 * F, + 1.120223999 * F, 0.404083252 * F, 0.139450073 * F, 0.045837402 * F, + 0.031387329 * F, 0.002334595 * F, 0.002685547 * F, 0.000244141 * F, + -0.000030518 * F, -0.000808716 * F, 0.003463745 * F, -0.014022827 * F, + 0.023422241 * F, -0.115921021 * F, 0.016510010 * F, -0.765029907 * F, + 1.111373901 * F, 0.376800537 * F, 0.143264771 * F, 0.040634155 * F, + 0.031005859 * F, 0.001693726 * F, 0.002578735 * F, 0.000213623 * F, + -0.000030518 * F, -0.000885010 * F, 0.003417969 * F, -0.015121460 * F, + 0.021575928 * F, -0.120697021 * F, 0.001068115 * F, -0.791213989 * F, + 1.101211548 * F, 0.349868774 * F, 0.146362305 * F, 0.035552979 * F, + 0.030532837 * F, 0.001098633 * F, 0.002456665 * F, 0.000198364 * F, + -0.000030518 * F, -0.000961304 * F, 0.003372192 * F, -0.016235352 * F, + 0.019531250 * F, -0.125259399 * F, -0.015228271 * F, -0.816864014 * F, + 1.089782715 * F, 0.323318481 * F, 0.148773193 * F, 0.030609131 * F, + 0.029937744 * F, 0.000549316 * F, 0.002349854 * F, 0.000167847 * F, + -0.000030518 * F, -0.001037598 * F, 0.003280640 * F, -0.017349243 * F, + 0.017257690 * F, -0.129562378 * F, -0.032379150 * F, -0.841949463 * F, + 1.077117920 * F, 0.297210693 * F, 0.150497437 * F, 0.025817871 * F, + 0.029281616 * F, 0.000030518 * F, 0.002243042 * F, 0.000152588 * F, + -0.000045776 * F, -0.001113892 * F, 0.003173828 * F, -0.018463135 * F, + 0.014801025 * F, -0.133590698 * F, -0.050354004 * F, -0.866363525 * F, + 1.063217163 * F, 0.271591187 * F, 0.151596069 * F, 0.021179199 * F, + 0.028533936 * F, -0.000442505 * F, 0.002120972 * F, 0.000137329 * F, + -0.000045776 * F, -0.001205444 * F, 0.003051758 * F, -0.019577026 * F, + 0.012115479 * F, -0.137298584 * F, -0.069168091 * F, -0.890090942 * F, + 1.048156738 * F, 0.246505737 * F, 0.152069092 * F, 0.016708374 * F, + 0.027725220 * F, -0.000869751 * F, 0.002014160 * F, 0.000122070 * F, + -0.000061035 * F, -0.001296997 * F, 0.002883911 * F, -0.020690918 * F, + 0.009231567 * F, -0.140670776 * F, -0.088775635 * F, -0.913055420 * F, + 1.031936646 * F, 0.221984863 * F, 0.151962280 * F, 0.012420654 * F, + 0.026840210 * F, -0.001266479 * F, 0.001907349 * F, 0.000106812 * F, + -0.000061035 * F, -0.001388550 * F, 0.002700806 * F, -0.021789551 * F, + 0.006134033 * F, -0.143676758 * F, -0.109161377 * F, -0.935195923 * F, + 1.014617920 * F, 0.198059082 * F, 0.151306152 * F, 0.008316040 * F, + 0.025909424 * F, -0.001617432 * F, 0.001785278 * F, 0.000106812 * F, + -0.000076294 * F, -0.001480103 * F, 0.002487183 * F, -0.022857666 * F, + 0.002822876 * F, -0.146255493 * F, -0.130310059 * F, -0.956481934 * F, + 0.996246338 * F, 0.174789429 * F, 0.150115967 * F, 0.004394531 * F, + 0.024932861 * F, -0.001937866 * F, 0.001693726 * F, 0.000091553 * F, + -0.000076294 * F, -0.001586914 * F, 0.002227783 * F, -0.023910522 * F, + -0.000686646 * F, -0.148422241 * F, -0.152206421 * F, -0.976852417 * F, + 0.976852417 * F, 0.152206421 * F, 0.148422241 * F, 0.000686646 * F, + 0.023910522 * F, -0.002227783 * F, 0.001586914 * F, 0.000076294 * F, + -0.000091553 * F, -0.001693726 * F, 0.001937866 * F, -0.024932861 * F, + -0.004394531 * F, -0.150115967 * F, -0.174789429 * F, -0.996246338 * F, + 0.956481934 * F, 0.130310059 * F, 0.146255493 * F, -0.002822876 * F, + 0.022857666 * F, -0.002487183 * F, 0.001480103 * F, 0.000076294 * F, + -0.000106812 * F, -0.001785278 * F, 0.001617432 * F, -0.025909424 * F, + -0.008316040 * F, -0.151306152 * F, -0.198059082 * F, -1.014617920 * F, + 0.935195923 * F, 0.109161377 * F, 0.143676758 * F, -0.006134033 * F, + 0.021789551 * F, -0.002700806 * F, 0.001388550 * F, 0.000061035 * F, + -0.000106812 * F, -0.001907349 * F, 0.001266479 * F, -0.026840210 * F, + -0.012420654 * F, -0.151962280 * F, -0.221984863 * F, -1.031936646 * F, + 0.913055420 * F, 0.088775635 * F, 0.140670776 * F, -0.009231567 * F, + 0.020690918 * F, -0.002883911 * F, 0.001296997 * F, 0.000061035 * F, + -0.000122070 * F, -0.002014160 * F, 0.000869751 * F, -0.027725220 * F, + -0.016708374 * F, -0.152069092 * F, -0.246505737 * F, -1.048156738 * F, + 0.890090942 * F, 0.069168091 * F, 0.137298584 * F, -0.012115479 * F, + 0.019577026 * F, -0.003051758 * F, 0.001205444 * F, 0.000045776 * F, + -0.000137329 * F, -0.002120972 * F, 0.000442505 * F, -0.028533936 * F, + -0.021179199 * F, -0.151596069 * F, -0.271591187 * F, -1.063217163 * F, + 0.866363525 * F, 0.050354004 * F, 0.133590698 * F, -0.014801025 * F, + 0.018463135 * F, -0.003173828 * F, 0.001113892 * F, 0.000045776 * F, + -0.000152588 * F, -0.002243042 * F, -0.000030518 * F, -0.029281616 * F, + -0.025817871 * F, -0.150497437 * F, -0.297210693 * F, -1.077117920 * F, + 0.841949463 * F, 0.032379150 * F, 0.129562378 * F, -0.017257690 * F, + 0.017349243 * F, -0.003280640 * F, 0.001037598 * F, 0.000030518 * F, + -0.000167847 * F, -0.002349854 * F, -0.000549316 * F, -0.029937744 * F, + -0.030609131 * F, -0.148773193 * F, -0.323318481 * F, -1.089782715 * F, + 0.816864014 * F, 0.015228271 * F, 0.125259399 * F, -0.019531250 * F, + 0.016235352 * F, -0.003372192 * F, 0.000961304 * F, 0.000030518 * F, + -0.000198364 * F, -0.002456665 * F, -0.001098633 * F, -0.030532837 * F, + -0.035552979 * F, -0.146362305 * F, -0.349868774 * F, -1.101211548 * F, + 0.791213989 * F, -0.001068115 * F, 0.120697021 * F, -0.021575928 * F, + 0.015121460 * F, -0.003417969 * F, 0.000885010 * F, 0.000030518 * F, + -0.000213623 * F, -0.002578735 * F, -0.001693726 * F, -0.031005859 * F, + -0.040634155 * F, -0.143264771 * F, -0.376800537 * F, -1.111373901 * F, + 0.765029907 * F, -0.016510010 * F, 0.115921021 * F, -0.023422241 * F, + 0.014022827 * F, -0.003463745 * F, 0.000808716 * F, 0.000030518 * F, + -0.000244141 * F, -0.002685547 * F, -0.002334595 * F, -0.031387329 * F, + -0.045837402 * F, -0.139450073 * F, -0.404083252 * F, -1.120223999 * F, + 0.738372803 * F, -0.031082153 * F, 0.110946655 * F, -0.025085449 * F, + 0.012939453 * F, -0.003479004 * F, 0.000747681 * F, 0.000015259 * F, + -0.000259399 * F, -0.002792358 * F, -0.003005981 * F, -0.031661987 * F, + -0.051132202 * F, -0.134887695 * F, -0.431655884 * F, -1.127746582 * F, + 0.711318970 * F, -0.044784546 * F, 0.105819702 * F, -0.026535034 * F, + 0.011886597 * F, -0.003479004 * F, 0.000686646 * F, 0.000015259 * F, + -0.000289917 * F, -0.002899170 * F, -0.003723145 * F, -0.031814575 * F, + -0.056533813 * F, -0.129577637 * F, -0.459472656 * F, -1.133926392 * F, + 0.683914185 * F, -0.057617188 * F, 0.100540161 * F, -0.027801514 * F, + 0.010848999 * F, -0.003463745 * F, 0.000625610 * F, 0.000015259 * F, + -0.000320435 * F, -0.002990723 * F, -0.004486084 * F, -0.031845093 * F, + -0.061996460 * F, -0.123474121 * F, -0.487472534 * F, -1.138763428 * F, + 0.656219482 * F, -0.069595337 * F, 0.095169067 * F, -0.028884888 * F, + 0.009841919 * F, -0.003433228 * F, 0.000579834 * F, 0.000015259 * F, + -0.000366211 * F, -0.003082275 * F, -0.005294800 * F, -0.031738281 * F, + -0.067520142 * F, -0.116577148 * F, -0.515609741 * F, -1.142211914 * F, + 0.628295898 * F, -0.080688477 * F, 0.089706421 * F, -0.029785156 * F, + 0.008865356 * F, -0.003387451 * F, 0.000534058 * F, 0.000015259 * F, + -0.000396729 * F, -0.003173828 * F, -0.006118774 * F, -0.031478882 * F, + -0.073059082 * F, -0.108856201 * F, -0.543823242 * F, -1.144287109 * F, + 0.600219727 * F, -0.090927124 * F, 0.084182739 * F, -0.030517578 * F, + 0.007919312 * F, -0.003326416 * F, 0.000473022 * F, 0.000015259 * F + }; +#undef F + int i; + float tmp, *v; + const float *f; + + f = c; + + switch(b->pos) + { + case 0: + v = b->actual; + for (i=0; i<32; i++) + { + tmp = *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + /* ceiling saturation */ + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + /* floor saturation */ + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 1: + v = b->actual + 1; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 2: + v = b->actual + 2; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 3: + v = b->actual + 3; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 4: + v = b->actual + 4; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 5: + v = b->actual + 5; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 6: + v = b->actual + 6; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 7: + v = b->actual + 7; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 8: + v = b->actual + 8; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 9: + v = b->actual + 9; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 10: + v = b->actual + 10; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 11: + v = b->actual + 11; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 12: + v = b->actual + 12; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 13: + v = b->actual + 13; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 14: + v = b->actual + 14; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v; + v += 15; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 15; + } + break; + case 15: + v = b->actual + 15; + for (i=0; i<32; i++) + { + tmp = *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + tmp += *f++ * *v--; + if ((tmp += *f++ * *v) > 32767) + { + *p_pcm = 0x7FFF; + } + else if (tmp < -32768) + { + *p_pcm = 0x8000; + } + else + { + *p_pcm = (s16)tmp; + } + p_pcm += jump; + v += 31; + } + break; + } + + /* Set the next position in the filter bank */ + b->pos++; + b->pos &= 15; + b->actual = (b->actual == b->v1 ? b->v2 : b->v1); +} diff --git a/modules/codec/mpeg_audio/math.h b/modules/codec/mpeg_audio/math.h new file mode 100644 index 0000000000..c8234c9c8e --- /dev/null +++ b/modules/codec/mpeg_audio/math.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * adec_math.h : PCM and DCT + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: math.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * + * 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 + *****************************************************************************/ +void DCT32 ( adec_bank_t *, float * ); +void PCM ( adec_bank_t *, s16 *, int ); + diff --git a/modules/codec/mpeg_audio/test.c b/modules/codec/mpeg_audio/test.c new file mode 100644 index 0000000000..1e66cf1e3a --- /dev/null +++ b/modules/codec/mpeg_audio/test.c @@ -0,0 +1,104 @@ +/***************************************************************************** + * test.c: MPEG Layer I-II audio decoder test program + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: test.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Kaempf + * Michel Lespinasse + * + * 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 +#include + +#include + +#include "generic.h" +#include "decoder.h" + +#define ADEC_FRAME_SIZE (2*1152) + +int main (void) +{ + audiodec_t decoder; + adec_sync_info_t sync_info; + adec_byte_stream_t * stream; + s16 buffer [ADEC_FRAME_SIZE]; + + int framenum; + + memset (&decoder, 0, sizeof (decoder)); + if (adec_init (&decoder)) + { + return 1; + } + + stream = adec_byte_stream (&decoder); + stream->p_byte = NULL; + stream->p_end = NULL; + stream->info = stdin; + + framenum = 0; + + while (1) + { + int i; + + if (adec_sync_frame (&decoder, &sync_info)) + { + return 1; + } + if (adec_decode_frame (&decoder, buffer)) + { + return 1; + } + +#if 1 + for (i = 0; i < (2*1152); i++) + { + fprintf ( stderr, "%04X\n",(u16)buffer[i] ); + } +#endif + } + + return 0; +} + +void adec_byte_stream_next (adec_byte_stream_t * p_byte_stream) +{ + static u8 buffer [1024]; + static u8 dummy = 0; + FILE * fd; + int size; + + fd = p_byte_stream->info; + size = fread (buffer, 1, 1024, fd); + if (size) + { + p_byte_stream->p_byte = buffer; + p_byte_stream->p_end = buffer + size; + } + else + { /* end of stream, read dummy zeroes */ + p_byte_stream->p_byte = &dummy; + p_byte_stream->p_end = &dummy + 1; + } +} diff --git a/modules/codec/mpeg_video/.cvsignore b/modules/codec/mpeg_video/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/mpeg_video/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/mpeg_video/Makefile b/modules/codec/mpeg_video/Makefile new file mode 100644 index 0000000000..b9e97b9f99 --- /dev/null +++ b/modules/codec/mpeg_video/Makefile @@ -0,0 +1,5 @@ +ifeq ($(ARCH),hppa64) +CFLAGS += -ffunction-sections +endif + +mpeg_video_SOURCES = parser.c headers.c blocks.c synchro.c pool.c decoder.c diff --git a/modules/codec/mpeg_video/blocks.c b/modules/codec/mpeg_video/blocks.c new file mode 100644 index 0000000000..c28dd7b416 --- /dev/null +++ b/modules/codec/mpeg_video/blocks.c @@ -0,0 +1,2205 @@ +/***************************************************************************** + * blocks.c : blocks parsing + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: blocks.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Lespinasse + * Aaron Holtzman + * Christophe Massiot + * + * 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 /* memset */ + +#include +#include +#include + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" +#include "blocks.h" + +/* + * Welcome to vpar_blocks.c ! Here's where the heavy processor-critical parsing + * task is done. This file is divided in several parts : + * - Decoding of coded blocks + * - Decoding of motion vectors + * - Decoding of the other macroblock structures + * - Picture data parsing management (slices and error handling) + * It's a pretty long file. Good luck and have a nice day. + */ + + +/***************************************************************************** + * vpar_InitScanTable : Initialize scan table + *****************************************************************************/ +void vpar_InitScanTable( vpar_thread_t * p_vpar ) +{ + int i; + + memcpy( p_vpar->ppi_scan, pi_scan, sizeof(pi_scan) ); + p_vpar->pf_norm_scan( p_vpar->ppi_scan ); + + /* If scan table has changed, we must change the quantization matrices. */ + for( i = 0; i < 64; i++ ) + { + p_vpar->pi_default_intra_quant[ p_vpar->ppi_scan[0][i] ] = + pi_default_intra_quant[ pi_scan[0][i] ]; + p_vpar->pi_default_nonintra_quant[ p_vpar->ppi_scan[0][i] ] = + pi_default_nonintra_quant[ pi_scan[0][i] ]; + } +} + + +/* + * Block parsing + */ + +/***************************************************************************** + * GetLumaDCDiff : Get the luminance DC coefficient difference + *****************************************************************************/ +static inline int GetLumaDCDiff( vpar_thread_t * p_vpar ) +{ + lookup_t * p_tab; + int i_size, i_dc_diff, i_code; + + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) < 0x1F ) + { + p_tab = DC_lum_5 + i_code; + i_size = p_tab->i_value; + if( i_size ) + { + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_dc_diff = GetBits( &p_vpar->bit_stream, i_size ); + if ((i_dc_diff & (1 << (i_size - 1))) == 0) + { + i_dc_diff -= (1 << i_size) - 1; + } + return( i_dc_diff ); + } + else + { + RemoveBits( &p_vpar->bit_stream, 3 ); + return 0; + } + } + else + { + p_tab = DC_long - 0x1e0 + ShowBits( &p_vpar->bit_stream, 9 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_size = p_tab->i_value; + i_dc_diff = GetBits( &p_vpar->bit_stream, i_size ); + if ((i_dc_diff & (1 << (i_size - 1))) == 0) + { + i_dc_diff -= (1 << i_size) - 1; + } + return( i_dc_diff ); + } +} + +/***************************************************************************** + * GetChromaDCDiff : Get the chrominance DC coefficient difference + *****************************************************************************/ +static inline int GetChromaDCDiff( vpar_thread_t * p_vpar ) +{ + lookup_t * p_tab; + int i_size, i_dc_diff, i_code; + + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) < 0x1F ) + { + p_tab = DC_chrom_5 + i_code; + i_size = p_tab->i_value; + if( i_size ) + { + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_dc_diff = GetBits( &p_vpar->bit_stream, i_size ); + if ((i_dc_diff & (1 << (i_size - 1))) == 0) + { + i_dc_diff -= (1 << i_size) - 1; + } + return( i_dc_diff ); + } + else + { + RemoveBits( &p_vpar->bit_stream, 2 ); + return 0; + } + } + else + { + p_tab = DC_long - 0x3e0 + ShowBits( &p_vpar->bit_stream, 10 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length + 1 ); + i_size = p_tab->i_value; + i_dc_diff = GetBits( &p_vpar->bit_stream, i_size ); + if ((i_dc_diff & (1 << (i_size - 1))) == 0) + { + i_dc_diff -= (1 << i_size) - 1; + } + return( i_dc_diff ); + } +} + + +#define SATURATE(val) \ + if ((u32)(val + 2048) > 4095) \ + { \ + val = (val > 0) ? 2047 : -2048; \ + } + +/***************************************************************************** + * MPEG2IntraB14 : Decode an intra block according to ISO/IEC 13818-2 table B14 + *****************************************************************************/ +static void MPEG2IntraB14( vpar_thread_t * p_vpar, idct_inner_t * p_idct, + u8 * pi_quant ) +{ + int i_coeff, i_mismatch, i_code, i_pos, i_value, i_nc; + s32 i_sign; + dct_lookup_t * p_tab; + + int i_q_scale = p_vpar->mb.i_quantizer_scale; + dctelem_t * p_dest = p_idct->pi_block; + u8 * p_scan = p_vpar->picture.pi_scan; + + i_coeff = 0; + i_mismatch = ~p_dest[0]; + i_nc = (p_dest[0] != 0); + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14AC_5 - 5 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff >= 64 ) + { + /* End of block */ + break; + } + +store_coeff: + i_nc++; + i_pos = p_scan[ i_coeff ]; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_value = (p_tab->i_level * i_q_scale * pi_quant[i_pos]) + >> 4; + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + /* if (i_sign) i_value = -i_value; */ + i_value = (i_value ^ i_sign) - i_sign; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 8 )) >= 0x4 ) + { + p_tab = DCT_B14_8 - 4 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + /* Normal coefficient */ + goto store_coeff; + } + + /* Escape code */ + i_coeff += (GetBits( &p_vpar->bit_stream, 12 ) & 0x3F) - 64; + if( i_coeff >= 64 ) + { + /* Illegal, but needed to avoid overflow */ + msg_Warn( p_vpar->p_fifo, "intra-B14 coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + i_nc++; + i_pos = p_scan[i_coeff]; + i_value = (GetSignedBits( &p_vpar->bit_stream, 12 ) + * i_q_scale * pi_quant[i_pos]) / 16; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 16)) >= 0x0200 ) + { + p_tab = DCT_B14_10 - 8 + (i_code >> 6); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0080 ) + { + p_tab = DCT_13 - 16 + (i_code >> 3); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0020 ) + { + p_tab = DCT_15 - 16 + (i_code >> 1); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else + { + p_tab = DCT_16 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + + msg_Warn( p_vpar->p_fifo, "intra-B14 coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + p_dest[63] ^= i_mismatch & 1; + RemoveBits( &p_vpar->bit_stream, 2 ); /* End of Block */ + + if( i_nc <= 1 ) + { + if( p_dest[63] ) + { + if( i_nc == 0 ) + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_copy; + p_idct->i_sparse_pos = 63; + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_copy; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_copy; + p_idct->i_sparse_pos = i_coeff - p_tab->i_run; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_copy; + } +} + +/***************************************************************************** + * MPEG2IntraB15 : Decode an intra block according to ISO/IEC 13818-2 table B15 + *****************************************************************************/ +static void MPEG2IntraB15( vpar_thread_t * p_vpar, idct_inner_t * p_idct, + u8 * pi_quant ) +{ + int i_coeff, i_mismatch, i_code, i_pos, i_value, i_nc; + s32 i_sign; + dct_lookup_t * p_tab; + + int i_q_scale = p_vpar->mb.i_quantizer_scale; + dctelem_t * p_dest = p_idct->pi_block; + u8 * p_scan = p_vpar->picture.pi_scan; + + i_coeff = 0; + i_mismatch = ~p_dest[0]; + i_nc = (p_dest[0] != 0); + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 8 )) >= 0x4 ) + { + p_tab = DCT_B15_8 - 4 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + +store_coeff: + i_nc++; + i_pos = p_scan[ i_coeff ]; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_value = (p_tab->i_level * i_q_scale * pi_quant[i_pos]) + >> 4; + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + /* if (i_sign) i_value = -i_value; */ + i_value = (i_value ^ i_sign) - i_sign; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + + continue; + } + else + { + if( i_coeff >= 128 ) + { + /* End of block */ + break; + } + + /* Escape code */ + i_coeff += (GetBits( &p_vpar->bit_stream, 12 ) & 0x3F) - 64; + if( i_coeff >= 64 ) + { + /* Illegal, but needed to avoid overflow */ + msg_Warn( p_vpar->p_fifo, + "intra-B15 coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + i_nc++; + i_pos = p_scan[i_coeff]; + i_value = (GetSignedBits( &p_vpar->bit_stream, 12 ) + * i_q_scale * pi_quant[i_pos]) / 16; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + continue; + } + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 16)) >= 0x0200 ) + { + p_tab = DCT_B15_10 - 8 + (i_code >> 6); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0080 ) + { + p_tab = DCT_13 - 16 + (i_code >> 3); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0020 ) + { + p_tab = DCT_15 - 16 + (i_code >> 1); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else + { + p_tab = DCT_16 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + + msg_Warn( p_vpar->p_fifo, "intra-B15 coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + p_dest[63] ^= i_mismatch & 1; + RemoveBits( &p_vpar->bit_stream, 4 ); /* End of Block */ + + if( i_nc <= 1 ) + { + if( p_dest[63] ) + { + if( i_nc == 0 ) + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_copy; + p_idct->i_sparse_pos = 63; + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_copy; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_copy; + p_idct->i_sparse_pos = i_coeff - p_tab->i_run; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_copy; + } +} + +/***************************************************************************** + * MPEG2NonIntra : Decode a non-intra MPEG-2 block + *****************************************************************************/ +static void MPEG2NonIntra( vpar_thread_t * p_vpar, idct_inner_t * p_idct, + u8 * pi_quant ) +{ + int i_coeff, i_mismatch, i_code, i_pos, i_value, i_nc; + s32 i_sign; + dct_lookup_t * p_tab; + + int i_q_scale = p_vpar->mb.i_quantizer_scale; + dctelem_t * p_dest = p_idct->pi_block; + u8 * p_scan = p_vpar->picture.pi_scan; + + i_coeff = -1; + i_mismatch = 1; + i_nc = 0; + + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14DC_5 - 5 + i_code; + goto coeff_1; + } + else + { + goto coeff_2; + } + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14AC_5 - 5 + i_code; +coeff_1: + i_coeff += p_tab->i_run; + if( i_coeff >= 64 ) + { + /* End of block */ + break; + } + +store_coeff: + i_nc++; + i_pos = p_scan[ i_coeff ]; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_value = ((2 * p_tab->i_level + 1) * i_q_scale * pi_quant[i_pos]) + >> 5; + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + /* if (i_sign) i_value = -i_value; */ + i_value = (i_value ^ i_sign) - i_sign; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + + continue; + } +coeff_2: + if( (i_code = ShowBits( &p_vpar->bit_stream, 8 )) >= 0x4 ) + { + p_tab = DCT_B14_8 - 4 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + /* Normal coefficient */ + goto store_coeff; + } + + /* Escape code */ + i_coeff += (GetBits( &p_vpar->bit_stream, 12 ) & 0x3F) - 64; + if( i_coeff >= 64 ) + { + /* Illegal, but needed to avoid overflow */ + msg_Warn( p_vpar->p_fifo, + "MPEG2NonIntra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + i_nc++; + i_pos = p_scan[i_coeff]; + i_value = 2 * (ShowSignedBits( &p_vpar->bit_stream, 1 ) + + GetSignedBits( &p_vpar->bit_stream, 12 )) + 1; + + i_value = (i_value * i_q_scale * pi_quant[i_pos]) / 32; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + i_mismatch ^= i_value; + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 16)) >= 0x0200 ) + { + p_tab = DCT_B14_10 - 8 + (i_code >> 6); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0080 ) + { + p_tab = DCT_13 - 16 + (i_code >> 3); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0020 ) + { + p_tab = DCT_15 - 16 + (i_code >> 1); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else + { + p_tab = DCT_16 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + + msg_Warn( p_vpar->p_fifo, "MPEG2NonIntra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + p_dest[63] ^= i_mismatch & 1; + RemoveBits( &p_vpar->bit_stream, 2 ); /* End of Block */ + + if( i_nc <= 1 ) + { + if( p_dest[63] ) + { + if( i_nc == 0 ) + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_add; + p_idct->i_sparse_pos = 63; + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_add; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_add; + if( i_nc == 0 ) + { + p_idct->i_sparse_pos = 0; + } + else + { + p_idct->i_sparse_pos = i_coeff - p_tab->i_run; + } + } + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_add; + } +} + +/***************************************************************************** + * MPEG1Intra : Decode an MPEG-1 intra block + *****************************************************************************/ +static void MPEG1Intra( vpar_thread_t * p_vpar, idct_inner_t * p_idct, + u8 * pi_quant ) +{ + int i_coeff, i_code, i_pos, i_value, i_nc; + s32 i_sign; + dct_lookup_t * p_tab; + + int i_q_scale = p_vpar->mb.i_quantizer_scale; + dctelem_t * p_dest = p_idct->pi_block; + u8 * p_scan = p_vpar->picture.pi_scan; + + i_coeff = 0; + i_nc = (p_dest[0] != 0); + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14AC_5 - 5 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff >= 64 ) + { + /* End of block */ + break; + } + +store_coeff: + i_nc++; + i_pos = p_scan[ i_coeff ]; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_value = (p_tab->i_level * i_q_scale * pi_quant[i_pos]) + >> 4; + + /* Oddification */ + i_value = (i_value - 1) | 1; + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + /* if (i_sign) i_value = -i_value; */ + i_value = (i_value ^ i_sign) - i_sign; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 8 )) >= 0x4 ) + { + p_tab = DCT_B14_8 - 4 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + /* Normal coefficient */ + goto store_coeff; + } + + /* Escape code */ + i_coeff += (GetBits( &p_vpar->bit_stream, 12 ) & 0x3F) - 64; + if( i_coeff >= 64 ) + { + /* Illegal, but needed to avoid overflow */ + msg_Warn( p_vpar->p_fifo, + "MPEG1Intra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + i_nc++; + i_pos = p_scan[i_coeff]; + + i_value = ShowSignedBits( &p_vpar->bit_stream, 8 ); + if( !(i_value & 0x7F) ) + { + RemoveBits( &p_vpar->bit_stream, 8 ); + i_value = ShowBits( &p_vpar->bit_stream, 8 ) + 2 * i_value; + } + + i_value = (i_value * i_q_scale * pi_quant[i_pos]) / 16; + + /* Oddification */ + i_value = (i_value + ~ShowSignedBits( &p_vpar->bit_stream, 1 )) | 1; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + RemoveBits( &p_vpar->bit_stream, 8 ); + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 16)) >= 0x0200 ) + { + p_tab = DCT_B14_10 - 8 + (i_code >> 6); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0080 ) + { + p_tab = DCT_13 - 16 + (i_code >> 3); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0020 ) + { + p_tab = DCT_15 - 16 + (i_code >> 1); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else + { + p_tab = DCT_16 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + + msg_Warn( p_vpar->p_fifo, "MPEG1Intra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + RemoveBits( &p_vpar->bit_stream, 2 ); /* End of Block */ + + if( i_nc <= 1 ) + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_copy; + p_idct->i_sparse_pos = i_coeff - p_tab->i_run; + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_copy; + } +} + +/***************************************************************************** + * MPEG1NonIntra : Decode a non-intra MPEG-1 block + *****************************************************************************/ +static void MPEG1NonIntra( vpar_thread_t * p_vpar, idct_inner_t * p_idct, + u8 * pi_quant ) +{ + int i_coeff, i_code, i_pos, i_value, i_nc; + s32 i_sign; + dct_lookup_t * p_tab; + + int i_q_scale = p_vpar->mb.i_quantizer_scale; + dctelem_t * p_dest = p_idct->pi_block; + u8 * p_scan = p_vpar->picture.pi_scan; + + i_coeff = -1; + i_nc = 0; + + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14DC_5 - 5 + i_code; + goto coeff_1; + } + else + { + goto coeff_2; + } + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 )) >= 0x5 ) + { + p_tab = DCT_B14AC_5 - 5 + i_code; +coeff_1: + i_coeff += p_tab->i_run; + if( i_coeff >= 64 ) + { + /* End of block */ + break; + } + +store_coeff: + i_nc++; + i_pos = p_scan[ i_coeff ]; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_value = ((2 * p_tab->i_level + 1) * i_q_scale * pi_quant[i_pos]) + >> 5; + + /* Oddification */ + i_value = (i_value - 1) | 1; + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + /* if (i_sign) i_value = -i_value; */ + i_value = (i_value ^ i_sign) - i_sign; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + + continue; + } +coeff_2: + if( (i_code = ShowBits( &p_vpar->bit_stream, 8 )) >= 0x4 ) + { + p_tab = DCT_B14_8 - 4 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + /* Normal coefficient */ + goto store_coeff; + } + + /* Escape code */ + i_coeff += (GetBits( &p_vpar->bit_stream, 12 ) & 0x3F) - 64; + if( i_coeff >= 64 ) + { + /* Illegal, but needed to avoid overflow */ + msg_Warn( p_vpar->p_fifo, + "MPEG1NonIntra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + i_nc++; + i_pos = p_scan[i_coeff]; + i_value = ShowSignedBits( &p_vpar->bit_stream, 8 ); + if( !(i_value & 0x7F) ) + { + RemoveBits( &p_vpar->bit_stream, 8 ); + i_value = ShowBits( &p_vpar->bit_stream, 8 ) + 2 * i_value; + } + i_sign = ShowSignedBits( &p_vpar->bit_stream, 1 ); + i_value = 2 * (i_sign + i_value) + 1; + i_value = (i_value * i_q_scale * pi_quant[i_pos]) / 32; + + /* Oddification */ + i_value = (i_value + ~i_sign) | 1; + + SATURATE( i_value ); + p_dest[i_pos] = i_value; + RemoveBits( &p_vpar->bit_stream, 8 ); + continue; + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 16)) >= 0x0200 ) + { + p_tab = DCT_B14_10 - 8 + (i_code >> 6); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0080 ) + { + p_tab = DCT_13 - 16 + (i_code >> 3); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else if( i_code >= 0x0020 ) + { + p_tab = DCT_15 - 16 + (i_code >> 1); + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + else + { + p_tab = DCT_16 + i_code; + i_coeff += p_tab->i_run; + if( i_coeff < 64 ) + { + goto store_coeff; + } + } + + msg_Warn( p_vpar->p_fifo, "MPEG1NonIntra coeff is out of bounds" ); + p_vpar->picture.b_error = 1; + break; + } + + RemoveBits( &p_vpar->bit_stream, 2 ); /* End of Block */ + + if( i_nc <= 1 ) + { + p_idct->pf_idct = p_vpar->pf_sparse_idct_add; + if( i_nc == 0 ) + { + p_idct->i_sparse_pos = 0; + } + else + { + p_idct->i_sparse_pos = i_coeff - p_tab->i_run; + } + } + else + { + p_idct->pf_idct = p_vpar->pf_idct_add; + } +} + +#undef SATURATE + +/***************************************************************************** + * *MB : decode all blocks of the macroblock + *****************************************************************************/ +#define DECODE_LUMABLOCK( I_B, PF_MBFUNC ) \ + p_idct = &p_mb->p_idcts[I_B]; \ + memset( p_idct->pi_block, 0, 64*sizeof(dctelem_t) ); \ + p_vpar->mb.pi_dc_dct_pred[0] += GetLumaDCDiff( p_vpar ); \ + p_idct->pi_block[0] = p_vpar->mb.pi_dc_dct_pred[0] \ + << (3 - p_vpar->picture.i_intra_dc_precision ); \ + PF_MBFUNC( p_vpar, p_idct, p_vpar->sequence.intra_quant.pi_matrix ); + +#define DECODE_CHROMABLOCK( I_B, PF_MBFUNC, I_CC ) \ + p_idct = &p_mb->p_idcts[I_B]; \ + memset( p_idct->pi_block, 0, 64*sizeof(dctelem_t) ); \ + p_vpar->mb.pi_dc_dct_pred[I_CC] += GetChromaDCDiff( p_vpar ); \ + p_idct->pi_block[0] = p_vpar->mb.pi_dc_dct_pred[I_CC] \ + << (3 - p_vpar->picture.i_intra_dc_precision ); \ + PF_MBFUNC( p_vpar, p_idct, \ + p_vpar->sequence.chroma_intra_quant.pi_matrix ); + +#define DECLARE_INTRAMB( PSZ_NAME, PF_MBFUNC ) \ +static inline void PSZ_NAME( vpar_thread_t * p_vpar, macroblock_t * p_mb ) \ +{ \ + idct_inner_t * p_idct; \ + int i_b = 4; \ + \ + p_mb->p_y_data = p_mb->pp_dest[0] + p_vpar->mb.i_offset; \ + p_mb->p_u_data = p_mb->pp_dest[1] + (p_vpar->mb.i_offset \ + >> p_vpar->sequence.b_chroma_h_subsampled); \ + p_mb->p_v_data = p_mb->pp_dest[2] + (p_vpar->mb.i_offset \ + >> p_vpar->sequence.b_chroma_h_subsampled); \ + \ + DECODE_LUMABLOCK( 0, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 1, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 2, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 3, PF_MBFUNC ); \ + \ + do \ + { \ + DECODE_CHROMABLOCK( i_b, PF_MBFUNC, 1 ); \ + DECODE_CHROMABLOCK( i_b + 1, PF_MBFUNC, 2 ); \ + i_b += 2; \ + } \ + while( i_b < 4 + p_vpar->sequence.i_chroma_nb_blocks ); \ +} + +DECLARE_INTRAMB( MPEG1IntraMB, MPEG1Intra ); +DECLARE_INTRAMB( MPEG2IntraB14MB, MPEG2IntraB14 ); +DECLARE_INTRAMB( MPEG2IntraB15MB, MPEG2IntraB15 ); + +#undef DECLARE_INTRAMB +#undef DECODE_LUMABLOCK +#undef DECODE_CHROMABLOCK + +#define DECODE_LUMABLOCK( I_B, PF_MBFUNC ) \ + if( p_mb->i_coded_block_pattern & (1 << (11 - (I_B))) ) \ + { \ + p_idct = &p_mb->p_idcts[I_B]; \ + memset( p_idct->pi_block, 0, 64*sizeof(dctelem_t) ); \ + PF_MBFUNC( p_vpar, p_idct, \ + p_vpar->sequence.nonintra_quant.pi_matrix ); \ + } + +#define DECODE_CHROMABLOCK( I_B, PF_MBFUNC ) \ + if( p_mb->i_coded_block_pattern & (1 << (11 - (I_B))) ) \ + { \ + p_idct = &p_mb->p_idcts[I_B]; \ + memset( p_idct->pi_block, 0, 64*sizeof(dctelem_t) ); \ + PF_MBFUNC( p_vpar, p_idct, \ + p_vpar->sequence.chroma_nonintra_quant.pi_matrix ); \ + } + +#define DECLARE_NONINTRAMB( PSZ_NAME, PF_MBFUNC ) \ +static inline void PSZ_NAME( vpar_thread_t * p_vpar, macroblock_t * p_mb ) \ +{ \ + idct_inner_t * p_idct; \ + int i_b = 4; \ + \ + p_mb->p_y_data = p_mb->pp_dest[0] + p_vpar->mb.i_offset; \ + p_mb->p_u_data = p_mb->pp_dest[1] + (p_vpar->mb.i_offset \ + >> p_vpar->sequence.b_chroma_h_subsampled); \ + p_mb->p_v_data = p_mb->pp_dest[2] + (p_vpar->mb.i_offset \ + >> p_vpar->sequence.b_chroma_h_subsampled); \ + \ + DECODE_LUMABLOCK( 0, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 1, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 2, PF_MBFUNC ); \ + DECODE_LUMABLOCK( 3, PF_MBFUNC ); \ + \ + do \ + { \ + DECODE_CHROMABLOCK( i_b, PF_MBFUNC ); \ + DECODE_CHROMABLOCK( i_b + 1, PF_MBFUNC ); \ + i_b += 2; \ + } \ + while( i_b < 4 + p_vpar->sequence.i_chroma_nb_blocks ); \ +} + +DECLARE_NONINTRAMB( MPEG1NonIntraMB, MPEG1NonIntra ); +DECLARE_NONINTRAMB( MPEG2NonIntraMB, MPEG2NonIntra ); + +#undef DECLARE_NONINTRAMB +#undef DECODE_LUMABLOCK +#undef DECODE_CHROMABLOCK + + +/* + * Motion vectors + */ + +/**************************************************************************** + * MotionDelta : Parse the next motion delta + ****************************************************************************/ +static inline int MotionDelta( vpar_thread_t * p_vpar, int i_f_code ) +{ + int i_delta, i_sign, i_code; + lookup_t * p_tab; + + if( ShowBits( &p_vpar->bit_stream, 1 ) ) + { + RemoveBits( &p_vpar->bit_stream, 1 ); + return 0; + } + + if( (i_code = ShowBits( &p_vpar->bit_stream, 6 )) >= 0x3 ) + { + p_tab = MV_4 + (i_code >> 2); + i_delta = (p_tab->i_value << i_f_code) + 1; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + if( i_f_code ) + { + i_delta += GetBits( &p_vpar->bit_stream, i_f_code ); + } + + return (i_delta ^ i_sign) - i_sign; + + } + else + { + p_tab = MV_10 + ShowBits( &p_vpar->bit_stream, 10 ); + i_delta = (p_tab->i_value << i_f_code) + 1; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + + i_sign = GetSignedBits( &p_vpar->bit_stream, 1 ); + if( i_f_code ) + { + i_delta += GetBits( &p_vpar->bit_stream, i_f_code ); + } + + return (i_delta ^ i_sign) - i_sign; + } +} + +/**************************************************************************** + * BoundMotionVector : Bound a motion_vector :-) + ****************************************************************************/ +static inline int BoundMotionVector( int i_vector, int i_f_code ) +{ + int i_limit; + + i_limit = 16 << i_f_code; + + if( i_vector >= i_limit ) + { + return i_vector - 2 * i_limit; + } + else if( i_vector < -i_limit) + { + return i_vector + 2 * i_limit; + } + else + { + return i_vector; + } +} + +/**************************************************************************** + * GetDMV : Decode a differential motion vector (Dual Prime Arithmetic) + ****************************************************************************/ +static inline int GetDMV( vpar_thread_t * p_vpar ) +{ + dmv_lookup_t * p_tab; + + p_tab = DMV_2 + ShowBits( &p_vpar->bit_stream, 2 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + return( p_tab->i_value ); +} + +/**************************************************************************** + * Motion* : Parse motion vectors + ****************************************************************************/ +#define MOTION_BLOCK( b_aver, i_x, i_y, i_dest, \ + pp_src, i_src, i_str, i_hei, \ + b_s_half ) \ + do { \ + motion_inner_t * p_m_inner = p_mb->p_motions + p_mb->i_nb_motions; \ + p_m_inner->b_average = b_aver; \ + p_m_inner->i_x_pred = i_x; \ + p_m_inner->i_y_pred = i_y; \ + p_m_inner->pp_source[0] = pp_src[0]; \ + p_m_inner->pp_source[1] = pp_src[1]; \ + p_m_inner->pp_source[2] = pp_src[2]; \ + p_m_inner->i_dest_offset = i_dest; \ + p_m_inner->i_src_offset = i_src; \ + p_m_inner->i_stride = i_str; \ + p_m_inner->i_height = i_hei; \ + p_m_inner->b_second_half = b_s_half; \ + p_mb->i_nb_motions++; \ + } while( 0 ); + +/* MPEG-1 predictions. */ + +static void MotionMPEG1( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[0][0] = i_motion_x; + + i_motion_y = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[0][1] = i_motion_y; + + if( p_motion->pi_f_code[1] ) + { + i_motion_x <<= 1; + i_motion_y <<= 1; + } + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[0], i_offset, i_width, 16, 0 ); +} + +static void MotionMPEG1Reuse( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + i_motion_x = p_motion->ppi_pmv[0][0]; + i_motion_y = p_motion->ppi_pmv[0][1]; + + if( p_motion->pi_f_code[1] ) + { + i_motion_x <<= 1; + i_motion_y <<= 1; + } + + MOTION_BLOCK( b_average, p_motion->ppi_pmv[0][0], p_motion->ppi_pmv[0][1], + i_offset, p_motion->pppi_ref[0], i_offset, i_width, 16, 0 ); +} + +/* MPEG-2 frame predictions. */ + +static void MotionFrameFrame( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_motion_x; + + i_motion_y = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_motion_y; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[0], i_offset, i_width, 16, 0 ); +} + +static void MotionFrameField( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y, i_field_select; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + i_field_select = GetSignedBits( &p_vpar->bit_stream, 1 ); + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[0][0] = i_motion_x; + + i_motion_y = (p_motion->ppi_pmv[0][1] >> 1) + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + /* According to ISO/IEC 13818-2 section 7.6.3.2, the vertical motion + * vector is restricted to a range that implies it doesn't need to + * be bound. */ + /* i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); */ + p_motion->ppi_pmv[0][1] = i_motion_y << 1; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[0], i_offset + (i_field_select & i_width), + i_width * 2, 8, 0 ); + + i_field_select = GetSignedBits( &p_vpar->bit_stream, 1 ); + + i_motion_x = p_motion->ppi_pmv[1][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = i_motion_x; + + i_motion_y = (p_motion->ppi_pmv[1][1] >> 1) + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + /* i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); */ + p_motion->ppi_pmv[1][1] = i_motion_y << 1; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset + i_width, + p_motion->pppi_ref[0], i_offset + (i_field_select & i_width), + i_width * 2, 8, 0 ); +} + +static void MotionFrameDMV( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + int i_dmv_x, i_dmv_y; + int i_tmp_x, i_tmp_y; + + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + int m; + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_motion_x; + + i_dmv_x = GetDMV( p_vpar ); + + i_motion_y = (p_motion->ppi_pmv[0][1] >> 1) + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + /* i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); */ + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_motion_y << 1; + + i_dmv_y = GetDMV( p_vpar ); + + /* First field. */ + MOTION_BLOCK( 0, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[0], i_offset, i_width * 2, 8, 0 ); + m = p_vpar->picture.b_top_field_first ? 1 : 3; + i_tmp_x = ((i_motion_x * m + (i_motion_x > 0)) >> 1) + i_dmv_x; + i_tmp_y = ((i_motion_y * m + (i_motion_y > 0)) >> 1) + i_dmv_y - 1; + MOTION_BLOCK( 1, i_tmp_x, i_tmp_y, i_offset, p_motion->pppi_ref[0], + i_offset + i_width, i_width * 2, 8, 0 ); + + /* Second field. */ + MOTION_BLOCK( 0, i_motion_x, i_motion_y, i_offset + i_width, + p_motion->pppi_ref[0], i_offset + i_width, i_width * 2, 8, 0 ); + m = p_vpar->picture.b_top_field_first ? 3 : 1; + i_tmp_x = ((i_motion_x * m + (i_motion_x > 0)) >> 1) + i_dmv_x; + i_tmp_y = ((i_motion_y * m + (i_motion_y > 0)) >> 1) + i_dmv_y + 1; + MOTION_BLOCK( 1, i_tmp_x, i_tmp_y, i_offset + i_width, + p_motion->pppi_ref[0], i_offset, i_width * 2, 8, 0 ); +} + +static void MotionFrameZero( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + MOTION_BLOCK( b_average, 0, 0, i_offset, p_motion->pppi_ref[0], + i_offset, i_width, 16, 0 ); +} + +static void MotionFrameReuse( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + MOTION_BLOCK( b_average, p_motion->ppi_pmv[0][0], p_motion->ppi_pmv[0][1], + i_offset, p_motion->pppi_ref[0], i_offset, i_width, 16, 0 ); +} + +/* MPEG-2 field predictions. */ + +static void MotionFieldField( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + vlc_bool_t b_field_select; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + b_field_select = GetBits( &p_vpar->bit_stream, 1 ); + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_motion_x; + + i_motion_y = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_motion_y; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[b_field_select], i_offset, i_width, 16, 0 ); +} + +static void MotionField16x8( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + vlc_bool_t b_field_select; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + + /* First half. */ + b_field_select = GetBits( &p_vpar->bit_stream, 1 ); + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[0][0] = i_motion_x; + + i_motion_y = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[0][1] = i_motion_y; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[b_field_select], i_offset, i_width, 8, 0 ); + + /* Second half. */ + b_field_select = GetBits( &p_vpar->bit_stream, 1 ); + + i_motion_x = p_motion->ppi_pmv[1][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = i_motion_x; + + i_motion_y = p_motion->ppi_pmv[1][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = i_motion_y; + + MOTION_BLOCK( b_average, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[b_field_select], i_offset, i_width, 8, 1 ); +} + +static void MotionFieldDMV( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_motion_x, i_motion_y; + int i_dmv_x, i_dmv_y; + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + vlc_bool_t b_current_field = p_vpar->picture.b_current_field; + + i_motion_x = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_motion_x = BoundMotionVector( i_motion_x, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_motion_x; + + i_dmv_x = GetDMV( p_vpar ); + + i_motion_y = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_motion_y = BoundMotionVector( i_motion_y, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_motion_y; + + i_dmv_y = GetDMV( p_vpar ); + + MOTION_BLOCK( 0, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[b_current_field], + i_offset, i_width, 16, 0 ); + + i_motion_x = ((i_motion_x + (i_motion_x > 0)) >> 1) + i_dmv_x; + i_motion_y = ((i_motion_y + (i_motion_y > 0)) >> 1) + i_dmv_y + + 2 * b_current_field - 1; + MOTION_BLOCK( 1, i_motion_x, i_motion_y, i_offset, + p_motion->pppi_ref[!b_current_field], + i_offset, i_width, 16, 0 ); +} + +static void MotionFieldZero( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + vlc_bool_t b_current_field = p_vpar->picture.b_current_field; + + MOTION_BLOCK( b_average, 0, 0, i_offset, p_motion->pppi_ref[b_current_field], + i_offset, i_width, 16, 0 ); +} + +static void MotionFieldReuse( vpar_thread_t * p_vpar, + macroblock_t * p_mb, + motion_t * p_motion, + vlc_bool_t b_average ) +{ + int i_offset = p_vpar->mb.i_offset; + int i_width = p_vpar->picture.i_lum_stride; + vlc_bool_t b_current_field = p_vpar->picture.b_current_field; + + MOTION_BLOCK( b_average, p_motion->ppi_pmv[0][0], p_motion->ppi_pmv[0][1], + i_offset, p_motion->pppi_ref[b_current_field], + i_offset, i_width, 16, 0 ); +} + +/* MPEG-2 concealment motion vectors. */ + +static void MotionFrameConceal( vpar_thread_t * p_vpar, + macroblock_t * p_mv, + motion_t * p_motion ) +{ + int i_tmp; + + i_tmp = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_tmp = BoundMotionVector( i_tmp, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_tmp; + + i_tmp = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_tmp = BoundMotionVector( i_tmp, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_tmp; + + /* Marker bit. */ + RemoveBits( &p_vpar->bit_stream, 1 ); +} + +static void MotionFieldConceal( vpar_thread_t * p_vpar, + macroblock_t * p_mv, + motion_t * p_motion ) +{ + int i_tmp; + + /* field_select */ + RemoveBits( &p_vpar->bit_stream, 1 ); + + i_tmp = p_motion->ppi_pmv[0][0] + + MotionDelta( p_vpar, p_motion->pi_f_code[0] ); + i_tmp = BoundMotionVector( i_tmp, p_motion->pi_f_code[0] ); + p_motion->ppi_pmv[1][0] = p_motion->ppi_pmv[0][0] = i_tmp; + + i_tmp = p_motion->ppi_pmv[0][1] + + MotionDelta( p_vpar, p_motion->pi_f_code[1] ); + i_tmp = BoundMotionVector( i_tmp, p_motion->pi_f_code[1] ); + p_motion->ppi_pmv[1][1] = p_motion->ppi_pmv[0][1] = i_tmp; + + /* Marker bit. */ + RemoveBits( &p_vpar->bit_stream, 1 ); +} + + +/* + * Macroblock information structures + */ + +/***************************************************************************** + * MacroblockAddressIncrement : Get the macroblock_address_increment field + *****************************************************************************/ +static inline int MacroblockAddressIncrement( vpar_thread_t * p_vpar ) +{ + lookup_t * p_tab; + int i_code; + int i_mba = 0; + + for( ; ; ) + { + if( (i_code = ShowBits( &p_vpar->bit_stream, 5 ) ) >= 0x2 ) + { + p_tab = MBA_5 - 2 + i_code; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + return( i_mba + p_tab->i_value ); + } + else if( (i_code = ShowBits( &p_vpar->bit_stream, 11 )) >= 0x18 ) + { + p_tab = MBA_11 - 24 + i_code; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + return( i_mba + p_tab->i_value ); + } + else switch( i_code ) + { + case 8: + /* Macroblock escape */ + i_mba += 33; + /* continue... */ + case 15: + /* Macroblock stuffing (MPEG-1 ONLY) */ + RemoveBits( &p_vpar->bit_stream, 11 ); + break; + + default: + /* End of slice, or error */ + return 0; + } + } +} + +/***************************************************************************** + * CodedPattern : coded_block_pattern + *****************************************************************************/ +static inline int CodedPattern( vpar_thread_t * p_vpar ) +{ + lookup_t * p_tab; + int i_code; + + if( (i_code = ShowBits( &p_vpar->bit_stream, 7 )) >= 0x10 ) + { + p_tab = CBP_7 - 16 + i_code; + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + } + else + { + p_tab = CBP_9 + ShowBits( &p_vpar->bit_stream, 9 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + } + if( p_vpar->sequence.i_chroma_format == CHROMA_420 ) + { + return( p_tab->i_value << 6 ); + } + if( p_vpar->sequence.i_chroma_format == CHROMA_422 ) + { + return( (p_tab->i_value << 6) + | (GetBits( &p_vpar->bit_stream, 2 ) << 4) ); + } + return( (p_tab->i_value << 6) + | GetBits( &p_vpar->bit_stream, 6 ) ); +} + +/***************************************************************************** + * MacroblockModes : Get the macroblock_modes structure + *****************************************************************************/ +static inline int MacroblockModes( vpar_thread_t * p_vpar, macroblock_t * p_mb, + int i_coding_type, int i_structure ) +{ + int i_mb_modes; + lookup_t * p_tab; + + switch( i_coding_type ) + { + case I_CODING_TYPE: + p_tab = MB_I + ShowBits( &p_vpar->bit_stream, 1 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_mb_modes = p_tab->i_value; + + if( (i_structure == FRAME_STRUCTURE) && + (!p_vpar->picture.b_frame_pred_frame_dct) ) + { + i_mb_modes |= GetBits( &p_vpar->bit_stream, 1 ) + * DCT_TYPE_INTERLACED; + } + return( i_mb_modes ); + + case P_CODING_TYPE: + p_tab = MB_P + ShowBits( &p_vpar->bit_stream, 5 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_mb_modes = p_tab->i_value; + + if( i_structure != FRAME_STRUCTURE ) + { + if( i_mb_modes & MB_MOTION_FORWARD ) + { + i_mb_modes |= GetBits( &p_vpar->bit_stream, 2 ) + * MOTION_TYPE_BASE; + } + return( i_mb_modes ); + } + else if( p_vpar->picture.b_frame_pred_frame_dct ) + { + if( i_mb_modes & MB_MOTION_FORWARD ) + { + i_mb_modes |= MC_FRAME; + } + return( i_mb_modes ); + } + else + { + if( i_mb_modes & MB_MOTION_FORWARD ) + { + i_mb_modes |= GetBits( &p_vpar->bit_stream, 2 ) + * MOTION_TYPE_BASE; + } + if( i_mb_modes & (MB_INTRA | MB_PATTERN) ) + { + i_mb_modes |= GetBits( &p_vpar->bit_stream, 1 ) + * DCT_TYPE_INTERLACED; + } + return( i_mb_modes ); + } + + case B_CODING_TYPE: + p_tab = MB_B + ShowBits( &p_vpar->bit_stream, 6 ); + RemoveBits( &p_vpar->bit_stream, p_tab->i_length ); + i_mb_modes = p_tab->i_value; + + if( i_structure != FRAME_STRUCTURE ) + { + if( !( i_mb_modes & MB_INTRA ) ) + { + i_mb_modes |= GetBits( &p_vpar->bit_stream, 2 ) + * MOTION_TYPE_BASE; + } + return( i_mb_modes ); + } + else if( p_vpar->picture.b_frame_pred_frame_dct ) + { + i_mb_modes |= MC_FRAME; + return( i_mb_modes ); + } + else + { + if( i_mb_modes & MB_INTRA ) + { + goto mb_intra; + } + i_mb_modes |= GetBits( &p_vpar->bit_stream, 2 ) + * MOTION_TYPE_BASE; + if( i_mb_modes & (MB_INTRA | MB_PATTERN) ) + { +mb_intra: + i_mb_modes |= GetBits( &p_vpar->bit_stream, 1 ) + * DCT_TYPE_INTERLACED; + } + return( i_mb_modes ); + } + + case D_CODING_TYPE: + RemoveBits( &p_vpar->bit_stream, 1 ); + return( MB_INTRA ); + + default: + return( 0 ); + } +} + + +/* + * Picture data parsing management + */ + +/***************************************************************************** + * ParseSlice : Parse the next slice structure + *****************************************************************************/ +#define MOTION( pf_routine, i_direction ) \ + if( (i_direction) & MB_MOTION_FORWARD ) \ + { \ + pf_routine( p_vpar, p_mb, &p_vpar->mb.f_motion, 0 ); \ + if( (i_coding_type == B_CODING_TYPE) \ + && ((i_direction) & MB_MOTION_BACKWARD) ) \ + { \ + pf_routine( p_vpar, p_mb, &p_vpar->mb.b_motion, 1 ); \ + } \ + } \ + else if( (i_coding_type == B_CODING_TYPE) \ + && ((i_direction) & MB_MOTION_BACKWARD) ) \ + { \ + pf_routine( p_vpar, p_mb, &p_vpar->mb.b_motion, 0 ); \ + } + +#define CHECK_BOUNDARIES \ + i_offset = p_vpar->mb.i_offset; \ + if( i_offset == p_vpar->picture.i_field_width ) \ + { \ + if( i_coding_type != I_CODING_TYPE || \ + p_vpar->picture.b_concealment_mv ) \ + { \ + p_f_motion->pppi_ref[0][0] += i_lum_vsize; \ + p_f_motion->pppi_ref[0][1] += i_chrom_vsize; \ + p_f_motion->pppi_ref[0][2] += i_chrom_vsize; \ + } \ + if( i_coding_type == B_CODING_TYPE ) \ + { \ + p_b_motion->pppi_ref[0][0] += i_lum_vsize; \ + p_b_motion->pppi_ref[0][1] += i_chrom_vsize; \ + p_b_motion->pppi_ref[0][2] += i_chrom_vsize; \ + } \ + p_dest[0] += i_lum_vsize; \ + p_dest[1] += i_chrom_vsize; \ + p_dest[2] += i_chrom_vsize; \ + i_offset = 0; \ + } \ + p_vpar->mb.i_offset = i_offset; + +#define PARSEERROR \ + if( p_vpar->picture.b_error ) \ + { \ + /* Go to the next slice. */ \ + p_vpar->pool.pf_free_mb( &p_vpar->pool, p_mb ); \ + return; \ + } + +static inline void ParseSlice( vpar_thread_t * p_vpar, + u32 i_vert_code, vlc_bool_t b_mpeg2, + int i_coding_type, int i_structure ) +{ + int i_lum_offset, i_chrom_offset, i_offset, i_lum_vsize, i_chrom_vsize; + picture_t * pp_forward_ref[2]; + yuv_data_t * p_dest[3]; + + motion_t * p_f_motion = &p_vpar->mb.f_motion; + motion_t * p_b_motion = &p_vpar->mb.b_motion; + + /* Parse header. */ + LoadQuantizerScale( p_vpar ); + + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* intra_slice, slice_id */ + RemoveBits( &p_vpar->bit_stream, 8 ); + /* extra_information_slice */ + while( GetBits( &p_vpar->bit_stream, 1 ) ) + { + RemoveBits( &p_vpar->bit_stream, 8 ); + } + } + + /* Calculate the position of the macroblock. */ + i_lum_offset = (i_vert_code - 1) * p_vpar->picture.p_picture->Y_PITCH * 16; + i_chrom_offset = (i_vert_code - 1) * p_vpar->picture.p_picture->U_PITCH + * 8 * (2 - p_vpar->sequence.b_chroma_v_subsampled); + i_lum_vsize = 16 * p_vpar->picture.p_picture->Y_PITCH; + i_chrom_vsize = 8 * (2 - p_vpar->sequence.b_chroma_v_subsampled) + * p_vpar->picture.p_picture->U_PITCH; + + /* Initialize motion context. */ + pp_forward_ref[0] = p_vpar->sequence.p_forward; + + if( i_structure != FRAME_STRUCTURE ) + { + i_lum_offset <<= 1; + i_chrom_offset <<= 1; + i_lum_vsize <<= 1; + i_chrom_vsize <<= 1; + + pp_forward_ref[1] = p_vpar->sequence.p_forward; + + if( i_coding_type != B_CODING_TYPE && p_vpar->picture.b_second_field ) + { + pp_forward_ref[!p_vpar->picture.b_current_field] = + p_vpar->picture.p_picture; + } + if( i_coding_type != I_CODING_TYPE || p_vpar->picture.b_concealment_mv ) + { + int i_tmp; + p_f_motion->pppi_ref[1][0] = pp_forward_ref[1]->Y_PIXELS + + i_lum_offset + pp_forward_ref[1]->Y_PITCH; + p_f_motion->pppi_ref[1][1] = pp_forward_ref[1]->U_PIXELS + + (i_tmp = i_chrom_offset + pp_forward_ref[1]->U_PITCH); + p_f_motion->pppi_ref[1][2] = pp_forward_ref[1]->V_PIXELS + + i_tmp; + } + if( i_coding_type == B_CODING_TYPE ) + { + int i_tmp; + p_b_motion->pppi_ref[1][0] = p_vpar->sequence.p_backward->Y_PIXELS + + i_lum_offset + p_vpar->sequence.p_backward->Y_PITCH; + p_b_motion->pppi_ref[1][1] = p_vpar->sequence.p_backward->U_PIXELS + + (i_tmp = i_chrom_offset + p_vpar->sequence.p_backward->U_PITCH); + p_b_motion->pppi_ref[1][2] = p_vpar->sequence.p_backward->V_PIXELS + + i_tmp; + } + } + + if( i_coding_type != I_CODING_TYPE || p_vpar->picture.b_concealment_mv ) + { + p_f_motion->pppi_ref[0][0] = pp_forward_ref[0]->Y_PIXELS + + i_lum_offset; + p_f_motion->pppi_ref[0][1] = pp_forward_ref[0]->U_PIXELS + + i_chrom_offset; + p_f_motion->pppi_ref[0][2] = pp_forward_ref[0]->V_PIXELS + + i_chrom_offset; + p_f_motion->pi_f_code[0] = p_vpar->picture.ppi_f_code[0][0]; + p_f_motion->pi_f_code[1] = p_vpar->picture.ppi_f_code[0][1]; + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + } + + if( i_coding_type == B_CODING_TYPE ) + { + p_b_motion->pppi_ref[0][0] = p_vpar->sequence.p_backward->Y_PIXELS + + i_lum_offset; + p_b_motion->pppi_ref[0][1] = p_vpar->sequence.p_backward->U_PIXELS + + i_chrom_offset; + p_b_motion->pppi_ref[0][2] = p_vpar->sequence.p_backward->V_PIXELS + + i_chrom_offset; + p_b_motion->pi_f_code[0] = p_vpar->picture.ppi_f_code[1][0]; + p_b_motion->pi_f_code[1] = p_vpar->picture.ppi_f_code[1][1]; + p_b_motion->ppi_pmv[0][0] = p_b_motion->ppi_pmv[0][1] = 0; + p_b_motion->ppi_pmv[1][0] = p_b_motion->ppi_pmv[1][1] = 0; + } + + /* Initialize destination pointers. */ + p_dest[0] = p_vpar->picture.p_picture->Y_PIXELS + + i_lum_offset; + p_dest[1] = p_vpar->picture.p_picture->U_PIXELS + + i_chrom_offset; + p_dest[2] = p_vpar->picture.p_picture->V_PIXELS + + i_chrom_offset; + + if( i_structure == BOTTOM_FIELD ) + { + p_dest[0] += p_vpar->picture.p_picture->Y_PITCH; + p_dest[1] += p_vpar->picture.p_picture->U_PITCH; + p_dest[2] += p_vpar->picture.p_picture->U_PITCH; + } + + /* Reset intra DC coefficients predictors (ISO/IEC 13818-2 7.2.1). */ + p_vpar->mb.pi_dc_dct_pred[0] = p_vpar->mb.pi_dc_dct_pred[1] + = p_vpar->mb.pi_dc_dct_pred[2] + = 1 << (7 + p_vpar->picture.i_intra_dc_precision); + + p_vpar->mb.i_offset = MacroblockAddressIncrement( p_vpar ) << 4; + + while( (int)(p_vpar->mb.i_offset - p_vpar->sequence.i_width) >= 0 ) + { + /* Unusual construct at the start of some slices. Jump one line. */ + p_vpar->mb.i_offset -= p_vpar->sequence.i_width; + + p_dest[0] += i_lum_vsize; + p_dest[1] += i_chrom_vsize; + p_dest[2] += i_chrom_vsize; + + p_f_motion->pppi_ref[0][0] += i_lum_vsize; + p_f_motion->pppi_ref[0][1] += i_chrom_vsize; + p_f_motion->pppi_ref[0][2] += i_chrom_vsize; + + p_f_motion->pppi_ref[1][0] += i_lum_vsize; + p_f_motion->pppi_ref[1][1] += i_chrom_vsize; + p_f_motion->pppi_ref[1][2] += i_chrom_vsize; + } + + for( ; ; ) + { + /* Decode macroblocks. */ + macroblock_t * p_mb; + int i_mb_modes; + + /* Get a macroblock structure. */ + p_mb = p_vpar->pool.pf_new_mb( &p_vpar->pool ); + p_mb->i_nb_motions = 0; + p_mb->pp_dest[0] = p_dest[0]; + p_mb->pp_dest[1] = p_dest[1]; + p_mb->pp_dest[2] = p_dest[2]; + + /* Parse off macroblock_modes structure. */ + p_mb->i_mb_modes = i_mb_modes = + MacroblockModes( p_vpar, p_mb, i_coding_type, i_structure ); + + if( i_mb_modes & MB_QUANT ) + { + LoadQuantizerScale( p_vpar ); + } + + if( i_mb_modes & MB_INTRA ) + { + if( p_vpar->picture.b_concealment_mv ) + { + if( i_structure == FRAME_STRUCTURE ) + { + MotionFrameConceal( p_vpar, p_mb, p_f_motion ); + } + else + { + MotionFieldConceal( p_vpar, p_mb, p_f_motion ); + } + } + else + { + /* Reset motion vectors predictors. */ + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + p_b_motion->ppi_pmv[0][0] = p_b_motion->ppi_pmv[0][1] = 0; + p_b_motion->ppi_pmv[1][0] = p_b_motion->ppi_pmv[1][1] = 0; + } + + /* Decode blocks */ + if( b_mpeg2 ) + { + if( p_vpar->picture.b_intra_vlc_format ) + { + MPEG2IntraB15MB( p_vpar, p_mb ); + } + else + { + MPEG2IntraB14MB( p_vpar, p_mb ); + } + } + else + { + MPEG1IntraMB( p_vpar, p_mb ); + } + + if( i_coding_type == D_CODING_TYPE ) + { + RemoveBits( &p_vpar->bit_stream, 1 ); + } + } + else + { + /* Non-intra block */ + if( !b_mpeg2 ) + { + if( (i_mb_modes & MOTION_TYPE_MASK) == MC_FRAME ) + { + MOTION( MotionMPEG1, i_mb_modes ); + } + else + { + /* Non-intra MB without forward mv in a P picture. */ + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + MOTION( MotionFrameZero, MB_MOTION_FORWARD ); + } + } + else if( i_structure == FRAME_STRUCTURE ) + { + switch( i_mb_modes & MOTION_TYPE_MASK ) + { + case MC_FRAME: + MOTION( MotionFrameFrame, i_mb_modes ); + break; + + case MC_FIELD: + MOTION( MotionFrameField, i_mb_modes ); + break; + + case MC_DMV: + MOTION( MotionFrameDMV, MB_MOTION_FORWARD ); + break; + + case 0: + /* Non-intra MB without forward mv in a P picture. */ + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + MOTION( MotionFrameZero, MB_MOTION_FORWARD ); + } + } + else + { + /* Field structure. */ + switch( i_mb_modes & MOTION_TYPE_MASK ) + { + case MC_FIELD: + MOTION( MotionFieldField, i_mb_modes ); + break; + + case MC_16X8: + MOTION( MotionField16x8, i_mb_modes ); + break; + + case MC_DMV: + MOTION( MotionFieldDMV, i_mb_modes ); + break; + + case 0: + /* Non-intra MB without forward mv in a P picture. */ + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + MOTION( MotionFieldZero, MB_MOTION_FORWARD ); + } + } + + /* ISO/IEC 13818-2 6.3.17.4 : Coded Block Pattern */ + if( i_mb_modes & MB_PATTERN ) + { + p_mb->i_coded_block_pattern = CodedPattern( p_vpar ); + if( b_mpeg2 ) + { + MPEG2NonIntraMB( p_vpar, p_mb ); + } + else + { + MPEG1NonIntraMB( p_vpar, p_mb ); + } + } + else + { + p_mb->i_coded_block_pattern = 0; + } + + /* Reset intra DC coefficients predictors. */ + p_vpar->mb.pi_dc_dct_pred[0] = p_vpar->mb.pi_dc_dct_pred[1] + = p_vpar->mb.pi_dc_dct_pred[2] + = 1 << (7 + p_vpar->picture.i_intra_dc_precision); + } + + /* End of macroblock. */ + PARSEERROR; + p_vpar->pool.pf_decode_mb( &p_vpar->pool, p_mb ); + + /* Prepare context for the next macroblock. */ + p_vpar->mb.i_offset += 16; + CHECK_BOUNDARIES; + + if( ShowBits( &p_vpar->bit_stream, 1 ) ) + { + /* Macroblock Address Increment == 1 */ + RemoveBits( &p_vpar->bit_stream, 1 ); + } + else + { + /* Check for skipped macroblock(s). */ + int i_mba_inc; + + i_mba_inc = MacroblockAddressIncrement( p_vpar ); + if( !i_mba_inc ) + { + /* End of slice. */ + break; + } + + /* Reset intra DC predictors. */ + p_vpar->mb.pi_dc_dct_pred[0] = p_vpar->mb.pi_dc_dct_pred[1] + = p_vpar->mb.pi_dc_dct_pred[2] + = 1 << (7 + p_vpar->picture.i_intra_dc_precision); + + if( i_coding_type == P_CODING_TYPE ) + { + p_f_motion->ppi_pmv[0][0] = p_f_motion->ppi_pmv[0][1] = 0; + p_f_motion->ppi_pmv[1][0] = p_f_motion->ppi_pmv[1][1] = 0; + + do { + p_mb = p_vpar->pool.pf_new_mb( &p_vpar->pool ); + p_mb->i_mb_modes = 0; + p_mb->i_nb_motions = 0; + p_mb->i_coded_block_pattern = 0; + p_mb->pp_dest[0] = p_dest[0]; + p_mb->pp_dest[1] = p_dest[1]; + p_mb->pp_dest[2] = p_dest[2]; + + if( i_structure == FRAME_STRUCTURE ) + { + MOTION( MotionFrameZero, MB_MOTION_FORWARD ); + } + else + { + MOTION( MotionFieldZero, MB_MOTION_FORWARD ); + } + + p_vpar->pool.pf_decode_mb( &p_vpar->pool, p_mb ); + p_vpar->mb.i_offset += 16; + CHECK_BOUNDARIES; + } while( --i_mba_inc ); + } + else + { + do { + p_mb = p_vpar->pool.pf_new_mb( &p_vpar->pool ); + p_mb->i_mb_modes = 0; + p_mb->i_nb_motions = 0; + p_mb->i_coded_block_pattern = 0; + p_mb->pp_dest[0] = p_dest[0]; + p_mb->pp_dest[1] = p_dest[1]; + p_mb->pp_dest[2] = p_dest[2]; + + if( !b_mpeg2 ) + { + MOTION( MotionMPEG1Reuse, i_mb_modes ); + } + else if( i_structure == FRAME_STRUCTURE ) + { + MOTION( MotionFrameReuse, i_mb_modes ); + } + else + { + MOTION( MotionFieldReuse, i_mb_modes ); + } + + p_vpar->pool.pf_decode_mb( &p_vpar->pool, p_mb ); + p_vpar->mb.i_offset += 16; + CHECK_BOUNDARIES; + } while( --i_mba_inc ); + } + } + } + + NextStartCode( &p_vpar->bit_stream ); +} + +/***************************************************************************** + * PictureData : Parse off all macroblocks (ISO/IEC 13818-2 6.2.3.7) + *****************************************************************************/ +static inline void vpar_PictureData( vpar_thread_t * p_vpar, vlc_bool_t b_mpeg2, + int i_coding_type, int i_structure ) +{ + u32 i_dummy; + + NextStartCode( &p_vpar->bit_stream ); + while( !p_vpar->picture.b_error && !p_vpar->p_fifo->b_die ) + { + if( ((i_dummy = ShowBits( &p_vpar->bit_stream, 32 )) + < SLICE_START_CODE_MIN) || + (i_dummy > SLICE_START_CODE_MAX) ) + { + break; + } + RemoveBits32( &p_vpar->bit_stream ); + + /* Decode slice data. */ + ParseSlice( p_vpar, i_dummy & 255, b_mpeg2, i_coding_type, + i_structure ); + } +} + +#define DECLARE_PICD( FUNCNAME, B_MPEG2, I_CODING_TYPE, I_STRUCTURE ) \ +void FUNCNAME( vpar_thread_t * p_vpar ) \ +{ \ + vpar_PictureData( p_vpar, B_MPEG2, I_CODING_TYPE, I_STRUCTURE ); \ +} + +DECLARE_PICD( vpar_PictureDataGENERIC, p_vpar->sequence.b_mpeg2, + p_vpar->picture.i_coding_type, p_vpar->picture.i_structure ); +#if (VPAR_OPTIM_LEVEL > 0) +DECLARE_PICD( vpar_PictureData2IF, 1, I_CODING_TYPE, FRAME_STRUCTURE ); +DECLARE_PICD( vpar_PictureData2PF, 1, P_CODING_TYPE, FRAME_STRUCTURE ); +DECLARE_PICD( vpar_PictureData2BF, 1, B_CODING_TYPE, FRAME_STRUCTURE ); +#endif +#if (VPAR_OPTIM_LEVEL > 1) +DECLARE_PICD( vpar_PictureData2IT, 1, I_CODING_TYPE, TOP_FIELD ); +DECLARE_PICD( vpar_PictureData2PT, 1, P_CODING_TYPE, TOP_FIELD ); +DECLARE_PICD( vpar_PictureData2BT, 1, B_CODING_TYPE, TOP_FIELD ); +DECLARE_PICD( vpar_PictureData2IB, 1, I_CODING_TYPE, BOTTOM_FIELD ); +DECLARE_PICD( vpar_PictureData2PB, 1, P_CODING_TYPE, BOTTOM_FIELD ); +DECLARE_PICD( vpar_PictureData2BB, 1, B_CODING_TYPE, BOTTOM_FIELD ); +DECLARE_PICD( vpar_PictureData1I, 0, I_CODING_TYPE, FRAME_STRUCTURE ); +DECLARE_PICD( vpar_PictureData1P, 0, P_CODING_TYPE, FRAME_STRUCTURE ); +DECLARE_PICD( vpar_PictureData1B, 0, B_CODING_TYPE, FRAME_STRUCTURE ); +DECLARE_PICD( vpar_PictureData1D, 0, D_CODING_TYPE, FRAME_STRUCTURE ); +#endif + +#undef DECLARE_PICD + diff --git a/modules/codec/mpeg_video/blocks.h b/modules/codec/mpeg_video/blocks.h new file mode 100644 index 0000000000..2aad2fd38a --- /dev/null +++ b/modules/codec/mpeg_video/blocks.h @@ -0,0 +1,432 @@ +/***************************************************************************** + * video_parser.h : Variable Length Codes + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: blocks.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Jean-Marc Dressler + * Stéphane Borel + * Aaron Holtzman + * Michel Lespinasse + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * lookup_t : entry type for lookup tables * + *****************************************************************************/ +typedef struct lookup_s +{ + u8 i_value; + u8 i_length; +} lookup_t; + +typedef struct dmv_lookup_s +{ + s8 i_value; + u8 i_length; +} dmv_lookup_t; + +/***************************************************************************** + * dct_lookup_t : special entry type for lookup tables about ac coefficients + *****************************************************************************/ +typedef struct dct_lookup_s +{ + u8 i_run; + u8 i_level; + u8 i_length; +} dct_lookup_t; + +/***************************************************************************** + * Standard codes + *****************************************************************************/ + +/* Motion types */ +#define MOTION_TYPE_MASK (3*64) +#define MOTION_TYPE_BASE 64 +#define MC_FIELD (1*64) +#define MC_FRAME (2*64) +#define MC_16X8 (2*64) +#define MC_DMV (3*64) + +/* Macroblock Address Increment types */ +#define MB_ADDRINC_ESCAPE 8 +#define MB_ADDRINC_STUFFING 15 + +/* Error constant for lookup tables */ +#define MB_ERROR (-1) + +/* Scan */ +#define SCAN_ZIGZAG 0 +#define SCAN_ALT 1 + +/* Constant for block decoding */ +#define DCT_EOB 64 +#define DCT_ESCAPE 65 + + +/***************************************************************************** + * Lookup tables for macroblock modes + *****************************************************************************/ + +#define INTRA MB_INTRA +#define QUANT MB_QUANT + +static lookup_t MB_I [] = { + {INTRA|QUANT, 2}, {INTRA, 1} +}; + +#define MC MB_MOTION_FORWARD +#define CODED MB_PATTERN + +static lookup_t MB_P [] = { + {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5}, + {MC, 3}, {MC, 3}, {MC, 3}, {MC, 3}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, + {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1} +}; + +#define FWD MB_MOTION_FORWARD +#define BWD MB_MOTION_BACKWARD +#define INTER MB_MOTION_FORWARD|MB_MOTION_BACKWARD + +static lookup_t MB_B [] = { + {0, 0}, {INTRA|QUANT, 6}, + {BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6}, + {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5}, + {INTRA, 5}, {INTRA, 5}, + {FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4}, + {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, + {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2} +}; + +#undef INTRA +#undef QUANT +#undef MC +#undef CODED +#undef FWD +#undef BWD +#undef INTER + + +/***************************************************************************** + * Lookup tables for motion vectors + *****************************************************************************/ + +static lookup_t MV_4 [] = { + { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2} +}; + +static lookup_t MV_10 [] = { + { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, + { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10}, + {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9}, + { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, + { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, + { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7} +}; + + +static dmv_lookup_t DMV_2 [] = { + { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2} +}; + + +/***************************************************************************** + * Lookup tables for Coded Block Patterns + *****************************************************************************/ + +static lookup_t CBP_7 [] = { + {0x22, 7}, {0x12, 7}, {0x0a, 7}, {0x06, 7}, + {0x21, 7}, {0x11, 7}, {0x09, 7}, {0x05, 7}, + {0x3f, 6}, {0x3f, 6}, {0x03, 6}, {0x03, 6}, + {0x24, 6}, {0x24, 6}, {0x18, 6}, {0x18, 6}, + {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, {0x3e, 5}, + {0x02, 5}, {0x02, 5}, {0x02, 5}, {0x02, 5}, + {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, {0x3d, 5}, + {0x01, 5}, {0x01, 5}, {0x01, 5}, {0x01, 5}, + {0x38, 5}, {0x38, 5}, {0x38, 5}, {0x38, 5}, + {0x34, 5}, {0x34, 5}, {0x34, 5}, {0x34, 5}, + {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, {0x2c, 5}, + {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, {0x1c, 5}, + {0x28, 5}, {0x28, 5}, {0x28, 5}, {0x28, 5}, + {0x14, 5}, {0x14, 5}, {0x14, 5}, {0x14, 5}, + {0x30, 5}, {0x30, 5}, {0x30, 5}, {0x30, 5}, + {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x20, 4}, {0x20, 4}, {0x20, 4}, {0x20, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x10, 4}, {0x10, 4}, {0x10, 4}, {0x10, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, + {0x3c, 3}, {0x3c, 3}, {0x3c, 3}, {0x3c, 3} +}; + +static lookup_t CBP_9 [] = { + {0, 0}, {0x00, 9}, {0x27, 9}, {0x1b, 9}, + {0x3b, 9}, {0x37, 9}, {0x2f, 9}, {0x1f, 9}, + {0x3a, 8}, {0x3a, 8}, {0x36, 8}, {0x36, 8}, + {0x2e, 8}, {0x2e, 8}, {0x1e, 8}, {0x1e, 8}, + {0x39, 8}, {0x39, 8}, {0x35, 8}, {0x35, 8}, + {0x2d, 8}, {0x2d, 8}, {0x1d, 8}, {0x1d, 8}, + {0x26, 8}, {0x26, 8}, {0x1a, 8}, {0x1a, 8}, + {0x25, 8}, {0x25, 8}, {0x19, 8}, {0x19, 8}, + {0x2b, 8}, {0x2b, 8}, {0x17, 8}, {0x17, 8}, + {0x33, 8}, {0x33, 8}, {0x0f, 8}, {0x0f, 8}, + {0x2a, 8}, {0x2a, 8}, {0x16, 8}, {0x16, 8}, + {0x32, 8}, {0x32, 8}, {0x0e, 8}, {0x0e, 8}, + {0x29, 8}, {0x29, 8}, {0x15, 8}, {0x15, 8}, + {0x31, 8}, {0x31, 8}, {0x0d, 8}, {0x0d, 8}, + {0x23, 8}, {0x23, 8}, {0x13, 8}, {0x13, 8}, + {0x0b, 8}, {0x0b, 8}, {0x07, 8}, {0x07, 8} +}; + + +/***************************************************************************** + * Lookup tables for coefficients + *****************************************************************************/ + +static lookup_t DC_lum_5 [] = { + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, + {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5} +}; + +static lookup_t DC_chrom_5 [] = { + {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, + {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, + {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, + {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5} +}; + +static lookup_t DC_long [] = { + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5}, + {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6}, + {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9} +}; + + +static dct_lookup_t DCT_16 [] = { + {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, + {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, + {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, + {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, {129, 0, 16}, + { 2,18, 16}, { 2,17, 16}, { 2,16, 16}, { 2,15, 16}, + { 7, 3, 16}, { 17, 2, 16}, { 16, 2, 16}, { 15, 2, 16}, + { 14, 2, 16}, { 13, 2, 16}, { 12, 2, 16}, { 32, 1, 16}, + { 31, 1, 16}, { 30, 1, 16}, { 29, 1, 16}, { 28, 1, 16} +}; + +static dct_lookup_t DCT_15 [] = { + { 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15}, + { 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15}, + { 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15}, + { 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15}, + { 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14}, + { 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14}, + { 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14}, + { 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14}, + { 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14}, + { 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14}, + { 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14}, + { 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14} +}; + +static dct_lookup_t DCT_13 [] = { + { 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13}, + { 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13}, + { 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13}, + { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13}, + { 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12}, + { 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12}, + { 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12}, + { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12}, + { 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12}, + { 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12}, + { 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12}, + { 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12} +}; + +static dct_lookup_t DCT_B14_10 [] = { + { 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10}, + { 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10} +}; + +static dct_lookup_t DCT_B14_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7}, + { 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, + { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, + { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8}, + { 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8} +}; + +static dct_lookup_t DCT_B14AC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2} +}; + +static dct_lookup_t DCT_B14DC_5 [] = { + { 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5}, + { 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 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, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, + { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1} +}; + +static dct_lookup_t DCT_B15_10 [] = { + { 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9}, + { 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9} +}; + +static dct_lookup_t DCT_B15_8 [] = { + { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, + { 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7}, + { 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7}, + { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, + { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, + { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, + { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, + { 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8}, + { 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, + { 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7}, + { 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7}, + { 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8}, + { 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8} +}; + + +/***************************************************************************** + * Lookup tables for Macroblock Address Increment + *****************************************************************************/ + +static lookup_t MBA_5 [] = { + {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4}, + {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1} +}; + +static lookup_t MBA_11 [] = { + {32, 11}, {31, 11}, {30, 11}, {29, 11}, + {28, 11}, {27, 11}, {26, 11}, {25, 11}, + {24, 11}, {23, 11}, {22, 11}, {21, 11}, + {20, 10}, {20, 10}, {19, 10}, {19, 10}, + {18, 10}, {18, 10}, {17, 10}, {17, 10}, + {16, 10}, {16, 10}, {15, 10}, {15, 10}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {14, 8}, {14, 8}, {14, 8}, {14, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {13, 8}, {13, 8}, {13, 8}, {13, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {12, 8}, {12, 8}, {12, 8}, {12, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {11, 8}, {11, 8}, {11, 8}, {11, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + {10, 8}, {10, 8}, {10, 8}, {10, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 9, 8}, { 9, 8}, { 9, 8}, { 9, 8}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 8, 7}, { 8, 7}, { 8, 7}, { 8, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}, + { 7, 7}, { 7, 7}, { 7, 7}, { 7, 7} +}; diff --git a/modules/codec/mpeg_video/decoder.c b/modules/codec/mpeg_video/decoder.c new file mode 100644 index 0000000000..347059638e --- /dev/null +++ b/modules/codec/mpeg_video/decoder.c @@ -0,0 +1,363 @@ +/***************************************************************************** + * video_decoder.c : video decoder thread + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: decoder.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Michel Lespinasse + * + * 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 /* free() */ +#include /* memcpy(), memset() */ +#include /* errno */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include /* getpid() */ +#endif + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" + +/* + * Local prototypes + */ +static void RunThread ( vdec_thread_t *p_vdec ); + +/***************************************************************************** + * vdec_CreateThread: create a video decoder thread + ***************************************************************************** + * This function creates a new video decoder thread, and returns a pointer + * to its description. On error, it returns NULL. + *****************************************************************************/ +vdec_thread_t * vdec_CreateThread( vdec_pool_t * p_pool ) +{ + vdec_thread_t * p_vdec; + + /* Allocate the memory needed to store the thread's structure */ + p_vdec = vlc_object_create( p_pool->p_vpar->p_fifo, sizeof(vdec_thread_t) ); + if( p_vdec == NULL ) + { + msg_Err( p_pool->p_vpar->p_fifo, "out of memory" ); + return NULL; + } + + /* + * Initialize the parser properties + */ + p_vdec->p_pool = p_pool; + + /* Spawn the video decoder thread */ + if( vlc_thread_create( p_vdec, "video decoder", RunThread, 0 ) ) + { + msg_Err( p_vdec, "cannot spawn video decoder thread" ); + vlc_object_destroy( p_vdec ); + return( NULL ); + } + + return p_vdec; +} + +/***************************************************************************** + * vdec_DestroyThread: destroy a video decoder thread + *****************************************************************************/ +void vdec_DestroyThread( vdec_thread_t *p_vdec ) +{ + /* Ask thread to kill itself */ + p_vdec->b_die = 1; + + /* Make sure the decoder thread leaves the vpar_GetMacroblock() function */ + vlc_mutex_lock( &p_vdec->p_pool->lock ); + vlc_cond_broadcast( &p_vdec->p_pool->wait_undecoded ); + vlc_mutex_unlock( &p_vdec->p_pool->lock ); + + /* Waiting for the decoder thread to exit */ + vlc_thread_join( p_vdec ); + + /* Free the object */ + vlc_object_destroy( p_vdec ); +} + +/* following functions are local */ + +/***************************************************************************** + * vdec_InitThread: initialize video decoder thread + ***************************************************************************** + * This function is called from RunThread and performs the second step of the + * initialization. + *****************************************************************************/ +void vdec_InitThread( vdec_thread_t * p_vdec ) +{ + /* Re-nice ourself - otherwise we would steal CPU time from the video + * output, which would make a poor display. */ +#if defined( HAVE_NICE ) + if( nice(VDEC_NICE) == -1 ) +#elif defined( WIN32 ) + if( !SetThreadPriority( GetCurrentThread(), + THREAD_PRIORITY_BELOW_NORMAL ) ) +#else + if( 0 ) +#endif + { + msg_Warn( p_vdec, "couldn't nice() (%s)", strerror(errno) ); + } + + p_vdec->p_idct_data = NULL; + + p_vdec->p_pool->pf_idct_init( &p_vdec->p_idct_data ); + + /* Mark thread as running and return */ +} + +/***************************************************************************** + * vdec_EndThread: thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +void vdec_EndThread( vdec_thread_t * p_vdec ) +{ + if( p_vdec->p_idct_data != NULL ) + { + free( p_vdec->p_idct_data ); + } +} + +/***************************************************************************** + * MotionBlock: does one component of the motion compensation + *****************************************************************************/ +static inline void MotionBlock( vdec_pool_t * p_pool, vlc_bool_t b_average, + int i_x_pred, int i_y_pred, + yuv_data_t * pp_dest[3], int i_dest_offset, + yuv_data_t * pp_src[3], int i_src_offset, + int i_stride, int i_height, + vlc_bool_t b_second_half, int i_chroma_format ) +{ + int i_xy_half; + yuv_data_t * p_src1; + yuv_data_t * p_src2; + + i_xy_half = ((i_y_pred & 1) << 1) | (i_x_pred & 1); + + p_src1 = pp_src[0] + i_src_offset + + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride + + b_second_half * (i_stride << 3); + + p_pool->ppppf_motion[b_average][0][i_xy_half] + ( pp_dest[0] + i_dest_offset + b_second_half * (i_stride << 3), + p_src1, i_stride, i_height ); + + if( i_chroma_format != CHROMA_NONE ) + { + /* Expanded at compile-time. */ + if( i_chroma_format != CHROMA_444 ) + { + i_x_pred /= 2; + i_stride >>= 1; + i_src_offset >>= 1; + i_dest_offset >>= 1; + } + if( i_chroma_format == CHROMA_420 ) + { + i_y_pred /= 2; + i_height >>= 1; + } + + i_xy_half = ((i_y_pred & 1) << 1) | (i_x_pred & 1); + + i_src_offset += b_second_half * (i_stride << 3); + i_dest_offset += b_second_half * (i_stride << 3); + + p_src1 = pp_src[1] + i_src_offset + + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride; + p_src2 = pp_src[2] + i_src_offset + + (i_x_pred >> 1) + (i_y_pred >> 1) * i_stride; + + p_pool->ppppf_motion[b_average][(i_chroma_format != CHROMA_444)] + [i_xy_half] + ( pp_dest[1] + i_dest_offset, p_src1, i_stride, i_height ); + p_pool->ppppf_motion[b_average][(i_chroma_format != CHROMA_444)] + [i_xy_half] + ( pp_dest[2] + i_dest_offset, p_src2, i_stride, i_height ); + } +} + + +/***************************************************************************** + * DecodeMacroblock: decode a macroblock + *****************************************************************************/ +#define DECODE_INTRA_BLOCK( i_b, p_dest ) \ + p_idct = &p_mb->p_idcts[i_b]; \ + p_idct->pf_idct( p_idct->pi_block, p_dest, \ + i_b < 4 ? i_lum_dct_stride : i_chrom_dct_stride, \ + p_vdec->p_idct_data, p_idct->i_sparse_pos ); + +#define DECODE_NONINTRA_BLOCK( i_b, p_dest ) \ + if( p_mb->i_coded_block_pattern & (1 << (11 - (i_b))) ) \ + { \ + DECODE_INTRA_BLOCK( i_b, p_dest ); \ + } + +#define DECLARE_DECODEMB( PSZ_NAME, I_CHROMA ) \ +void PSZ_NAME ( vdec_thread_t *p_vdec, macroblock_t * p_mb ) \ +{ \ + int i, i_lum_dct_offset, i_lum_dct_stride; \ + int i_chrom_dct_offset, i_chrom_dct_stride; \ + idct_inner_t * p_idct; \ + vdec_pool_t * p_pool = p_vdec->p_pool; \ + vpar_thread_t * p_vpar = p_pool->p_vpar; \ + \ + if( p_mb->i_mb_modes & DCT_TYPE_INTERLACED ) \ + { \ + i_lum_dct_offset = p_vpar->picture.i_lum_stride; \ + i_lum_dct_stride = p_vpar->picture.i_lum_stride * 2; \ + } \ + else \ + { \ + i_lum_dct_offset = p_vpar->picture.i_lum_stride * 8; \ + i_lum_dct_stride = p_vpar->picture.i_lum_stride; \ + } \ + \ + i_chrom_dct_offset = p_vpar->picture.i_chrom_stride * 8; \ + i_chrom_dct_stride = p_vpar->picture.i_chrom_stride; \ + \ + if( !(p_mb->i_mb_modes & MB_INTRA) ) \ + { \ + /* \ + * Motion Compensation (ISO/IEC 13818-2 section 7.6) \ + */ \ + for( i = 0; i < p_mb->i_nb_motions; i++ ) \ + { \ + motion_inner_t * p_motion = &p_mb->p_motions[i]; \ + MotionBlock( p_pool, p_motion->b_average, \ + p_motion->i_x_pred, p_motion->i_y_pred, \ + p_mb->pp_dest, p_motion->i_dest_offset, \ + p_motion->pp_source, p_motion->i_src_offset, \ + p_motion->i_stride, p_motion->i_height, \ + p_motion->b_second_half, I_CHROMA ); \ + } \ + \ + /* \ + * Inverse DCT (ISO/IEC 13818-2 section Annex A) and \ + * adding prediction and coefficient data (ISO/IEC \ + * 13818-2 section 7.6.8) \ + */ \ + DECODE_NONINTRA_BLOCK( 0, p_mb->p_y_data ); \ + DECODE_NONINTRA_BLOCK( 1, p_mb->p_y_data + 8 ); \ + DECODE_NONINTRA_BLOCK( 2, p_mb->p_y_data + i_lum_dct_offset ); \ + DECODE_NONINTRA_BLOCK( 3, p_mb->p_y_data + i_lum_dct_offset + 8 ); \ + if( I_CHROMA != CHROMA_NONE ) \ + { \ + DECODE_NONINTRA_BLOCK( 4, p_mb->p_u_data ); \ + DECODE_NONINTRA_BLOCK( 5, p_mb->p_v_data ); \ + if( I_CHROMA != CHROMA_420 ) \ + { \ + DECODE_NONINTRA_BLOCK( 6, p_mb->p_u_data \ + + i_chrom_dct_offset ); \ + DECODE_NONINTRA_BLOCK( 7, p_mb->p_v_data \ + + i_chrom_dct_offset ); \ + if( I_CHROMA == CHROMA_444 ) \ + { \ + DECODE_NONINTRA_BLOCK( 8, p_mb->p_u_data + 8 ); \ + DECODE_NONINTRA_BLOCK( 9, p_mb->p_v_data + 8 ); \ + DECODE_NONINTRA_BLOCK( 10, p_mb->p_u_data + 8 \ + + i_chrom_dct_offset ); \ + DECODE_NONINTRA_BLOCK( 11, p_mb->p_v_data + 8 \ + + i_chrom_dct_offset ); \ + } \ + } \ + } \ + } \ + else \ + { \ + /* Intra macroblock */ \ + DECODE_INTRA_BLOCK( 0, p_mb->p_y_data ); \ + DECODE_INTRA_BLOCK( 1, p_mb->p_y_data + 8 ); \ + DECODE_INTRA_BLOCK( 2, p_mb->p_y_data + i_lum_dct_offset ); \ + DECODE_INTRA_BLOCK( 3, p_mb->p_y_data + i_lum_dct_offset + 8 ); \ + if( I_CHROMA != CHROMA_NONE ) \ + { \ + DECODE_INTRA_BLOCK( 4, p_mb->p_u_data ); \ + DECODE_INTRA_BLOCK( 5, p_mb->p_v_data ); \ + if( I_CHROMA != CHROMA_420 ) \ + { \ + DECODE_INTRA_BLOCK( 6, p_mb->p_u_data \ + + i_chrom_dct_offset ); \ + DECODE_INTRA_BLOCK( 7, p_mb->p_v_data \ + + i_chrom_dct_offset ); \ + if( I_CHROMA == CHROMA_444 ) \ + { \ + DECODE_INTRA_BLOCK( 8, p_mb->p_u_data + 8 ); \ + DECODE_INTRA_BLOCK( 9, p_mb->p_v_data + 8 ); \ + DECODE_INTRA_BLOCK( 10, p_mb->p_u_data + 8 \ + + i_chrom_dct_offset ); \ + DECODE_INTRA_BLOCK( 11, p_mb->p_v_data + 8 \ + + i_chrom_dct_offset ); \ + } \ + } \ + } \ + } \ +} + +DECLARE_DECODEMB( vdec_DecodeMacroblockBW, CHROMA_NONE ); +DECLARE_DECODEMB( vdec_DecodeMacroblock420, CHROMA_420 ); +DECLARE_DECODEMB( vdec_DecodeMacroblock422, CHROMA_422 ); +DECLARE_DECODEMB( vdec_DecodeMacroblock444, CHROMA_444 ); + +#undef DECLARE_DECODEMB + +/***************************************************************************** + * RunThread: video decoder thread + ***************************************************************************** + * Video decoder thread. This function does only return when the thread is + * terminated. + *****************************************************************************/ +static void RunThread( vdec_thread_t *p_vdec ) +{ + vdec_InitThread( p_vdec ); + + /* + * Main loop + */ + while( !p_vdec->b_die ) + { + macroblock_t * p_mb; + + if( (p_mb = vpar_GetMacroblock( p_vdec->p_pool, &p_vdec->b_die )) != NULL ) + { + p_vdec->p_pool->pf_vdec_decode( p_vdec, p_mb ); + + /* Decoding is finished, release the macroblock and free + * unneeded memory. */ + p_vdec->p_pool->pf_free_mb( p_vdec->p_pool, p_mb ); + } + } + + /* End of thread */ + vdec_EndThread( p_vdec ); +} + diff --git a/modules/codec/mpeg_video/decoder.h b/modules/codec/mpeg_video/decoder.h new file mode 100644 index 0000000000..deceb752fc --- /dev/null +++ b/modules/codec/mpeg_video/decoder.h @@ -0,0 +1,50 @@ +/***************************************************************************** + * video_decoder.h : video decoder thread + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: decoder.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * vdec_thread_t: video decoder thread descriptor + *****************************************************************************/ +typedef struct vdec_thread_s +{ + VLC_COMMON_MEMBERS + + /* IDCT iformations */ + void * p_idct_data; + + /* Input properties */ + struct vdec_pool_s * p_pool; + +} vdec_thread_t; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +void vdec_InitThread ( vdec_thread_t * ); +void vdec_EndThread ( vdec_thread_t * ); +void vdec_DecodeMacroblockBW ( vdec_thread_t *, macroblock_t * ); +void vdec_DecodeMacroblock420( vdec_thread_t *, macroblock_t * ); +void vdec_DecodeMacroblock422( vdec_thread_t *, macroblock_t * ); +void vdec_DecodeMacroblock444( vdec_thread_t *, macroblock_t * ); +vdec_thread_t * vdec_CreateThread ( struct vdec_pool_s * ); +void vdec_DestroyThread ( vdec_thread_t * ); + diff --git a/modules/codec/mpeg_video/headers.c b/modules/codec/mpeg_video/headers.c new file mode 100644 index 0000000000..bebddda718 --- /dev/null +++ b/modules/codec/mpeg_video/headers.c @@ -0,0 +1,1204 @@ +/***************************************************************************** + * vpar_headers.c : headers parsing + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: headers.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Stéphane Borel + * + * 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 /* free() */ +#include /* memcpy(), memset() */ + +#include +#include +#include + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" + +/* + * Local prototypes + */ +static inline void NextStartCode( bit_stream_t * ); +static void SequenceHeader( vpar_thread_t * p_vpar ); +static void GroupHeader( vpar_thread_t * p_vpar ); +static void PictureHeader( vpar_thread_t * p_vpar ); +static void ExtensionAndUserData( vpar_thread_t * p_vpar ); +static void QuantMatrixExtension( vpar_thread_t * p_vpar ); +static void SequenceScalableExtension( vpar_thread_t * p_vpar ); +static void SequenceDisplayExtension( vpar_thread_t * p_vpar ); +static void PictureDisplayExtension( vpar_thread_t * p_vpar ); +static void PictureSpatialScalableExtension( vpar_thread_t * p_vpar ); +static void PictureTemporalScalableExtension( vpar_thread_t * p_vpar ); +static void CopyrightExtension( vpar_thread_t * p_vpar ); + +/* + * Standard variables + */ + +/***************************************************************************** + * pi_default_intra_quant : default quantization matrix + *****************************************************************************/ +u8 pi_default_intra_quant[] ATTR_ALIGN(16) = +{ + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; + +/***************************************************************************** + * pi_default_nonintra_quant : default quantization matrix + *****************************************************************************/ +u8 pi_default_nonintra_quant[] ATTR_ALIGN(16) = +{ + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 +}; + +/***************************************************************************** + * pi_scan : zig-zag and alternate scan patterns + *****************************************************************************/ +u8 pi_scan[2][64] ATTR_ALIGN(16) = +{ + { /* Zig-Zag pattern */ + 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5, + 12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28, + 35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 + }, + { /* Alternate scan pattern */ + 0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49, + 41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43, + 51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45, + 53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63 + } +}; + +/* + * Local inline functions. + */ + +/***************************************************************************** + * ReferenceUpdate : Update the reference pointers when we have a new picture + *****************************************************************************/ +static void inline ReferenceUpdate( vpar_thread_t * p_vpar, + int i_coding_type, picture_t * p_newref ) +{ + if( i_coding_type != B_CODING_TYPE ) + { + if( p_vpar->sequence.p_forward != NULL ) + { + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward ); + } + if( p_vpar->sequence.p_backward != NULL ) + { + vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward, + vpar_SynchroDate( p_vpar ) ); + } + p_vpar->sequence.p_forward = p_vpar->sequence.p_backward; + p_vpar->sequence.p_backward = p_newref; + if( p_newref != NULL ) + { + vout_LinkPicture( p_vpar->p_vout, p_newref ); + } + } + else if( p_newref != NULL ) + { + /* Put date immediately. */ + vout_DatePicture( p_vpar->p_vout, p_newref, vpar_SynchroDate(p_vpar) ); + } +} + +/***************************************************************************** + * ReferenceReplace : Replace the last reference pointer when we destroy + * a picture + *****************************************************************************/ +static void inline ReferenceReplace( vpar_thread_t * p_vpar, + int i_coding_type, picture_t * p_newref ) +{ + if( i_coding_type != B_CODING_TYPE ) + { + if( p_vpar->sequence.p_backward != NULL ) + { + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward ); + } + p_vpar->sequence.p_backward = p_newref; + if( p_newref != NULL ) + { + vout_LinkPicture( p_vpar->p_vout, p_newref ); + } + } +} + +/***************************************************************************** + * LoadMatrix : Load a quantization matrix + *****************************************************************************/ +static inline void LoadMatrix( vpar_thread_t * p_vpar, + quant_matrix_t * p_matrix ) +{ + int i_dummy; + + if( !p_matrix->b_allocated ) + { + /* Allocate a piece of memory to load the matrix. */ + if( (p_matrix->pi_matrix = (u8 *)malloc( 64*sizeof(u8) )) == NULL ) + { + msg_Err( p_vpar->p_fifo, "out of memory" ); + p_vpar->p_fifo->b_error = 1; + return; + } + p_matrix->b_allocated = 1; + } + + for( i_dummy = 0; i_dummy < 64; i_dummy++ ) + { + p_matrix->pi_matrix[p_vpar->ppi_scan[0][i_dummy]] + = GetBits( &p_vpar->bit_stream, 8 ); + } +} + +/***************************************************************************** + * LinkMatrix : Link a quantization matrix to another + *****************************************************************************/ +static inline void LinkMatrix( quant_matrix_t * p_matrix, u8 * pi_array ) +{ + if( p_matrix->b_allocated ) + { + /* Deallocate the piece of memory. */ + free( p_matrix->pi_matrix ); + p_matrix->b_allocated = 0; + } + + p_matrix->pi_matrix = pi_array; +} + +/***************************************************************************** + * ChromaToFourCC: Return a FourCC value used by the video output. + *****************************************************************************/ +static inline u64 ChromaToFourCC( int i_chroma ) +{ + switch( i_chroma ) + { + case CHROMA_420: + return VLC_FOURCC('I','4','2','0'); + + case CHROMA_422: + return VLC_FOURCC('I','4','2','2'); + + case CHROMA_444: + return VLC_FOURCC('I','4','4','4'); + + default: + /* This can't happen */ + return 0xdeadbeef; + } +} + +/* + * Exported functions. + */ + +/***************************************************************************** + * vpar_NextSequenceHeader : Find the next sequence header + *****************************************************************************/ +int vpar_NextSequenceHeader( vpar_thread_t * p_vpar ) +{ + while( !p_vpar->p_fifo->b_die ) + { + NextStartCode( &p_vpar->bit_stream ); + if( ShowBits( &p_vpar->bit_stream, 32 ) == SEQUENCE_HEADER_CODE ) + { + return 0; + } + RemoveBits( &p_vpar->bit_stream, 8 ); + } + return 1; +} + +/***************************************************************************** + * vpar_ParseHeader : Parse the next header + *****************************************************************************/ +int vpar_ParseHeader( vpar_thread_t * p_vpar ) +{ + NextStartCode( &p_vpar->bit_stream ); + switch( GetBits32( &p_vpar->bit_stream ) ) + { + case SEQUENCE_HEADER_CODE: + p_vpar->c_sequences++; + SequenceHeader( p_vpar ); + return 0; + + case GROUP_START_CODE: + GroupHeader( p_vpar ); + return 0; + + case PICTURE_START_CODE: + PictureHeader( p_vpar ); + return 0; + + case SEQUENCE_END_CODE: + msg_Dbg( p_vpar->p_fifo, "sequence end code received" ); + if( p_vpar->sequence.p_backward != NULL ) + { + p_vpar->sequence.p_backward->b_force = 1; + } + ReferenceUpdate( p_vpar, I_CODING_TYPE, NULL ); + return 1; + + default: + break; + } + + return 0; +} + +/* + * Following functions are local + */ + +/***************************************************************************** + * SequenceHeader : Parse the next sequence header + *****************************************************************************/ +static void SequenceHeader( vpar_thread_t * p_vpar ) +{ +#define RESERVED -1 + static int i_frame_rate_table[16] = + { + 0, + 23 * 1000, + 24 * 1001, + 25 * 1001, + 30 * 1000, + 30 * 1001, + 50 * 1001, + 60 * 1000, + 60 * 1001, + RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED, RESERVED + }; +#undef RESERVED + + int i_height_save, i_width_save, i_aspect; + + i_height_save = p_vpar->sequence.i_height; + i_width_save = p_vpar->sequence.i_width; + + p_vpar->sequence.i_width = GetBits( &p_vpar->bit_stream, 12 ); + p_vpar->sequence.i_height = GetBits( &p_vpar->bit_stream, 12 ); + i_aspect = GetBits( &p_vpar->bit_stream, 4 ); + p_vpar->sequence.i_frame_rate = + i_frame_rate_table[ GetBits( &p_vpar->bit_stream, 4 ) ]; + + /* We don't need bit_rate_value, marker_bit, vbv_buffer_size, + * constrained_parameters_flag */ + RemoveBits( &p_vpar->bit_stream, 30 ); + + /* + * Quantization matrices + */ + if( GetBits( &p_vpar->bit_stream, 1 ) ) /* load_intra_quantizer_matrix */ + { + LoadMatrix( p_vpar, &p_vpar->sequence.intra_quant ); + } + else + { + /* Use default matrix. */ + LinkMatrix( &p_vpar->sequence.intra_quant, + p_vpar->pi_default_intra_quant ); + } + + if( GetBits(&p_vpar->bit_stream, 1) ) /* load_non_intra_quantizer_matrix */ + { + LoadMatrix( p_vpar, &p_vpar->sequence.nonintra_quant ); + } + else + { + /* Use default matrix. */ + LinkMatrix( &p_vpar->sequence.nonintra_quant, + p_vpar->pi_default_nonintra_quant ); + } + + /* Unless later overwritten by a matrix extension, we have the same + * matrices for luminance and chrominance. */ + LinkMatrix( &p_vpar->sequence.chroma_intra_quant, + p_vpar->sequence.intra_quant.pi_matrix ); + LinkMatrix( &p_vpar->sequence.chroma_nonintra_quant, + p_vpar->sequence.nonintra_quant.pi_matrix ); + + /* + * Sequence Extension + */ + NextStartCode( &p_vpar->bit_stream ); + if( ShowBits( &p_vpar->bit_stream, 32 ) == EXTENSION_START_CODE ) + { + int i_dummy; + + /* Turn the MPEG2 flag on */ + p_vpar->sequence.b_mpeg2 = 1; + + /* Parse sequence_extension */ + RemoveBits32( &p_vpar->bit_stream ); + /* extension_start_code_identifier, profile_and_level_indication */ + RemoveBits( &p_vpar->bit_stream, 12 ); + p_vpar->sequence.b_progressive = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->sequence.i_chroma_format = GetBits( &p_vpar->bit_stream, 2 ); + p_vpar->sequence.i_width |= GetBits( &p_vpar->bit_stream, 2 ) << 12; + p_vpar->sequence.i_height |= GetBits( &p_vpar->bit_stream, 2 ) << 12; + /* bit_rate_extension, marker_bit, vbv_buffer_size_extension, + * low_delay */ + RemoveBits( &p_vpar->bit_stream, 22 ); + /* frame_rate_extension_n */ + i_dummy = GetBits( &p_vpar->bit_stream, 2 ); + /* frame_rate_extension_d */ + p_vpar->sequence.i_frame_rate *= (i_dummy + 1) + / (GetBits( &p_vpar->bit_stream, 5 ) + 1); + } + else + { + /* It's an MPEG-1 stream. Put adequate parameters. */ + int i_xyratio; + static int pi_mpeg1ratio[15] = { + 10000, 10000, 6735, 7031, 7615, 8055, 8437, 8935, + 9157, 9815, 10255, 10695, 10950, 11575, 12015 + }; + + if( i_aspect > 1 ) + { + i_xyratio = p_vpar->sequence.i_height * + pi_mpeg1ratio[i_aspect] / p_vpar->sequence.i_width; + if( 7450 < i_xyratio && i_xyratio < 7550 ) + { + i_aspect = 2; + } + else if( 5575 < i_xyratio && i_xyratio < 5675 ) + { + i_aspect = 3; + } + else if( 4475 < i_xyratio && i_xyratio < 4575 ) + { + i_aspect = 4; + } + } + + p_vpar->sequence.b_mpeg2 = 0; + p_vpar->sequence.b_progressive = 1; + p_vpar->sequence.i_chroma_format = CHROMA_420; + } + + /* check whether the input gives a particular aspect ratio */ + if( p_vpar->p_fifo->p_demux_data + && ( *(int*)(p_vpar->p_fifo->p_demux_data) & 0x7 ) ) + { + i_aspect = *(int*)(p_vpar->p_fifo->p_demux_data); + } + + /* Store calculated aspect ratio */ + switch( i_aspect ) + { + case AR_3_4_PICTURE: + p_vpar->sequence.i_aspect = VOUT_ASPECT_FACTOR * 4 / 3; + break; + + case AR_16_9_PICTURE: + p_vpar->sequence.i_aspect = VOUT_ASPECT_FACTOR * 16 / 9; + break; + + case AR_221_1_PICTURE: + p_vpar->sequence.i_aspect = VOUT_ASPECT_FACTOR * 221 / 100; + break; + + case AR_SQUARE_PICTURE: + default: + p_vpar->sequence.i_aspect = VOUT_ASPECT_FACTOR + * p_vpar->sequence.i_width / p_vpar->sequence.i_height; + break; + } + + /* Update sizes */ + p_vpar->sequence.i_mb_width = (p_vpar->sequence.i_width + 15) / 16; + p_vpar->sequence.i_mb_height = (p_vpar->sequence.b_progressive) ? + (p_vpar->sequence.i_height + 15) / 16 : + 2 * ((p_vpar->sequence.i_height + 31) / 32); + p_vpar->sequence.i_mb_size = p_vpar->sequence.i_mb_width + * p_vpar->sequence.i_mb_height; + p_vpar->sequence.i_width = (p_vpar->sequence.i_mb_width * 16); + p_vpar->sequence.i_height = (p_vpar->sequence.i_mb_height * 16); + p_vpar->sequence.i_size = p_vpar->sequence.i_width + * p_vpar->sequence.i_height; + switch( p_vpar->sequence.i_chroma_format ) + { + case CHROMA_420: + p_vpar->sequence.i_chroma_nb_blocks = 2; + p_vpar->sequence.b_chroma_h_subsampled = 1; + p_vpar->sequence.b_chroma_v_subsampled = 1; + break; + case CHROMA_422: + p_vpar->sequence.i_chroma_nb_blocks = 4; + p_vpar->sequence.b_chroma_h_subsampled = 1; + p_vpar->sequence.b_chroma_v_subsampled = 0; + break; + case CHROMA_444: + p_vpar->sequence.i_chroma_nb_blocks = 6; + p_vpar->sequence.b_chroma_h_subsampled = 0; + p_vpar->sequence.b_chroma_v_subsampled = 0; + break; + } + +#if 0 + if( p_vpar->sequence.i_width != i_width_save + || p_vpar->sequence.i_height != i_height_save ) + { + /* FIXME: Warn the video output */ + } +#endif + + /* Extension and User data */ + ExtensionAndUserData( p_vpar ); + + /* Spawn a video output if there is none. First we look for our children, + * then we look for any other vout that might be available. */ + p_vpar->p_vout = vlc_object_find( p_vpar->p_fifo, VLC_OBJECT_VOUT, + FIND_CHILD ); + if( p_vpar->p_vout == NULL ) + { + p_vpar->p_vout = vlc_object_find( p_vpar->p_fifo, VLC_OBJECT_VOUT, + FIND_ANYWHERE ); + } + + if( p_vpar->p_vout ) + { + if( p_vpar->p_vout->render.i_width != p_vpar->sequence.i_width + || p_vpar->p_vout->render.i_height != p_vpar->sequence.i_height + || p_vpar->p_vout->render.i_chroma != ChromaToFourCC( p_vpar->sequence.i_chroma_format ) + || p_vpar->p_vout->render.i_aspect != p_vpar->sequence.i_aspect ) + { + /* We are not interested in this format, close this vout */ + vlc_object_detach_all( p_vpar->p_vout ); + vlc_object_release( p_vpar->p_vout ); + vout_DestroyThread( p_vpar->p_vout ); + p_vpar->p_vout = NULL; + } + else + { + /* This video output is cool! Hijack it. */ + vlc_object_detach_all( p_vpar->p_vout ); + vlc_object_attach( p_vpar->p_vout, p_vpar->p_fifo ); + vlc_object_release( p_vpar->p_vout ); + } + } + + if( p_vpar->p_fifo->b_die || p_vpar->p_fifo->b_error ) + { + return; + } + + if( p_vpar->p_vout == NULL ) + { + msg_Dbg( p_vpar->p_fifo, "no vout present, spawning one" ); + + p_vpar->p_vout = vout_CreateThread( p_vpar->p_fifo, + p_vpar->sequence.i_width, + p_vpar->sequence.i_height, + ChromaToFourCC( p_vpar->sequence.i_chroma_format ), + p_vpar->sequence.i_aspect ); + + /* Everything failed */ + if( p_vpar->p_vout == NULL ) + { + msg_Err( p_vpar->p_fifo, "cannot open vout, aborting" ); + p_vpar->p_fifo->b_error = 1; + return; + } + } +} + +/***************************************************************************** + * GroupHeader : Parse the next group of pictures header + *****************************************************************************/ +static void GroupHeader( vpar_thread_t * p_vpar ) +{ + /* Nothing to do, we don't care. */ + RemoveBits( &p_vpar->bit_stream, 27 ); + ExtensionAndUserData( p_vpar ); +} + +/***************************************************************************** + * PictureHeader : Parse the next picture header + *****************************************************************************/ +static void PictureHeader( vpar_thread_t * p_vpar ) +{ + int i_structure, i_previous_coding_type; + vlc_bool_t b_parsable = 0; + + /* Retrieve the PTS. */ + CurrentPTS( &p_vpar->bit_stream, &p_vpar->sequence.next_pts, + &p_vpar->sequence.next_dts ); + + /* Recover in case of stream discontinuity. */ + if( p_vpar->sequence.b_expect_discontinuity ) + { + ReferenceUpdate( p_vpar, I_CODING_TYPE, NULL ); + ReferenceUpdate( p_vpar, I_CODING_TYPE, NULL ); + if( p_vpar->picture.p_picture != NULL ) + { + vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture ); + p_vpar->picture.p_picture = NULL; + } + p_vpar->picture.i_current_structure = 0; + p_vpar->sequence.b_expect_discontinuity = 0; + } + + /* Parse the picture header. */ + RemoveBits( &p_vpar->bit_stream, 10 ); /* temporal_reference */ + i_previous_coding_type = p_vpar->picture.i_coding_type; + p_vpar->picture.i_coding_type = GetBits( &p_vpar->bit_stream, 3 ); + RemoveBits( &p_vpar->bit_stream, 16 ); /* vbv_delay */ + + if( p_vpar->picture.i_coding_type == P_CODING_TYPE + || p_vpar->picture.i_coding_type == B_CODING_TYPE ) + { + p_vpar->picture.ppi_f_code[0][1] = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.ppi_f_code[0][0] = GetBits( &p_vpar->bit_stream, 3 ) + - 1; + } + if( p_vpar->picture.i_coding_type == B_CODING_TYPE ) + { + p_vpar->picture.ppi_f_code[1][1] = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.ppi_f_code[1][0] = GetBits( &p_vpar->bit_stream, 3 ) + - 1; + } + + /* extra_information_picture */ + while( GetBits( &p_vpar->bit_stream, 1 ) ) + { + RemoveBits( &p_vpar->bit_stream, 8 ); + } + + /* + * Picture Coding Extension + */ + NextStartCode( &p_vpar->bit_stream ); + if( ShowBits( &p_vpar->bit_stream, 32 ) == EXTENSION_START_CODE ) + { + /* Parse picture_coding_extension */ + RemoveBits32( &p_vpar->bit_stream ); + /* extension_start_code_identifier */ + RemoveBits( &p_vpar->bit_stream, 4 ); + + /* Pre-substract 1 for later use in MotionDelta(). */ + p_vpar->picture.ppi_f_code[0][0] = GetBits( &p_vpar->bit_stream, 4 ) -1; + p_vpar->picture.ppi_f_code[0][1] = GetBits( &p_vpar->bit_stream, 4 ) -1; + p_vpar->picture.ppi_f_code[1][0] = GetBits( &p_vpar->bit_stream, 4 ) -1; + p_vpar->picture.ppi_f_code[1][1] = GetBits( &p_vpar->bit_stream, 4 ) -1; + p_vpar->picture.i_intra_dc_precision = GetBits( &p_vpar->bit_stream, 2 ); + i_structure = GetBits( &p_vpar->bit_stream, 2 ); + p_vpar->picture.b_top_field_first = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.b_frame_pred_frame_dct + = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.b_concealment_mv = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.b_q_scale_type = GetBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.b_intra_vlc_format = GetBits( &p_vpar->bit_stream, 1 ); + /* Alternate scan */ + p_vpar->picture.pi_scan = + p_vpar->ppi_scan[ GetBits( &p_vpar->bit_stream, 1 ) ]; + p_vpar->picture.b_repeat_first_field = GetBits( &p_vpar->bit_stream, 1 ); + /* chroma_420_type (obsolete) */ + RemoveBits( &p_vpar->bit_stream, 1 ); + p_vpar->picture.b_progressive = GetBits( &p_vpar->bit_stream, 1 ); + + /* composite_display_flag */ + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* v_axis, field_sequence, sub_carrier, burst_amplitude, + * sub_carrier_phase */ + RemoveBits( &p_vpar->bit_stream, 20 ); + } + } + else + { + /* MPEG-1 compatibility flags */ + p_vpar->picture.i_intra_dc_precision = 0; /* 8 bits */ + i_structure = FRAME_STRUCTURE; + p_vpar->picture.b_top_field_first = 0; + p_vpar->picture.b_frame_pred_frame_dct = 1; + p_vpar->picture.b_concealment_mv = 0; + p_vpar->picture.b_q_scale_type = 0; + p_vpar->picture.b_intra_vlc_format = 0; + p_vpar->picture.pi_scan = p_vpar->ppi_scan[0]; + p_vpar->picture.b_repeat_first_field = 0; + p_vpar->picture.b_progressive = 1; + } + + /* Extension and User data. */ + ExtensionAndUserData( p_vpar ); + + p_vpar->pc_pictures[p_vpar->picture.i_coding_type]++; + + if( p_vpar->picture.i_current_structure ) + { + if ( (i_structure == FRAME_STRUCTURE || + i_structure == p_vpar->picture.i_current_structure) ) + { + /* We don't have the second field of the buffered frame. */ + if( p_vpar->picture.p_picture != NULL ) + { + ReferenceReplace( p_vpar, + p_vpar->picture.i_coding_type, + NULL ); + vout_DestroyPicture( p_vpar->p_vout, + p_vpar->picture.p_picture ); + p_vpar->picture.p_picture = NULL; + } + + p_vpar->picture.i_current_structure = 0; + + msg_Warn( p_vpar->p_fifo, "odd number of field pictures" ); + } + else + { + /* Second field of a frame. We will decode it if, and only if we + * have decoded the first field. */ + if( p_vpar->picture.p_picture == NULL ) + { + if( (p_vpar->picture.i_coding_type == I_CODING_TYPE + && p_vpar->sequence.p_backward == NULL) ) + { + /* Exceptionnally, parse the picture if it is I. We need + * this in case of an odd number of field pictures, if the + * previous picture is not intra, we desperately need a + * new reference picture. OK, this is kind of kludgy. */ + p_vpar->picture.i_current_structure = 0; + } + else + { + b_parsable = 0; + } + } + else + { + /* We suppose we have the reference pictures, since we already + * decoded the first field and the second field will not need + * any extra reference picture. There is a special case of + * P field being the second field of an I field, but ISO/IEC + * 13818-2 section 7.6.3.5 specifies that this P field will + * not need any reference picture besides the I field. So far + * so good. */ + b_parsable = 1; + + if( p_vpar->picture.i_coding_type == P_CODING_TYPE && + i_previous_coding_type == I_CODING_TYPE && + p_vpar->sequence.p_forward == NULL ) + { + /* This is the special case of section 7.6.3.5. Create + * a fake reference picture (which will not be used) + * but will prevent us from segfaulting in the slice + * parsing. */ + static picture_t fake_picture; + fake_picture.i_planes = 0; /* We will use it later */ + p_vpar->sequence.p_forward = &fake_picture; + } + } + } + } + + if( !p_vpar->picture.i_current_structure ) + { + /* First field of a frame, or new frame picture. */ + int i_repeat_field; + + /* Do we have the reference pictures ? */ + b_parsable = !(((p_vpar->picture.i_coding_type == P_CODING_TYPE || + p_vpar->picture.b_concealment_mv) && + (p_vpar->sequence.p_backward == NULL)) || + /* p_backward will become p_forward later */ + ((p_vpar->picture.i_coding_type == B_CODING_TYPE) && + (p_vpar->sequence.p_forward == NULL || + p_vpar->sequence.p_backward == NULL))); + + /* Compute the number of times the frame will be emitted by the + * decoder (number of half-periods). */ + if( p_vpar->sequence.b_progressive ) + { + i_repeat_field = (1 + p_vpar->picture.b_repeat_first_field + + p_vpar->picture.b_top_field_first) * 2; + } + else + { + if( p_vpar->picture.b_progressive ) + { + i_repeat_field = 2 + p_vpar->picture.b_repeat_first_field; + } + else + { + i_repeat_field = 2; + } + } + + /* Warn synchro we have a new picture (updates pictures index). */ + vpar_SynchroNewPicture( p_vpar, p_vpar->picture.i_coding_type, + i_repeat_field ); + + if( b_parsable ) + { + /* Does synchro say we have enough time to decode it ? */ + b_parsable = vpar_SynchroChoose( p_vpar, + p_vpar->picture.i_coding_type, i_structure ); + } + } + + if( !b_parsable ) + { + /* Update the reference pointers. */ + ReferenceUpdate( p_vpar, p_vpar->picture.i_coding_type, NULL ); + + /* Update context. */ + if( i_structure != FRAME_STRUCTURE ) + { + if( (p_vpar->picture.i_current_structure | i_structure) + == FRAME_STRUCTURE ) + { + /* The frame is complete. */ + p_vpar->picture.i_current_structure = 0; + + vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure ); + } + else + { + p_vpar->picture.i_current_structure = i_structure; + } + } + else + { + /* Warn Synchro we have trashed a picture. */ + vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure ); + } + p_vpar->picture.p_picture = NULL; + + return; + } + + /* OK, now we are sure we will decode the picture. */ + p_vpar->pc_decoded_pictures[p_vpar->picture.i_coding_type]++; + +#define P_picture p_vpar->picture.p_picture + p_vpar->picture.b_error = 0; + p_vpar->picture.b_frame_structure = (i_structure == FRAME_STRUCTURE); + + if( !p_vpar->picture.i_current_structure ) + { + /* This is a new frame. Get a structure from the video_output. */ + while( ( P_picture = vout_CreatePicture( p_vpar->p_vout, + p_vpar->picture.b_progressive, + p_vpar->picture.b_top_field_first, + p_vpar->picture.b_repeat_first_field ) ) + == NULL ) + { + if( p_vpar->p_fifo->b_die || p_vpar->p_fifo->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + /* Initialize values. */ + vpar_SynchroDecode( p_vpar, p_vpar->picture.i_coding_type, i_structure ); + P_picture->i_matrix_coefficients = p_vpar->sequence.i_matrix_coefficients; + + /* Update the reference pointers. */ + ReferenceUpdate( p_vpar, p_vpar->picture.i_coding_type, P_picture ); + } + + /* Initialize picture data for decoding. */ + p_vpar->picture.i_current_structure |= i_structure; + p_vpar->picture.i_structure = i_structure; + p_vpar->picture.b_second_field = + (i_structure != p_vpar->picture.i_current_structure); + p_vpar->picture.b_current_field = + (i_structure == BOTTOM_FIELD ); + p_vpar->picture.i_lum_stride = p_vpar->picture.p_picture->Y_PITCH + << ( 1 - p_vpar->picture.b_frame_structure ); + p_vpar->picture.i_chrom_stride = p_vpar->picture.p_picture->U_PITCH + << ( 1 - p_vpar->picture.b_frame_structure ); + /* We suppose the pitch is the same for U and V planes. */ + p_vpar->picture.i_field_width = p_vpar->sequence.i_width + << ( 1 - p_vpar->picture.b_frame_structure ); + + if( !p_vpar->p_fifo->p_stream_ctrl->b_grayscale ) + { + switch( p_vpar->sequence.i_chroma_format ) + { + case CHROMA_422: + p_vpar->pool.pf_vdec_decode = vdec_DecodeMacroblock422; + break; + case CHROMA_444: + p_vpar->pool.pf_vdec_decode = vdec_DecodeMacroblock444; + break; + case CHROMA_420: + default: + p_vpar->pool.pf_vdec_decode = vdec_DecodeMacroblock420; + break; + } + } + else + { + p_vpar->pool.pf_vdec_decode = vdec_DecodeMacroblockBW; + } + + + if( p_vpar->sequence.b_mpeg2 ) + { + static f_picture_data_t ppf_picture_data[4][4] = + { + { + NULL, NULL, NULL, NULL + }, + { + /* TOP_FIELD */ +#if (VPAR_OPTIM_LEVEL > 1) + NULL, vpar_PictureData2IT, vpar_PictureData2PT, + vpar_PictureData2BT +#else + NULL, vpar_PictureDataGENERIC, vpar_PictureDataGENERIC, + vpar_PictureDataGENERIC +#endif + }, + { + /* BOTTOM_FIELD */ +#if (VPAR_OPTIM_LEVEL > 1) + NULL, vpar_PictureData2IB, vpar_PictureData2PB, + vpar_PictureData2BB +#else + NULL, vpar_PictureDataGENERIC, vpar_PictureDataGENERIC, + vpar_PictureDataGENERIC +#endif + }, + { + /* FRAME_PICTURE */ +#if (VPAR_OPTIM_LEVEL > 0) + NULL, vpar_PictureData2IF, vpar_PictureData2PF, + vpar_PictureData2BF +#else + NULL, vpar_PictureDataGENERIC, vpar_PictureDataGENERIC, + vpar_PictureDataGENERIC +#endif + } + }; + + ppf_picture_data[p_vpar->picture.i_structure] + [p_vpar->picture.i_coding_type]( p_vpar ); + } + else + { +#if (VPAR_OPTIM_LEVEL > 1) + static f_picture_data_t pf_picture_data[5] = + { NULL, vpar_PictureData1I, vpar_PictureData1P, vpar_PictureData1B, + vpar_PictureData1D }; + + pf_picture_data[p_vpar->picture.i_coding_type]( p_vpar ); +#else + vpar_PictureDataGENERIC( p_vpar ); +#endif + } + + /* Wait for all the macroblocks to be decoded. */ + p_vpar->pool.pf_wait_pool( &p_vpar->pool ); + + /* Re-spawn decoder threads if the user changed settings. */ + vpar_SpawnPool( p_vpar ); + + if( p_vpar->p_fifo->b_die || p_vpar->p_fifo->b_error ) + { + return; + } + + if( p_vpar->sequence.p_forward != NULL && + p_vpar->sequence.p_forward->i_planes == 0 ) + { + /* This can only happen with the fake picture created for section + * 7.6.3.5. Clean up our mess. */ + p_vpar->sequence.p_forward = NULL; + } + + if( p_vpar->picture.b_error ) + { + /* Trash picture. */ + p_vpar->pc_malformed_pictures[p_vpar->picture.i_coding_type]++; + + vpar_SynchroEnd( p_vpar, p_vpar->picture.i_coding_type, + p_vpar->picture.i_structure, 1 ); + vout_DestroyPicture( p_vpar->p_vout, P_picture ); + + ReferenceReplace( p_vpar, p_vpar->picture.i_coding_type, NULL ); + + /* Prepare context for the next picture. */ + P_picture = NULL; + if( p_vpar->picture.i_current_structure == FRAME_STRUCTURE ) + p_vpar->picture.i_current_structure = 0; + } + else if( p_vpar->picture.i_current_structure == FRAME_STRUCTURE ) + { + /* Frame completely parsed. */ + vpar_SynchroEnd( p_vpar, p_vpar->picture.i_coding_type, + p_vpar->picture.i_structure, 0 ); + vout_DisplayPicture( p_vpar->p_vout, P_picture ); + + /* Prepare context for the next picture. */ + P_picture = NULL; + p_vpar->picture.i_current_structure = 0; + } +#undef P_picture +} + +/***************************************************************************** + * ExtensionAndUserData : Parse the extension_and_user_data structure + *****************************************************************************/ +static void ExtensionAndUserData( vpar_thread_t * p_vpar ) +{ + while( !p_vpar->p_fifo->b_die ) + { + NextStartCode( &p_vpar->bit_stream ); + switch( ShowBits( &p_vpar->bit_stream, 32 ) ) + { + case EXTENSION_START_CODE: + RemoveBits32( &p_vpar->bit_stream ); + switch( GetBits( &p_vpar->bit_stream, 4 ) ) + { + case SEQUENCE_DISPLAY_EXTENSION_ID: + SequenceDisplayExtension( p_vpar ); + break; + case QUANT_MATRIX_EXTENSION_ID: + QuantMatrixExtension( p_vpar ); + break; + case SEQUENCE_SCALABLE_EXTENSION_ID: + SequenceScalableExtension( p_vpar ); + break; + case PICTURE_DISPLAY_EXTENSION_ID: + PictureDisplayExtension( p_vpar ); + break; + case PICTURE_SPATIAL_SCALABLE_EXTENSION_ID: + PictureSpatialScalableExtension( p_vpar ); + break; + case PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID: + PictureTemporalScalableExtension( p_vpar ); + break; + case COPYRIGHT_EXTENSION_ID: + CopyrightExtension( p_vpar ); + break; + default: + break; + } + break; + + case USER_DATA_START_CODE: + RemoveBits32( &p_vpar->bit_stream ); + /* Wait for the next start code */ + break; + + default: + return; + } + } +} + + +/***************************************************************************** + * SequenceDisplayExtension : Parse the sequence_display_extension structure * + *****************************************************************************/ + +static void SequenceDisplayExtension( vpar_thread_t * p_vpar ) +{ + /* We don't care sequence_display_extension. */ + /* video_format */ + RemoveBits( &p_vpar->bit_stream, 3 ); + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* Two bytes for color_desciption */ + RemoveBits( &p_vpar->bit_stream, 16 ); + p_vpar->sequence.i_matrix_coefficients = GetBits( &p_vpar->bit_stream, 8 ); + } + /* display_horizontal and vertical_size and a marker_bit */ + RemoveBits( &p_vpar->bit_stream, 29 ); +} + + +/***************************************************************************** + * QuantMatrixExtension : Load quantization matrices for luminance * + * and chrominance * + *****************************************************************************/ + +static void QuantMatrixExtension( vpar_thread_t * p_vpar ) +{ + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* Load intra_quantiser_matrix for luminance. */ + LoadMatrix( p_vpar, &p_vpar->sequence.intra_quant ); + } + else + { + /* Use the default matrix. */ + LinkMatrix( &p_vpar->sequence.intra_quant, + p_vpar->pi_default_intra_quant ); + } + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* Load non_intra_quantiser_matrix for luminance. */ + LoadMatrix( p_vpar, &p_vpar->sequence.nonintra_quant ); + } + else + { + /* Use the default matrix. */ + LinkMatrix( &p_vpar->sequence.nonintra_quant, + p_vpar->pi_default_nonintra_quant ); + } + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* Load intra_quantiser_matrix for chrominance. */ + LoadMatrix( p_vpar, &p_vpar->sequence.chroma_intra_quant ); + } + else + { + /* Link the chrominance intra matrix to the luminance one. */ + LinkMatrix( &p_vpar->sequence.chroma_intra_quant, + p_vpar->sequence.intra_quant.pi_matrix ); + } + if( GetBits( &p_vpar->bit_stream, 1 ) ) + { + /* Load non_intra_quantiser_matrix for chrominance. */ + LoadMatrix( p_vpar, &p_vpar->sequence.chroma_nonintra_quant ); + } + else + { + /* Link the chrominance nonintra matrix to the luminance one. */ + LinkMatrix( &p_vpar->sequence.chroma_nonintra_quant, + p_vpar->sequence.nonintra_quant.pi_matrix ); + } +} + + +/***************************************************************************** + * SequenceScalableExtension : Parse the sequence_scalable_extension * + * structure to handle scalable coding * + *****************************************************************************/ + +static void SequenceScalableExtension( vpar_thread_t * p_vpar ) +{ + /* We don't care about anything scalable except the scalable mode. */ + switch( p_vpar->sequence.i_scalable_mode = GetBits( &p_vpar->bit_stream, 2 ) ) + /* The length of the structure depends on the value of the scalable_mode */ + { + case 1: + RemoveBits32( &p_vpar->bit_stream ); + RemoveBits( &p_vpar->bit_stream, 21 ); + break; + case 2: + RemoveBits( &p_vpar->bit_stream, 12 ); + break; + default: + RemoveBits( &p_vpar->bit_stream, 4 ); + } + +} +/***************************************************************************** + * PictureDisplayExtension : Parse the picture_display_extension structure * + *****************************************************************************/ + +static void PictureDisplayExtension( vpar_thread_t * p_vpar ) +{ + /* Number of frame center offset */ + int i_nb, i_dummy; + /* I am not sure it works but it should + (fewer tests than shown in §6.3.12) */ + i_nb = p_vpar->sequence.b_progressive ? p_vpar->sequence.b_progressive + + p_vpar->picture.b_repeat_first_field + + p_vpar->picture.b_top_field_first + : ( p_vpar->picture.b_frame_structure + 1 ) + + p_vpar->picture.b_repeat_first_field; + for( i_dummy = 0; i_dummy < i_nb; i_dummy++ ) + { + RemoveBits( &p_vpar->bit_stream, 17 ); + RemoveBits( &p_vpar->bit_stream, 17 ); + } +} + + +/***************************************************************************** + * PictureSpatialScalableExtension * + *****************************************************************************/ + +static void PictureSpatialScalableExtension( vpar_thread_t * p_vpar ) +{ + /* That's scalable, so we trash it */ + RemoveBits32( &p_vpar->bit_stream ); + RemoveBits( &p_vpar->bit_stream, 16 ); +} + + +/***************************************************************************** + * PictureTemporalScalableExtension * + *****************************************************************************/ + +static void PictureTemporalScalableExtension( vpar_thread_t * p_vpar ) +{ + /* Scalable again, trashed again */ + RemoveBits( &p_vpar->bit_stream, 23 ); +} + + +/***************************************************************************** + * CopyrightExtension : Keeps some legal informations * + *****************************************************************************/ + +static void CopyrightExtension( vpar_thread_t * p_vpar ) +{ + u32 i_copyright_nb_1, i_copyright_nb_2; /* local integers */ + p_vpar->sequence.b_copyright_flag = GetBits( &p_vpar->bit_stream, 1 ); + /* A flag that says whether the copyright information is significant */ + p_vpar->sequence.i_copyright_id = GetBits( &p_vpar->bit_stream, 8 ); + /* An identifier compliant with ISO/CEI JTC 1/SC 29 */ + p_vpar->sequence.b_original = GetBits( &p_vpar->bit_stream, 1 ); + /* Reserved bits */ + RemoveBits( &p_vpar->bit_stream, 8 ); + /* The copyright_number is split in three parts */ + /* first part */ + i_copyright_nb_1 = GetBits( &p_vpar->bit_stream, 20 ); + RemoveBits( &p_vpar->bit_stream, 1 ); + /* second part */ + i_copyright_nb_2 = GetBits( &p_vpar->bit_stream, 22 ); + RemoveBits( &p_vpar->bit_stream, 1 ); + /* third part and sum */ + p_vpar->sequence.i_copyright_nb = ( (u64)i_copyright_nb_1 << 44 ) | + ( (u64)i_copyright_nb_2 << 22 ) | + ( (u64)GetBits( &p_vpar->bit_stream, 22 ) ); +} diff --git a/modules/codec/mpeg_video/idct/.cvsignore b/modules/codec/mpeg_video/idct/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/mpeg_video/idct/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/mpeg_video/idct/Makefile b/modules/codec/mpeg_video/idct/Makefile new file mode 100644 index 0000000000..f8c68d50fd --- /dev/null +++ b/modules/codec/mpeg_video/idct/Makefile @@ -0,0 +1,5 @@ +idct_SOURCES = idct.c +idctclassic_SOURCES = idctclassic.c +idctmmx_SOURCES = idctmmx.c +idctmmxext_SOURCES = idctmmxext.c +idctaltivec_SOURCES = idctaltivec.c diff --git a/modules/codec/mpeg_video/idct/block_c.h b/modules/codec/mpeg_video/idct/block_c.h new file mode 100644 index 0000000000..fc6a9b89f5 --- /dev/null +++ b/modules/codec/mpeg_video/idct/block_c.h @@ -0,0 +1,103 @@ +/***************************************************************************** + * block_c.h: Macroblock copy functions in C + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: block_c.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * Static variables + ***************************************************************************** + * We can keep them static since they will always contain the same values. + *****************************************************************************/ +static u8 pi_crop_buf[VDEC_CROPRANGE]; +static u8 *pi_crop; + +/***************************************************************************** + * InitBlock: initialize the crop table + *****************************************************************************/ +static void InitBlock ( ) +{ + int i_dummy; + + /* Init crop table */ + pi_crop = pi_crop_buf + (VDEC_CROPRANGE >> 1); + + for( i_dummy = -(VDEC_CROPRANGE >> 1); i_dummy < 0; i_dummy++ ) + { + pi_crop[i_dummy] = 0; + } + + for( ; i_dummy < 255; i_dummy ++ ) + { + pi_crop[i_dummy] = i_dummy; + } + + for( ; i_dummy < (VDEC_CROPRANGE >> 1) -1; i_dummy++ ) + { + pi_crop[i_dummy] = 255; + } +} + +/***************************************************************************** + * AddBlock: add a block + *****************************************************************************/ +static inline void AddBlock( dctelem_t * p_block, yuv_data_t * p_data, + int i_incr ) +{ + int i = 8; + + do { + p_data[0] = pi_crop[ p_data[0] + p_block[0] ]; + p_data[1] = pi_crop[ p_data[1] + p_block[1] ]; + p_data[2] = pi_crop[ p_data[2] + p_block[2] ]; + p_data[3] = pi_crop[ p_data[3] + p_block[3] ]; + p_data[4] = pi_crop[ p_data[4] + p_block[4] ]; + p_data[5] = pi_crop[ p_data[5] + p_block[5] ]; + p_data[6] = pi_crop[ p_data[6] + p_block[6] ]; + p_data[7] = pi_crop[ p_data[7] + p_block[7] ]; + + p_data += i_incr; + p_block += 8; + } while( --i ); +} + +/***************************************************************************** + * CopyBlock: copy a block + *****************************************************************************/ +static inline void CopyBlock( dctelem_t * p_block, yuv_data_t * p_data, + int i_incr ) +{ + int i = 8; + + do { + p_data[0] = pi_crop[ p_block[0] ]; + p_data[1] = pi_crop[ p_block[1] ]; + p_data[2] = pi_crop[ p_block[2] ]; + p_data[3] = pi_crop[ p_block[3] ]; + p_data[4] = pi_crop[ p_block[4] ]; + p_data[5] = pi_crop[ p_block[5] ]; + p_data[6] = pi_crop[ p_block[6] ]; + p_data[7] = pi_crop[ p_block[7] ]; + + p_data += i_incr; + p_block += 8; + } while( --i ); +} + diff --git a/modules/codec/mpeg_video/idct/block_mmx.h b/modules/codec/mpeg_video/idct/block_mmx.h new file mode 100644 index 0000000000..f58d78a99c --- /dev/null +++ b/modules/codec/mpeg_video/idct/block_mmx.h @@ -0,0 +1,103 @@ +/***************************************************************************** + * block_mmx.h: Macroblock copy functions in MMX assembly + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: block_mmx.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Lespinasse + * Aaron Holtzman + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * InitBlock: placeholder because we don't need a crop table, MMX does it for us + *****************************************************************************/ +static inline void InitBlock( ) +{ + ; +} + +/***************************************************************************** + * AddBlock: add a block + *****************************************************************************/ +#define ADD_MMX(offset,r1,r2,r3,r4) \ + movq_m2r (*(p_data+2*i_incr), r1); \ + packuswb_r2r (r4, r3); \ + movq_r2r (r1, r2); \ + p_data += i_incr; \ + movq_r2m (r3, *p_data); \ + punpcklbw_r2r (mm0, r1); \ + paddsw_m2r (*(p_block+offset), r1); \ + punpckhbw_r2r (mm0, r2); \ + paddsw_m2r (*(p_block+offset+4), r2); + +static inline void AddBlock( dctelem_t * p_block, yuv_data_t * p_data, + int i_incr ) +{ + movq_m2r (*p_data, mm1); + pxor_r2r (mm0, mm0); + movq_m2r (*(p_data + i_incr), mm3); + movq_r2r (mm1, mm2); + punpcklbw_r2r (mm0, mm1); + movq_r2r (mm3, mm4); + paddsw_m2r (*(p_block+0*8), mm1); + punpckhbw_r2r (mm0, mm2); + paddsw_m2r (*(p_block+0*8+4), mm2); + punpcklbw_r2r (mm0, mm3); + paddsw_m2r (*(p_block+1*8), mm3); + packuswb_r2r (mm2, mm1); + punpckhbw_r2r (mm0, mm4); + movq_r2m (mm1, *p_data); + paddsw_m2r (*(p_block+1*8+4), mm4); + ADD_MMX (2*8, mm1, mm2, mm3, mm4); + ADD_MMX (3*8, mm3, mm4, mm1, mm2); + ADD_MMX (4*8, mm1, mm2, mm3, mm4); + ADD_MMX (5*8, mm3, mm4, mm1, mm2); + ADD_MMX (6*8, mm1, mm2, mm3, mm4); + ADD_MMX (7*8, mm3, mm4, mm1, mm2); + packuswb_r2r (mm4, mm3); + movq_r2m (mm3, *(p_data + i_incr)); +} + +/***************************************************************************** + * CopyBlock: copy a block + *****************************************************************************/ +#define COPY_MMX(offset,r0,r1,r2) \ + movq_m2r (*(p_block+offset), r0); \ + p_data += i_incr; \ + movq_m2r (*(p_block+offset+4), r1); \ + movq_r2m (r2, *p_data); \ + packuswb_r2r (r1, r0); + +static inline void CopyBlock( dctelem_t * p_block, yuv_data_t * p_data, + int i_incr ) +{ + movq_m2r (*(p_block+0*8), mm0); + movq_m2r (*(p_block+0*8+4), mm1); + movq_m2r (*(p_block+1*8), mm2); + packuswb_r2r (mm1, mm0); + movq_m2r (*(p_block+1*8+4), mm3); + movq_r2m (mm0, *p_data); + packuswb_r2r (mm3, mm2); + COPY_MMX (2*8, mm0, mm1, mm2); + COPY_MMX (3*8, mm2, mm3, mm0); + COPY_MMX (4*8, mm0, mm1, mm2); + COPY_MMX (5*8, mm2, mm3, mm0); + COPY_MMX (6*8, mm0, mm1, mm2); + COPY_MMX (7*8, mm2, mm3, mm0); + movq_r2m (mm2, *(p_data + i_incr)); +} + diff --git a/modules/codec/mpeg_video/idct/idct.c b/modules/codec/mpeg_video/idct/idct.c new file mode 100644 index 0000000000..9dad3a9ccf --- /dev/null +++ b/modules/codec/mpeg_video/idct/idct.c @@ -0,0 +1,1243 @@ +/***************************************************************************** + * idct.c : C IDCT module + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: idct.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Author: Gaël Hendryckx + * + * 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 +#include + +#include + +#include "idct.h" +#include "block_c.h" + +static int Open( vlc_object_t *p_this ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("IDCT module") ); + set_capability( "idct", 50 ); + add_shortcut( "c" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/* Following functions are local */ + +/***************************************************************************** + * NormScan : Unused in this IDCT + *****************************************************************************/ +static void NormScan( u8 ppi_scan[2][64] ) +{ +} + +/***************************************************************************** + * IDCT : IDCT function for normal matrices + *****************************************************************************/ +static inline void IDCT( dctelem_t * p_block ) +{ + s32 tmp0, tmp1, tmp2, tmp3; + s32 tmp10, tmp11, tmp12, tmp13; + s32 z1, z2, z3, z4, z5; + s32 d0, d1, d2, d3, d4, d5, d6, d7; + dctelem_t * dataptr; + int rowctr; + + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = p_block; + + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) + { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + register int * idataptr = (int*)dataptr; + d0 = dataptr[0]; + d1 = dataptr[1]; + if ( (d1 == 0) && ((idataptr[1] | idataptr[2] | idataptr[3]) == 0) ) + { + /* AC terms all zero */ + if (d0) + { + /* Compute a 32 bit value to assign. */ + dctelem_t dcval = (dctelem_t) (d0 << PASS1_BITS); + register int v = (dcval & 0xffff) | (dcval << 16); + + idataptr[0] = v; + idataptr[1] = v; + idataptr[2] = v; + idataptr[3] = v; + } + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + d2 = dataptr[2]; + d3 = dataptr[3]; + d4 = dataptr[4]; + d5 = dataptr[5]; + d6 = dataptr[6]; + d7 = dataptr[7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) + { + if (d4) + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } + else + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } + else + { + if (d4) + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } + else + { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } + else + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } + else + { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + if (d7) + { + if (d5) + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d7 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } + else + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } + else + { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } + else + { + if (d5) + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp1 += z4; + tmp2 = z2 + z5; + tmp3 += z4; + } + else + { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } + else + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } + else + { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } + else + { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (dctelem_t) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (dctelem_t) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (dctelem_t) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (dctelem_t) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (dctelem_t) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (dctelem_t) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (dctelem_t) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (dctelem_t) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = p_block; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) + { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + + d0 = dataptr[DCTSIZE*0]; + d1 = dataptr[DCTSIZE*1]; + d2 = dataptr[DCTSIZE*2]; + d3 = dataptr[DCTSIZE*3]; + d4 = dataptr[DCTSIZE*4]; + d5 = dataptr[DCTSIZE*5]; + d6 = dataptr[DCTSIZE*6]; + d7 = dataptr[DCTSIZE*7]; + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + if (d6) + { + if (d4) + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 != 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 == 0, d4 != 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, -FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + } + else + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 == 0, d6 != 0 */ + z1 = MULTIPLY(d2 + d6, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(d6, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(d2, FIX(0.765366865)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 == 0, d4 == 0, d6 != 0 */ + tmp2 = MULTIPLY(d6, - FIX2(1.306562965)); + tmp3 = MULTIPLY(d6, FIX(0.541196100)); + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + } + } + else + { + if (d4) + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = (d0 + d4) << CONST_BITS; + tmp1 = (d0 - d4) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 != 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d4 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp2 - tmp0; + tmp12 = -(tmp0 + tmp2); + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = (d0 + d4) << CONST_BITS; + tmp11 = tmp12 = (d0 - d4) << CONST_BITS; + } + else + { + /* d0 == 0, d2 == 0, d4 != 0, d6 == 0 */ + tmp10 = tmp13 = d4 << CONST_BITS; + tmp11 = tmp12 = -tmp10; + } + } + } + else + { + if (d2) + { + if (d0) + { + /* d0 != 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp0 = d0 << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + } + else + { + /* d0 == 0, d2 != 0, d4 == 0, d6 == 0 */ + tmp2 = MULTIPLY(d2, FIX(0.541196100)); + tmp3 = MULTIPLY(d2, (FIX(1.306562965) + .5)); + + tmp10 = tmp3; + tmp13 = -tmp3; + tmp11 = tmp2; + tmp12 = -tmp2; + } + } + else + { + if (d0) + { + /* d0 != 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = d0 << CONST_BITS; + } + else + { + /* d0 == 0, d2 == 0, d4 == 0, d6 == 0 */ + tmp10 = tmp13 = tmp11 = tmp12 = 0; + } + } + } + } + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + if (d7) + { + if (d5) + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z2 = d5 + d3; + z3 = d7 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 != 0, d7 != 0 */ + z2 = d5 + d3; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d5, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 = z1 + z4; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 != 0, d7 != 0 */ + z1 = d7 + d1; + z4 = d5 + d1; + z5 = MULTIPLY(d7 + z4, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 = z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 == 0, d5 != 0, d7 != 0 */ + z5 = MULTIPLY(d5 + d7, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z3; + tmp1 += z4; + tmp2 = z2 + z3; + tmp3 = z1 + z4; + } + } + } + else + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z3 = d7 + d3; + z5 = MULTIPLY(z3 + d1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, FIX(0.298631336)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(z1, - FIX(0.899976223)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 = z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 == 0, d7 != 0 */ + z3 = d7 + d3; + z5 = MULTIPLY(z3, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(0.601344887)); + z1 = MULTIPLY(d7, - FIX(0.899976223)); + tmp2 = MULTIPLY(d3, FIX(0.509795579)); + z2 = MULTIPLY(d3, - FIX(2.562915447)); + z3 = MULTIPLY(z3, - FIX2(0.785694958)); + + tmp0 += z3; + tmp1 = z2 + z5; + tmp2 += z3; + tmp3 = z1 + z5; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 == 0, d7 != 0 */ + z1 = d7 + d1; + z5 = MULTIPLY(z1, FIX(1.175875602)); + + tmp0 = MULTIPLY(d7, - FIX2(1.662939224)); + tmp3 = MULTIPLY(d1, FIX2(1.111140466)); + z1 = MULTIPLY(z1, FIX2(0.275899379)); + z3 = MULTIPLY(d7, - FIX(1.961570560)); + z4 = MULTIPLY(d1, - FIX(0.390180644)); + + tmp0 += z1; + tmp1 = z4 + z5; + tmp2 = z3 + z5; + tmp3 += z1; + } + else + { + /* d1 == 0, d3 == 0, d5 == 0, d7 != 0 */ + tmp0 = MULTIPLY(d7, - FIX2(1.387039845)); + tmp1 = MULTIPLY(d7, FIX(1.175875602)); + tmp2 = MULTIPLY(d7, - FIX2(0.785694958)); + tmp3 = MULTIPLY(d7, FIX2(0.275899379)); + } + } + } + } + else + { + if (d5) + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z4 = d5 + d1; + z5 = MULTIPLY(d3 + z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX(2.053119869)); + tmp2 = MULTIPLY(d3, FIX(3.072711026)); + tmp3 = MULTIPLY(d1, FIX(1.501321110)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(z2, - FIX(2.562915447)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(z4, - FIX(0.390180644)); + + z3 += z5; + z4 += z5; + + tmp0 = z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + } + else + { + /* d1 == 0, d3 != 0, d5 != 0, d7 == 0 */ + z2 = d5 + d3; + z5 = MULTIPLY(z2, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, FIX2(1.662939225)); + tmp2 = MULTIPLY(d3, FIX2(1.111140466)); + z2 = MULTIPLY(z2, - FIX2(1.387039845)); + z3 = MULTIPLY(d3, - FIX(1.961570560)); + z4 = MULTIPLY(d5, - FIX(0.390180644)); + + tmp0 = z3 + z5; + tmp1 += z2; + tmp2 += z2; + tmp3 = z4 + z5; + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 != 0, d7 == 0 */ + z4 = d5 + d1; + z5 = MULTIPLY(z4, FIX(1.175875602)); + + tmp1 = MULTIPLY(d5, - FIX2(0.509795578)); + tmp3 = MULTIPLY(d1, FIX2(0.601344887)); + z1 = MULTIPLY(d1, - FIX(0.899976223)); + z2 = MULTIPLY(d5, - FIX(2.562915447)); + z4 = MULTIPLY(z4, FIX2(0.785694958)); + + tmp0 = z1 + z5; + tmp1 += z4; + tmp2 = z2 + z5; + tmp3 += z4; + } + else + { + /* d1 == 0, d3 == 0, d5 != 0, d7 == 0 */ + tmp0 = MULTIPLY(d5, FIX(1.175875602)); + tmp1 = MULTIPLY(d5, FIX2(0.275899380)); + tmp2 = MULTIPLY(d5, - FIX2(1.387039845)); + tmp3 = MULTIPLY(d5, FIX2(0.785694958)); + } + } + } + else + { + if (d3) + { + if (d1) + { + /* d1 != 0, d3 != 0, d5 == 0, d7 == 0 */ + z5 = d3 + d1; + + tmp2 = MULTIPLY(d3, - FIX(1.451774981)); + tmp3 = MULTIPLY(d1, (FIX(0.211164243) - 1)); + z1 = MULTIPLY(d1, FIX(1.061594337)); + z2 = MULTIPLY(d3, - FIX(2.172734803)); + z4 = MULTIPLY(z5, FIX(0.785694958)); + z5 = MULTIPLY(z5, FIX(1.175875602)); + + tmp0 = z1 - z4; + tmp1 = z2 + z4; + tmp2 += z5; + tmp3 += z5; + } + else + { + /* d1 == 0, d3 != 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d3, - FIX2(0.785694958)); + tmp1 = MULTIPLY(d3, - FIX2(1.387039845)); + tmp2 = MULTIPLY(d3, - FIX2(0.275899379)); + tmp3 = MULTIPLY(d3, FIX(1.175875602)); + } + } + else + { + if (d1) + { + /* d1 != 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = MULTIPLY(d1, FIX2(0.275899379)); + tmp1 = MULTIPLY(d1, FIX2(0.785694958)); + tmp2 = MULTIPLY(d1, FIX(1.175875602)); + tmp3 = MULTIPLY(d1, FIX2(1.387039845)); + } + else + { + /* d1 == 0, d3 == 0, d5 == 0, d7 == 0 */ + tmp0 = tmp1 = tmp2 = tmp3 = 0; + } + } + } + } + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (dctelem_t) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (dctelem_t) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (dctelem_t) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (dctelem_t) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (dctelem_t) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (dctelem_t) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (dctelem_t) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (dctelem_t) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + +static inline void RestoreCPUState( ) +{ + ; +} + +#include "idct_sparse.h" +#include "idct_decl.h" diff --git a/modules/codec/mpeg_video/idct/idct.h b/modules/codec/mpeg_video/idct/idct.h new file mode 100644 index 0000000000..adc995725c --- /dev/null +++ b/modules/codec/mpeg_video/idct/idct.h @@ -0,0 +1,142 @@ +/***************************************************************************** + * idct.h : macros for the inverse discrete cosine transform + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: idct.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Gaël Hendryckx + * Christophe Massiot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define SPARSE_SCALE_FACTOR 8 +#define DCTSIZE 8 /* 8*8 DCT */ + +/***************************************************************************** + * Macros + *****************************************************************************/ + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an s32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS s32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((s32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* + * A 2-D IDCT can be done by 1-D IDCT on each row followed by 1-D IDCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate s32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#define CONST_BITS 8 /* Jimmy chose this constant :) */ + +#ifdef EIGHT_BIT_SAMPLES +#define PASS1_BITS 2 +#else +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +#define ONE ((s32) 1) + +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * IMPORTANT: if your compiler doesn't do this arithmetic at compile time, + * you will pay a significant penalty in run time. In that case, figure + * the correct integer constant values and insert them by hand. + */ + +#define FIX(x) ((s32) ((x) * CONST_SCALE + 0.5)) + +/* When adding two opposite-signed fixes, the 0.5 cancels */ +#define FIX2(x) ((s32) ((x) * CONST_SCALE)) + +/* Descale and correctly round an s32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an s32 variable by an s32 constant to yield an s32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply; + * this provides a useful speedup on many machines. + * There is no way to specify a 16x16->32 multiply in portable C, but + * some C compilers will do the right thing if you provide the correct + * combination of casts. + * NB: for 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#ifdef EIGHT_BIT_SAMPLES +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY(var,const) (((INT16) (var)) * ((s32) (const))) +#endif +#endif + +#ifndef MULTIPLY /* default definition */ +#define MULTIPLY(var,const) ((var) * (const)) +#endif + diff --git a/modules/codec/mpeg_video/idct/idct_decl.h b/modules/codec/mpeg_video/idct/idct_decl.h new file mode 100644 index 0000000000..82a94cad34 --- /dev/null +++ b/modules/codec/mpeg_video/idct/idct_decl.h @@ -0,0 +1,53 @@ +/***************************************************************************** + * idct_decl.h : common declarations, must be included at the very end + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: idct_decl.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Author: Christophe Massiot + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * Final declarations + *****************************************************************************/ +static void IDCTCopy( dctelem_t * p_block, yuv_data_t * p_dest, + int i_stride, void * p_unused, int i_unused ) +{ + IDCT( p_block ); + CopyBlock( p_block, p_dest, i_stride ); +} + +static void IDCTAdd( dctelem_t * p_block, yuv_data_t * p_dest, + int i_stride, void * p_unused, int i_unused ) +{ + IDCT( p_block ); + AddBlock( p_block, p_dest, i_stride ); +} + +static void * IDCTFunctions[] = + { InitIDCT, NormScan, SparseIDCTAdd, SparseIDCTCopy, IDCTAdd, IDCTCopy }; + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + p_this->p_private = IDCTFunctions; + return VLC_SUCCESS; +} + diff --git a/modules/codec/mpeg_video/idct/idct_sparse.h b/modules/codec/mpeg_video/idct/idct_sparse.h new file mode 100644 index 0000000000..1ff2a2439f --- /dev/null +++ b/modules/codec/mpeg_video/idct/idct_sparse.h @@ -0,0 +1,120 @@ +/***************************************************************************** + * idct_sparse.h : Sparse IDCT functions (must be include at the end) + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: idct_sparse.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Author: Gaël Hendryckx + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * InitIDCT : initialize data for SparseIDCT + *****************************************************************************/ +static void InitIDCT ( void ** pp_idct_data ) +{ + int i; + dctelem_t * p_pre; + + *pp_idct_data = malloc( sizeof(dctelem_t) * 64 * 64 ); + p_pre = (dctelem_t *) *pp_idct_data; + memset( p_pre, 0, 64 * 64 * sizeof(dctelem_t) ); + + for( i = 0 ; i < 64 ; i++ ) + { + p_pre[i*64+i] = 1 << SPARSE_SCALE_FACTOR; + IDCT( &p_pre[i*64] ) ; + } + + InitBlock(); + + RestoreCPUState(); +} + +/***************************************************************************** + * SparseIDCT : IDCT function for sparse matrices + *****************************************************************************/ +static inline void SparseIDCT( dctelem_t * p_block, void * p_idct_data, + int i_sparse_pos ) +{ + short int val; + int * dp; + int v; + short int * p_dest; + short int * p_source; + int coeff, rr; + dctelem_t * p_pre = (dctelem_t *) p_idct_data; + + /* If DC Coefficient. */ + if ( i_sparse_pos == 0 ) + { + dp=(int *)p_block; + val=RIGHT_SHIFT((*p_block + 4), 3); + /* Compute int to assign. This speeds things up a bit */ + v = ((val & 0xffff) | (val << 16)); + dp[0] = v; dp[1] = v; dp[2] = v; dp[3] = v; + dp[4] = v; dp[5] = v; dp[6] = v; dp[7] = v; + dp[8] = v; dp[9] = v; dp[10] = v; dp[11] = v; + dp[12] = v; dp[13] = v; dp[14] = v; dp[15] = v; + dp[16] = v; dp[17] = v; dp[18] = v; dp[19] = v; + dp[20] = v; dp[21] = v; dp[22] = v; dp[23] = v; + dp[24] = v; dp[25] = v; dp[26] = v; dp[27] = v; + dp[28] = v; dp[29] = v; dp[30] = v; dp[31] = v; + return; + } + /* Some other coefficient. */ + p_dest = (s16*)p_block; + p_source = (s16*)&p_pre[i_sparse_pos * 64]; + coeff = (int)p_dest[i_sparse_pos]; + for( rr=0 ; rr < 4 ; rr++ ) + { + p_dest[0] = (p_source[0] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[1] = (p_source[1] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[2] = (p_source[2] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[3] = (p_source[3] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[4] = (p_source[4] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[5] = (p_source[5] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[6] = (p_source[6] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[7] = (p_source[7] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[8] = (p_source[8] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[9] = (p_source[9] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[10] = (p_source[10] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[11] = (p_source[11] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[12] = (p_source[12] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[13] = (p_source[13] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[14] = (p_source[14] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest[15] = (p_source[15] * coeff) >> SPARSE_SCALE_FACTOR; + p_dest += 16; + p_source += 16; + } +} + +/***************************************************************************** + * Final declarations + *****************************************************************************/ +static void SparseIDCTCopy( dctelem_t * p_block, yuv_data_t * p_dest, + int i_stride, void * p_idct_data, int i_sparse_pos ) +{ + SparseIDCT( p_block, p_idct_data, i_sparse_pos ); + CopyBlock( p_block, p_dest, i_stride ); +} + +static void SparseIDCTAdd( dctelem_t * p_block, yuv_data_t * p_dest, + int i_stride, void * p_idct_data, int i_sparse_pos ) +{ + SparseIDCT( p_block, p_idct_data, i_sparse_pos ); + AddBlock( p_block, p_dest, i_stride ); +} diff --git a/modules/codec/mpeg_video/idct/idctaltivec.c b/modules/codec/mpeg_video/idct/idctaltivec.c new file mode 100644 index 0000000000..ed49f0de1e --- /dev/null +++ b/modules/codec/mpeg_video/idct/idctaltivec.c @@ -0,0 +1,719 @@ +/***************************************************************************** + * idctaltivec.c : AltiVec IDCT module + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: idctaltivec.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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. + *****************************************************************************/ + +#ifndef __BUILD_ALTIVEC_ASM__ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include + +#include /* malloc(), free() */ +#include +#ifdef HAVE_INTTYPES_H +# include /* int16_t .. */ +#endif + +#include "idct.h" + +static int Open( vlc_object_t *p_this ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("AltiVec IDCT module") ); + set_capability( "idct", 200 ); + add_shortcut( "altivec" ); + add_requirement( ALTIVEC ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * NormScan : This IDCT uses reordered coeffs, so we patch the scan table + *****************************************************************************/ +static void NormScan( u8 ppi_scan[2][64] ) +{ + int i, j; + + for( i = 0; i < 64; i++ ) + { + j = ppi_scan[0][i]; + ppi_scan[0][i] = (j >> 3) | ((j & 7) << 3); + + j = ppi_scan[1][i]; + ppi_scan[1][i] = (j >> 3) | ((j & 7) << 3); + } +} + +/***************************************************************************** + * Placeholders for unused functions + *****************************************************************************/ +static void InitIDCT( void ** pp_idct_data ) +{ +} + +/***************************************************************************** + * IDCT in AltiVec + *****************************************************************************/ + +#ifndef CAN_COMPILE_C_ALTIVEC + +static int16_t constants[5][8] ATTR_ALIGN(16) = { + {23170, 13573, 6518, 21895, -23170, -21895, 32, 31}, + {16384, 22725, 21407, 19266, 16384, 19266, 21407, 22725}, + {22725, 31521, 29692, 26722, 22725, 26722, 29692, 31521}, + {21407, 29692, 27969, 25172, 21407, 25172, 27969, 29692}, + {19266, 26722, 25172, 22654, 19266, 22654, 25172, 26722} +}; + +/* + * The asm code is generated with: + * + * gcc-2.95 -fvec -D__BUILD_ALTIVEC_ASM__ -O9 -fomit-frame-pointer -mregnames -S + * idct_altivec.c + * + * awk '{args=""; len=split ($2, arg, ","); + * for (i=1; i<=len; i++) { a=arg[i]; if (ip_private = IDCTFunctions; + return VLC_SUCCESS; +} + +#endif /* __BUILD_ALTIVEC_ASM__ */ diff --git a/modules/codec/mpeg_video/idct/idctclassic.c b/modules/codec/mpeg_video/idct/idctclassic.c new file mode 100644 index 0000000000..8dac31d01c --- /dev/null +++ b/modules/codec/mpeg_video/idct/idctclassic.c @@ -0,0 +1,281 @@ +/***************************************************************************** + * idctclassic.c : Classic IDCT module + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: idctclassic.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Gaël Hendryckx + * + * 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 +#include + +#include + +#include "idct.h" +#include "block_c.h" + +static int Open( vlc_object_t *p_this ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("classic IDCT module") ); + set_capability( "idct", 100 ); + add_shortcut( "classic" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * NormScan : Unused in this IDCT + *****************************************************************************/ +static void NormScan( u8 ppi_scan[2][64] ) +{ +} + +/***************************************************************************** + * IDCT : IDCT function for normal matrices + *****************************************************************************/ +static inline void IDCT( dctelem_t * p_block ) +{ + s32 tmp0, tmp1, tmp2, tmp3; + s32 tmp10, tmp11, tmp12, tmp13; + s32 z1, z2, z3, z4, z5; + dctelem_t * dataptr; + int rowctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = p_block; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) + { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any row in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * row DCT calculations can be simplified this way. + */ + + if ((dataptr[1] | dataptr[2] | dataptr[3] | dataptr[4] | + dataptr[5] | dataptr[6] | dataptr[7]) == 0) + { + /* AC terms all zero */ + dctelem_t dcval = (dctelem_t) (dataptr[0] << PASS1_BITS); + + dataptr[0] = dcval; + dataptr[1] = dcval; + dataptr[2] = dcval; + dataptr[3] = dcval; + dataptr[4] = dcval; + dataptr[5] = dcval; + dataptr[6] = dcval; + dataptr[7] = dcval; + + dataptr += DCTSIZE; /* advance pointer to next row */ + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (s32) dataptr[2]; + z3 = (s32) dataptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((s32) dataptr[0] + (s32) dataptr[4]) << CONST_BITS; + tmp1 = ((s32) dataptr[0] - (s32) dataptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (s32) dataptr[7]; + tmp1 = (s32) dataptr[5]; + tmp2 = (s32) dataptr[3]; + tmp3 = (s32) dataptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[0] = (dctelem_t) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + dataptr[7] = (dctelem_t) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + dataptr[1] = (dctelem_t) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + dataptr[6] = (dctelem_t) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + dataptr[2] = (dctelem_t) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + dataptr[5] = (dctelem_t) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + dataptr[3] = (dctelem_t) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + dataptr[4] = (dctelem_t) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + dataptr = p_block; + for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) + { + /* Columns of zeroes can be exploited in the same way as we did with rows. + * However, the row calculation has created many nonzero AC terms, so the + * simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_COLUMN_TEST /* Adds a test but avoids calculus */ + if ((dataptr[DCTSIZE*1] | dataptr[DCTSIZE*2] | dataptr[DCTSIZE*3] | + dataptr[DCTSIZE*4] | dataptr[DCTSIZE*5] | dataptr[DCTSIZE*6] | + dataptr[DCTSIZE*7]) == 0) + { + /* AC terms all zero */ + dctelem_t dcval = (dctelem_t) DESCALE((s32) dataptr[0], PASS1_BITS+3); + + dataptr[DCTSIZE*0] = dcval; + dataptr[DCTSIZE*1] = dcval; + dataptr[DCTSIZE*2] = dcval; + dataptr[DCTSIZE*3] = dcval; + dataptr[DCTSIZE*4] = dcval; + dataptr[DCTSIZE*5] = dcval; + dataptr[DCTSIZE*6] = dcval; + dataptr[DCTSIZE*7] = dcval; + + dataptr++; /* advance pointer to next column */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (s32) dataptr[DCTSIZE*2]; + z3 = (s32) dataptr[DCTSIZE*6]; + + z1 = MULTIPLY(z2 + z3, FIX(0.541196100)); + tmp2 = z1 + MULTIPLY(z3, - FIX(1.847759065)); + tmp3 = z1 + MULTIPLY(z2, FIX(0.765366865)); + + tmp0 = ((s32) dataptr[DCTSIZE*0] + (s32) dataptr[DCTSIZE*4]) << CONST_BITS; + tmp1 = ((s32) dataptr[DCTSIZE*0] - (s32) dataptr[DCTSIZE*4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (s32) dataptr[DCTSIZE*7]; + tmp1 = (s32) dataptr[DCTSIZE*5]; + tmp2 = (s32) dataptr[DCTSIZE*3]; + tmp3 = (s32) dataptr[DCTSIZE*1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX(1.175875602)); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX(0.298631336)); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX(2.053119869)); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX(3.072711026)); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX(1.501321110)); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX(0.899976223)); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX(2.562915447)); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX(1.961570560)); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX(0.390180644)); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + dataptr[DCTSIZE*0] = (dctelem_t) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*7] = (dctelem_t) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*1] = (dctelem_t) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*6] = (dctelem_t) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*2] = (dctelem_t) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*5] = (dctelem_t) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*3] = (dctelem_t) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3); + dataptr[DCTSIZE*4] = (dctelem_t) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3); + + dataptr++; /* advance pointer to next column */ + } +} + +static inline void RestoreCPUState( ) +{ + ; +} + +#include "idct_sparse.h" +#include "idct_decl.h" diff --git a/modules/codec/mpeg_video/idct/idctmmx.c b/modules/codec/mpeg_video/idct/idctmmx.c new file mode 100644 index 0000000000..d5b4047196 --- /dev/null +++ b/modules/codec/mpeg_video/idct/idctmmx.c @@ -0,0 +1,406 @@ +/***************************************************************************** + * idctmmx.c : MMX IDCT module + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: idctmmx.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Aaron Holtzman + * Michel Lespinasse + * Peter Gubanov + * (from the LiViD project) + * Christophe Massiot + * + * 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 +#include + +#include + +#include "mmx.h" + +#include "idct.h" +#include "block_mmx.h" + +static int Open( vlc_object_t *p_this ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MMX IDCT module") ); + set_capability( "idct", 150 ); + add_shortcut( "mmx" ); + add_requirement( MMX ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * NormScan : This IDCT uses reordered coeffs, so we patch the scan table + *****************************************************************************/ +static void NormScan( u8 ppi_scan[2][64] ) +{ + int i, j; + + for( i = 0; i < 64; i++ ) + { + j = ppi_scan[0][i]; + ppi_scan[0][i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + + j = ppi_scan[1][i]; + ppi_scan[1][i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + } +} + +/***************************************************************************** + * IDCT : + *****************************************************************************/ +#define ROW_SHIFT 11 +#define COL_SHIFT 6 + +#define round(bias) ((int)(((bias)+0.5) * (1< + * Michel Lespinasse + * Peter Gubanov + * (from the LiViD project) + * Christophe Massiot + * + * 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 +#include + +#include + +#include "mmx.h" + +#include "idct.h" +#include "block_mmx.h" + +static int Open( vlc_object_t *p_this ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MMX EXT IDCT module") ); + set_capability( "idct", 200 ); + add_shortcut( "mmxext" ); + add_requirement( MMXEXT ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * NormScan : This IDCT uses reordered coeffs, so we patch the scan table + *****************************************************************************/ +static void NormScan( u8 ppi_scan[2][64] ) +{ + int i, j; + + for( i = 0; i < 64; i++ ) + { + j = ppi_scan[0][i]; + ppi_scan[0][i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + + j = ppi_scan[1][i]; + ppi_scan[1][i] = (j & 0x38) | ((j & 6) >> 1) | ((j & 1) << 2); + } +} + +/***************************************************************************** + * IDCT : + *****************************************************************************/ +#define ROW_SHIFT 11 +#define COL_SHIFT 6 + +#define round(bias) ((int)(((bias)+0.5) * (1< + * Michel Lespinasse + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * Local prototype + *****************************************************************************/ +static int Open ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("motion compensation module") ); + set_capability( "motion compensation", 50 ); + add_shortcut( "c" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Simple motion compensation in C + *****************************************************************************/ + +#define avg2(a,b) ((a+b+1)>>1) +#define avg4(a,b,c,d) ((a+b+c+d+2)>>2) + +#define predict_o(i) (ref[i]) +#define predict_x(i) (avg2 (ref[i], ref[i+1])) +#define predict_y(i) (avg2 (ref[i], (ref+stride)[i])) +#define predict_xy(i) (avg4 (ref[i], ref[i+1], (ref+stride)[i], (ref+stride)[i+1])) + +#define put(predictor,i) dest[i] = predictor (i) +#define avg(predictor,i) dest[i] = avg2 (predictor (i), dest[i]) + +// mc function template + +#define MC_FUNC(op,xy) \ +static void MC_##op##_##xy##16_c (yuv_data_t * dest, yuv_data_t * ref, \ + int stride, int height) \ +{ \ + do { \ + op (predict_##xy, 0); \ + op (predict_##xy, 1); \ + op (predict_##xy, 2); \ + op (predict_##xy, 3); \ + op (predict_##xy, 4); \ + op (predict_##xy, 5); \ + op (predict_##xy, 6); \ + op (predict_##xy, 7); \ + op (predict_##xy, 8); \ + op (predict_##xy, 9); \ + op (predict_##xy, 10); \ + op (predict_##xy, 11); \ + op (predict_##xy, 12); \ + op (predict_##xy, 13); \ + op (predict_##xy, 14); \ + op (predict_##xy, 15); \ + ref += stride; \ + dest += stride; \ + } while (--height); \ +} \ +static void MC_##op##_##xy##8_c (yuv_data_t * dest, yuv_data_t * ref, \ + int stride, int height) \ +{ \ + do { \ + op (predict_##xy, 0); \ + op (predict_##xy, 1); \ + op (predict_##xy, 2); \ + op (predict_##xy, 3); \ + op (predict_##xy, 4); \ + op (predict_##xy, 5); \ + op (predict_##xy, 6); \ + op (predict_##xy, 7); \ + ref += stride; \ + dest += stride; \ + } while (--height); \ +} + +// definitions of the actual mc functions + +MC_FUNC (put,o) +MC_FUNC (avg,o) +MC_FUNC (put,x) +MC_FUNC (avg,x) +MC_FUNC (put,y) +MC_FUNC (avg,y) +MC_FUNC (put,xy) +MC_FUNC (avg,xy) + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) = +{ + /* Copying functions */ + { + /* Width == 16 */ + { MC_put_o16_c, MC_put_x16_c, MC_put_y16_c, MC_put_xy16_c }, + /* Width == 8 */ + { MC_put_o8_c, MC_put_x8_c, MC_put_y8_c, MC_put_xy8_c } + }, + /* Averaging functions */ + { + /* Width == 16 */ + { MC_avg_o16_c, MC_avg_x16_c, MC_avg_y16_c, MC_avg_xy16_c }, + /* Width == 8 */ + { MC_avg_o8_c, MC_avg_x8_c, MC_avg_y8_c, MC_avg_xy8_c } + } +}; + +static int Open ( vlc_object_t *p_this ) +{ + p_this->p_private = ppppf_motion; + return VLC_SUCCESS; +} + diff --git a/modules/codec/mpeg_video/motion/motion3dnow.c b/modules/codec/mpeg_video/motion/motion3dnow.c new file mode 100644 index 0000000000..c83b4a88ec --- /dev/null +++ b/modules/codec/mpeg_video/motion/motion3dnow.c @@ -0,0 +1,576 @@ +/***************************************************************************** + * motion3dnow.c : 3D Now! motion compensation module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: motion3dnow.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Aaron Holtzman + * Michel Lespinasse + * + * 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 /* malloc(), free() */ +#include + +#include + +#include "mmx.h" + +/***************************************************************************** + * Local prototype. + *****************************************************************************/ +static int Open ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("3D Now! motion compensation module") ); + set_capability( "motion compensation", 150 ); + add_requirement( 3DNOW ); + add_shortcut( "3dn" ); + add_shortcut( "3dnow" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Motion compensation in 3D Now! (OK I know this does MMXEXT too and it's ugly) + *****************************************************************************/ + +#define CPU_MMXEXT 0 +#define CPU_3DNOW 1 + + +//CPU_MMXEXT/CPU_3DNOW adaptation layer + +#define pavg_r2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_r2r (src, dest); \ + else \ + pavgusb_r2r (src, dest); \ +} while (0) + +#define pavg_m2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_m2r (src, dest); \ + else \ + pavgusb_m2r (src, dest); \ +} while (0) + + +//CPU_MMXEXT code + + +static inline void MC_put1_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_r2m (mm0, *dest); + ref += stride; + dest += stride; + } while (--height); +} + +static inline void MC_put1_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_put2_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_put2_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static mmx_t mask_one = {0x0101010101010101LL}; + +static inline void MC_put4_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + movq_m2r (*ref, mm0); + movq_m2r (*(ref+1), mm1); + movq_r2r (mm0, mm7); + pxor_r2r (mm1, mm7); + pavg_r2r (mm1, mm0); + ref += stride; + + do { + movq_m2r (*ref, mm2); + movq_r2r (mm0, mm5); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm2, mm6); + + pxor_r2r (mm3, mm6); + pavg_r2r (mm3, mm2); + + por_r2r (mm6, mm7); + pxor_r2r (mm2, mm5); + + pand_r2r (mm5, mm7); + pavg_r2r (mm2, mm0); + + pand_m2r (mask_one, mm7); + + psubusb_r2r (mm7, mm0); + + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + + movq_r2r (mm6, mm7); // unroll ! + movq_r2r (mm2, mm0); // unroll ! + } while (--height); +} + +static inline void MC_put4_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*(dest+8), mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static void MC_avg_16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_x8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_y16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_y8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_xy16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_xy8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + + +static void MC_avg_16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_avg_8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_x8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_y16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_avg_y8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_avg_xy16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_avg_xy8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_8 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_xy16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_xy8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_8 (height, dest, ref, stride, CPU_3DNOW); +} + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) = +{ + /* Copying functions */ + { + /* Width == 16 */ + { MC_put_16_3dnow, MC_put_x16_3dnow, MC_put_y16_3dnow, MC_put_xy16_3dnow }, + /* Width == 8 */ + { MC_put_8_3dnow, MC_put_x8_3dnow, MC_put_y8_3dnow, MC_put_xy8_3dnow } + }, + /* Averaging functions */ + { + /* Width == 16 */ + { MC_avg_16_3dnow, MC_avg_x16_3dnow, MC_avg_y16_3dnow, MC_avg_xy16_3dnow }, + /* Width == 8 */ + { MC_avg_8_3dnow, MC_avg_x8_3dnow, MC_avg_y8_3dnow, MC_avg_xy8_3dnow } + } +}; + +static int Open ( vlc_object_t *p_this ) +{ + p_this->p_private = ppppf_motion; + return VLC_SUCCESS; +} + diff --git a/modules/codec/mpeg_video/motion/motionaltivec.c b/modules/codec/mpeg_video/motion/motionaltivec.c new file mode 100644 index 0000000000..1ea055e51d --- /dev/null +++ b/modules/codec/mpeg_video/motion/motionaltivec.c @@ -0,0 +1,2074 @@ +/***************************************************************************** + * motionaltivec.c : AltiVec motion compensation module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: motionaltivec.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Michel Lespinasse + * Paul Mackerras + * + * 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. + *****************************************************************************/ + +#ifndef __BUILD_ALTIVEC_ASM__ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include + +#include /* malloc(), free() */ +#include +#ifdef HAVE_INTTYPES_H +# include /* int16_t .. */ +#endif + +/***************************************************************************** + * Local prototype + *****************************************************************************/ +static int Open ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("AltiVec motion compensation module") ); + set_capability( "motion compensation", 150 ); + add_requirement( ALTIVEC ); + add_shortcut( "altivec" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Motion compensation in AltiVec + *****************************************************************************/ + +#ifndef CAN_COMPILE_C_ALTIVEC + +/* + * The asm code is generated with: + * + * gcc-2.95 -fvec -D__BUILD_ALTIVEC_ASM__ -O9 -fomit-frame-pointer -mregnames -S + * motion_comp_altivec.c + * + * sed 's/.L/._L/g' motion_comp_altivec.s | + * awk '{args=""; len=split ($2, arg, ","); + * for (i=1; i<=len; i++) { a=arg[i]; if (i> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + tmp = vec_perm (ref0, ref1, perm); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + vec_st (tmp, 0, dest); + tmp = vec_perm (ref0, ref1, perm); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp = vec_perm (ref0, ref1, perm); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + vec_st (tmp, 0, dest); + tmp = vec_perm (ref0, ref1, perm); + vec_st (tmp, stride, dest); +} + +void MC_put_o_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0, perm1, tmp0, tmp1, ref0, ref1; + + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0 = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1 = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_perm (ref0, ref1, perm1); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_perm (ref0, ref1, perm1); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); +} + +void MC_put_x_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t permA, permB, ref0, ref1, tmp; + + permA = vec_lvsl (0, ref); + permB = vec_add (permA, vec_splat_u8 (1)); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + tmp = vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + vec_st (tmp, 0, dest); + tmp = vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp = vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + vec_st (tmp, 0, dest); + tmp = vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB)); + vec_st (tmp, stride, dest); +} + +void MC_put_x_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0A, perm0B, perm1A, perm1B, ones, tmp0, tmp1, ref0, ref1; + + ones = vec_splat_u8 (1); + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0A = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + perm0B = vec_add (perm0A, ones); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1A = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + perm1B = vec_add (perm1A, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + tmp0 = vec_avg (vec_perm (ref0, ref1, perm0A), + vec_perm (ref0, ref1, perm0B)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (vec_perm (ref0, ref1, perm1A), + vec_perm (ref0, ref1, perm1B)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_avg (vec_perm (ref0, ref1, perm0A), + vec_perm (ref0, ref1, perm0B)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (vec_perm (ref0, ref1, perm1A), + vec_perm (ref0, ref1, perm1B)); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); +} + +void MC_put_y_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm, ref0, ref1, tmp0, tmp1, tmp; + + perm = vec_lvsl (0, ref); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + tmp0 = vec_perm (ref0, ref1, perm); + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + tmp1 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (tmp0, tmp1); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + vec_st (tmp, 0, dest); + tmp0 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (tmp0, tmp1); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp1 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (tmp0, tmp1); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + vec_st (tmp, 0, dest); + tmp0 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (tmp0, tmp1); + vec_st (tmp, stride, dest); +} + +void MC_put_y_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0, perm1, tmp0, tmp1, tmp, ref0, ref1; + + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0 = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1 = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + tmp1 = vec_perm (ref0, ref1, perm1); + tmp = vec_avg (tmp0, tmp1); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + tmp = vec_avg (tmp0, tmp1); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_perm (ref0, ref1, perm1); + tmp = vec_avg (tmp0, tmp1); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + tmp = vec_avg (tmp0, tmp1); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); +} + +void MC_put_xy_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t permA, permB, ref0, ref1, A, B, avg0, avg1, xor0, xor1, tmp; + vector_u8_t ones; + + ones = vec_splat_u8 (1); + permA = vec_lvsl (0, ref); + permB = vec_add (permA, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + vec_st (tmp, 0, dest); + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + vec_st (tmp, stride, dest); + dest += 2*stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + vec_st (tmp, 0, dest); + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + vec_st (tmp, stride, dest); +} + +void MC_put_xy_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0A, perm0B, perm1A, perm1B, ref0, ref1, A, B; + vector_u8_t avg0, avg1, xor0, xor1, tmp, ones; + + ones = vec_splat_u8 (1); + perm0A = vec_lvsl (0, ref); + perm0A = vec_mergeh (perm0A, perm0A); + perm0A = vec_pack ((vector_u16_t)perm0A, (vector_u16_t)perm0A); + perm0B = vec_add (perm0A, ones); + perm1A = vec_lvsl (stride, ref); + perm1A = vec_mergeh (perm1A, perm1A); + perm1A = vec_pack ((vector_u16_t)perm1A, (vector_u16_t)perm1A); + perm1B = vec_add (perm1A, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + A = vec_perm (ref0, ref1, perm1A); + B = vec_perm (ref0, ref1, perm1B); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm1A); + B = vec_perm (ref0, ref1, perm1B); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1))); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); +} + +#if 0 +void MC_put_xy_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t permA, permB, ref0, ref1, A, B, C, D, tmp, zero, ones; + vector_u16_t splat2, temp; + + ones = vec_splat_u8 (1); + permA = vec_lvsl (0, ref); + permB = vec_add (permA, ones); + + zero = vec_splat_u8 (0); + splat2 = vec_splat_u16 (2); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + C = vec_perm (ref0, ref1, permA); + D = vec_perm (ref0, ref1, permB); + + temp = vec_add (vec_add ((vector_u16_t)vec_mergeh (zero, A), + (vector_u16_t)vec_mergeh (zero, B)), + vec_add ((vector_u16_t)vec_mergeh (zero, C), + (vector_u16_t)vec_mergeh (zero, D))); + temp = vec_sr (vec_add (temp, splat2), splat2); + tmp = vec_pack (temp, temp); + + vec_st (tmp, 0, dest); + dest += stride; + tmp = vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB)); + } while (--height); +} +#endif + +void MC_avg_o_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm, ref0, ref1, tmp, prev; + + perm = vec_lvsl (0, ref); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (0, dest); + tmp = vec_avg (prev, vec_perm (ref0, ref1, perm)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp = vec_avg (prev, vec_perm (ref0, ref1, perm)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (2*stride, dest); + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp = vec_avg (prev, vec_perm (ref0, ref1, perm)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp = vec_avg (prev, vec_perm (ref0, ref1, perm)); + vec_st (tmp, stride, dest); +} + +void MC_avg_o_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0, perm1, tmp0, tmp1, ref0, ref1, prev; + + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0 = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1 = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (0, dest); + tmp0 = vec_avg (prev, vec_perm (ref0, ref1, perm0)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (prev, vec_perm (ref0, ref1, perm1)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_avg (prev, vec_perm (ref0, ref1, perm0)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (prev, vec_perm (ref0, ref1, perm1)); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); +} + +void MC_avg_x_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t permA, permB, ref0, ref1, tmp, prev; + + permA = vec_lvsl (0, ref); + permB = vec_add (permA, vec_splat_u8 (1)); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + prev = vec_ld (0, dest); + ref += stride; + tmp = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + prev = vec_ld (2*stride, dest); + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, permA), + vec_perm (ref0, ref1, permB))); + vec_st (tmp, stride, dest); +} + +void MC_avg_x_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0A, perm0B, perm1A, perm1B, ones, tmp0, tmp1, ref0, ref1; + vector_u8_t prev; + + ones = vec_splat_u8 (1); + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0A = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + perm0B = vec_add (perm0A, ones); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1A = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + perm1B = vec_add (perm1A, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + prev = vec_ld (0, dest); + ref += stride; + tmp0 = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, perm0A), + vec_perm (ref0, ref1, perm0B))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, perm1A), + vec_perm (ref0, ref1, perm1B))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, perm0A), + vec_perm (ref0, ref1, perm0B))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp0, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp0, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_avg (prev, vec_avg (vec_perm (ref0, ref1, perm1A), + vec_perm (ref0, ref1, perm1B))); + vec_ste ((vector_u32_t)tmp1, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp1, 4, (unsigned int *)dest); +} + +void MC_avg_y_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm, ref0, ref1, tmp0, tmp1, tmp, prev; + + perm = vec_lvsl (0, ref); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + tmp0 = vec_perm (ref0, ref1, perm); + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (0, dest); + tmp1 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp0 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + ref += stride; + prev = vec_ld (2*stride, dest); + vec_st (tmp, stride, dest); + dest += 2*stride; + tmp1 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (15, ref); + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + tmp0 = vec_perm (ref0, ref1, perm); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + vec_st (tmp, stride, dest); +} + +void MC_avg_y_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0, perm1, tmp0, tmp1, tmp, ref0, ref1, prev; + + tmp0 = vec_lvsl (0, ref); + tmp0 = vec_mergeh (tmp0, tmp0); + perm0 = vec_pack ((vector_u16_t)tmp0, (vector_u16_t)tmp0); + tmp1 = vec_lvsl (stride, ref); + tmp1 = vec_mergeh (tmp1, tmp1); + perm1 = vec_pack ((vector_u16_t)tmp1, (vector_u16_t)tmp1); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (0, dest); + tmp1 = vec_perm (ref0, ref1, perm1); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp1 = vec_perm (ref0, ref1, perm1); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (7, ref); + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + tmp0 = vec_perm (ref0, ref1, perm0); + tmp = vec_avg (prev, vec_avg (tmp0, tmp1)); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); +} + +void MC_avg_xy_16_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t permA, permB, ref0, ref1, A, B, avg0, avg1, xor0, xor1, tmp; + vector_u8_t ones, prev; + + ones = vec_splat_u8 (1); + permA = vec_lvsl (0, ref); + permB = vec_add (permA, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + prev = vec_ld (0, dest); + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_avg (prev, vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_avg (prev, + vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + ref += stride; + prev = vec_ld (2*stride, dest); + vec_st (tmp, stride, dest); + dest += 2*stride; + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_avg (prev, + vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (16, ref); + prev = vec_ld (stride, dest); + vec_st (tmp, 0, dest); + A = vec_perm (ref0, ref1, permA); + B = vec_perm (ref0, ref1, permB); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_avg (prev, vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + vec_st (tmp, stride, dest); +} + +void MC_avg_xy_8_altivec (unsigned char * dest, unsigned char * ref, + int stride, int height) +{ + vector_u8_t perm0A, perm0B, perm1A, perm1B, ref0, ref1, A, B; + vector_u8_t avg0, avg1, xor0, xor1, tmp, ones, prev; + + ones = vec_splat_u8 (1); + perm0A = vec_lvsl (0, ref); + perm0A = vec_mergeh (perm0A, perm0A); + perm0A = vec_pack ((vector_u16_t)perm0A, (vector_u16_t)perm0A); + perm0B = vec_add (perm0A, ones); + perm1A = vec_lvsl (stride, ref); + perm1A = vec_mergeh (perm1A, perm1A); + perm1A = vec_pack ((vector_u16_t)perm1A, (vector_u16_t)perm1A); + perm1B = vec_add (perm1A, ones); + + height = (height >> 1) - 1; + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + prev = vec_ld (0, dest); + A = vec_perm (ref0, ref1, perm1A); + B = vec_perm (ref0, ref1, perm1B); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_avg (prev, vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + + do { + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_avg (prev, + vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + ref += stride; + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm1A); + B = vec_perm (ref0, ref1, perm1B); + avg1 = vec_avg (A, B); + xor1 = vec_xor (A, B); + tmp = vec_avg (prev, + vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + } while (--height); + + ref0 = vec_ld (0, ref); + ref1 = vec_ld (8, ref); + prev = vec_ld (stride, dest); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); + dest += stride; + A = vec_perm (ref0, ref1, perm0A); + B = vec_perm (ref0, ref1, perm0B); + avg0 = vec_avg (A, B); + xor0 = vec_xor (A, B); + tmp = vec_avg (prev, vec_sub (vec_avg (avg0, avg1), + vec_and (vec_and (ones, vec_or (xor0, xor1)), + vec_xor (avg0, avg1)))); + vec_ste ((vector_u32_t)tmp, 0, (unsigned int *)dest); + vec_ste ((vector_u32_t)tmp, 4, (unsigned int *)dest); +} + +#endif /* CAN_COMPILE_C_ALTIVEC || __BUILD_ALTIVEC_ASM__ */ +#ifndef __BUILD_ALTIVEC_ASM__ + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) = +{ + /* Copying functions */ + { + /* Width == 16 */ + { MC_put_o_16_altivec, MC_put_x_16_altivec, MC_put_y_16_altivec, MC_put_xy_16_altivec }, + /* Width == 8 */ + { MC_put_o_8_altivec, MC_put_x_8_altivec, MC_put_y_8_altivec, MC_put_xy_8_altivec } + }, + /* Averaging functions */ + { + /* Width == 16 */ + { MC_avg_o_16_altivec, MC_avg_x_16_altivec, MC_avg_y_16_altivec, MC_avg_xy_16_altivec }, + /* Width == 8 */ + { MC_avg_o_8_altivec, MC_avg_x_8_altivec, MC_avg_y_8_altivec, MC_avg_xy_8_altivec } + } +}; + +static int Open ( vlc_object_t *p_this ) +{ + p_this->p_private = ppppf_motion; + return VLC_SUCCESS; +} + +#endif /* __BUILD_ALTIVEC_ASM__ */ diff --git a/modules/codec/mpeg_video/motion/motionmmx.c b/modules/codec/mpeg_video/motion/motionmmx.c new file mode 100644 index 0000000000..097fa3e61b --- /dev/null +++ b/modules/codec/mpeg_video/motion/motionmmx.c @@ -0,0 +1,660 @@ +/***************************************************************************** + * motionmmx.c : MMX motion compensation module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: motionmmx.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Aaron Holtzman + * Michel Lespinasse + * Vladimir Chernyshov + * + * 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 /* malloc(), free() */ +#include + +#include + +#include "mmx.h" + +/***************************************************************************** + * Local prototype. + *****************************************************************************/ +static int Open ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MMX motion compensation module") ); + set_capability( "motion compensation", 150 ); + add_requirement( MMX ); + add_shortcut( "mmx" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Motion compensation in MMX + *****************************************************************************/ + +// some rounding constants +mmx_t round1 = {0x0001000100010001LL}; +mmx_t round4 = {0x0002000200020002LL}; + +/* + * This code should probably be compiled with loop unrolling + * (ie, -funroll-loops in gcc)becuase some of the loops + * use a small static number of iterations. This was written + * with the assumption the compiler knows best about when + * unrolling will help + */ + +static inline void mmx_zero_reg () +{ + // load 0 into mm0 + pxor_r2r (mm0, mm0); +} + +static inline void mmx_average_2_U8 (yuv_data_t * dest, + yuv_data_t * src1, yuv_data_t * src2) +{ + // + // *dest = (*src1 + *src2 + 1)/ 2; + // + static mmx_t mask1 = {0x0101010101010101LL}; + static mmx_t mask7f = {0x7f7f7f7f7f7f7f7fLL}; + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); + psrlq_i2r (1, mm1); + pand_m2r (mask7f, mm1); + + movq_m2r (*src2, mm3); // load 8 src2 bytes + por_r2r (mm3, mm2); + psrlq_i2r (1, mm3); + pand_m2r (mask7f, mm3); + + paddb_r2r (mm1, mm3); + pand_m2r (mask1, mm2); + paddb_r2r (mm3, mm2); + movq_r2m (mm2, *dest); // store result in dest +} + +static inline void mmx_interp_average_2_U8 (yuv_data_t * dest, + yuv_data_t * src1, yuv_data_t * src2) +{ + // + // *dest = (*dest + (*src1 + *src2 + 1)/ 2 + 1)/ 2; + // + + movq_m2r (*dest, mm1); // load 8 dest bytes + movq_r2r (mm1, mm2); // copy 8 dest bytes + + movq_m2r (*src1, mm3); // load 8 src1 bytes + movq_r2r (mm3, mm4); // copy 8 src1 bytes + + movq_m2r (*src2, mm5); // load 8 src2 bytes + movq_r2r (mm5, mm6); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low dest bytes + punpckhbw_r2r (mm0, mm2); // unpack high dest bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src1 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src2 bytes + + paddw_r2r (mm5, mm3); // add lows + paddw_m2r (round1, mm3); + psraw_i2r (1, mm3); // /2 + + paddw_r2r (mm6, mm4); // add highs + paddw_m2r (round1, mm4); + psraw_i2r (1, mm4); // /2 + + paddw_r2r (mm3, mm1); // add lows + paddw_m2r (round1, mm1); + psraw_i2r (1, mm1); // /2 + + paddw_r2r (mm4, mm2); // add highs + paddw_m2r (round1, mm2); + psraw_i2r (1, mm2); // /2 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1, *dest); // store result in dest +} + +static inline void mmx_average_4_U8 (yuv_data_t * dest, + yuv_data_t * src1, yuv_data_t * src2, + yuv_data_t * src3, yuv_data_t * src4) +{ + // + // *dest = (*src1 + *src2 + *src3 + *src4 + 2)/ 4; + // + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); // copy 8 src1 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm2); // unpack high src1 bytes + + movq_m2r (*src2, mm3); // load 8 src2 bytes + movq_r2r (mm3, mm4); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src2 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + // now have partials in mm1 and mm2 + + movq_m2r (*src3, mm3); // load 8 src3 bytes + movq_r2r (mm3, mm4); // copy 8 src3 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src3 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src3 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + movq_m2r (*src4, mm5); // load 8 src4 bytes + movq_r2r (mm5, mm6); // copy 8 src4 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src4 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src4 bytes + + paddw_r2r (mm5, mm1); // add lows + paddw_r2r (mm6, mm2); // add highs + + // now have subtotal in mm1 and mm2 + + paddw_m2r (round4, mm1); + psraw_i2r (2, mm1); // /4 + paddw_m2r (round4, mm2); + psraw_i2r (2, mm2); // /4 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1, *dest); // store result in dest +} + +static inline void mmx_interp_average_4_U8 (yuv_data_t * dest, + yuv_data_t * src1, yuv_data_t * src2, + yuv_data_t * src3, yuv_data_t * src4) +{ + // + // *dest = (*dest + (*src1 + *src2 + *src3 + *src4 + 2)/ 4 + 1)/ 2; + // + + movq_m2r (*src1, mm1); // load 8 src1 bytes + movq_r2r (mm1, mm2); // copy 8 src1 bytes + + punpcklbw_r2r (mm0, mm1); // unpack low src1 bytes + punpckhbw_r2r (mm0, mm2); // unpack high src1 bytes + + movq_m2r (*src2, mm3); // load 8 src2 bytes + movq_r2r (mm3, mm4); // copy 8 src2 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src2 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src2 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + // now have partials in mm1 and mm2 + + movq_m2r (*src3, mm3); // load 8 src3 bytes + movq_r2r (mm3, mm4); // copy 8 src3 bytes + + punpcklbw_r2r (mm0, mm3); // unpack low src3 bytes + punpckhbw_r2r (mm0, mm4); // unpack high src3 bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + movq_m2r (*src4, mm5); // load 8 src4 bytes + movq_r2r (mm5, mm6); // copy 8 src4 bytes + + punpcklbw_r2r (mm0, mm5); // unpack low src4 bytes + punpckhbw_r2r (mm0, mm6); // unpack high src4 bytes + + paddw_r2r (mm5, mm1); // add lows + paddw_r2r (mm6, mm2); // add highs + + paddw_m2r (round4, mm1); + psraw_i2r (2, mm1); // /4 + paddw_m2r (round4, mm2); + psraw_i2r (2, mm2); // /4 + + // now have subtotal/4 in mm1 and mm2 + + movq_m2r (*dest, mm3); // load 8 dest bytes + movq_r2r (mm3, mm4); // copy 8 dest bytes + + punpcklbw_r2r (mm0, mm3); // unpack low dest bytes + punpckhbw_r2r (mm0, mm4); // unpack high dest bytes + + paddw_r2r (mm3, mm1); // add lows + paddw_r2r (mm4, mm2); // add highs + + paddw_m2r (round1, mm1); + psraw_i2r (1, mm1); // /2 + paddw_m2r (round1, mm2); + psraw_i2r (1, mm2); // /2 + + // now have end value in mm1 and mm2 + + packuswb_r2r (mm2, mm1); // pack (w/ saturation) + movq_r2m (mm1,*dest); // store result in dest +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, dest, ref); + + if (width == 16) + mmx_average_2_U8 (dest+8, dest+8, ref+8); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_avg_16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + movq_m2r (* ref, mm1); // load 8 ref bytes + movq_r2m (mm1,* dest); // store 8 bytes at curr + + if (width == 16) + { + movq_m2r (* (ref+8), mm1); // load 8 ref bytes + movq_r2m (mm1,* (dest+8)); // store 8 bytes at curr + } + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_put_16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_mmx (16, height, dest, ref, stride); +} + +static void MC_put_8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +// Half pixel interpolation in the x direction +static inline void MC_avg_x_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_interp_average_2_U8 (dest, ref, ref+1); + + if (width == 16) + mmx_interp_average_2_U8 (dest+8, ref+8, ref+9); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_avg_x16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_x_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_x8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_x_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_x_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, ref, ref+1); + + if (width == 16) + mmx_average_2_U8 (dest+8, ref+8, ref+9); + + dest += stride; + ref += stride; + } while (--height); +} + +static void MC_put_x16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_x_mmx (16, height, dest, ref, stride); +} + +static void MC_put_x8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_x_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_xy_8wide_mmx (int height, yuv_data_t * dest, + yuv_data_t * ref, int stride) +{ + pxor_r2r (mm0, mm0); + movq_m2r (round4, mm7); + + movq_m2r (*ref, mm1); // calculate first row ref[0] + ref[1] + movq_r2r (mm1, mm2); + + punpcklbw_r2r (mm0, mm1); + punpckhbw_r2r (mm0, mm2); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm3, mm4); + + punpcklbw_r2r (mm0, mm3); + punpckhbw_r2r (mm0, mm4); + + paddw_r2r (mm3, mm1); + paddw_r2r (mm4, mm2); + + ref += stride; + + do { + + movq_m2r (*ref, mm5); // calculate next row ref[0] + ref[1] + movq_r2r (mm5, mm6); + + punpcklbw_r2r (mm0, mm5); + punpckhbw_r2r (mm0, mm6); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm3, mm4); + + punpcklbw_r2r (mm0, mm3); + punpckhbw_r2r (mm0, mm4); + + paddw_r2r (mm3, mm5); + paddw_r2r (mm4, mm6); + + movq_r2r (mm7, mm3); // calculate round4 + previous row + current row + movq_r2r (mm7, mm4); + + paddw_r2r (mm1, mm3); + paddw_r2r (mm2, mm4); + + paddw_r2r (mm5, mm3); + paddw_r2r (mm6, mm4); + + psraw_i2r (2, mm3); // /4 + psraw_i2r (2, mm4); // /4 + + movq_m2r (*dest, mm1); // calculate (subtotal + dest[0] + round1) / 2 + movq_r2r (mm1, mm2); + + punpcklbw_r2r (mm0, mm1); + punpckhbw_r2r (mm0, mm2); + + paddw_r2r (mm1, mm3); + paddw_r2r (mm2, mm4); + + paddw_m2r (round1, mm3); + paddw_m2r (round1, mm4); + + psraw_i2r (1, mm3); // /2 + psraw_i2r (1, mm4); // /2 + + packuswb_r2r (mm4, mm3); // pack (w/ saturation) + movq_r2m (mm3, *dest); // store result in dest + + movq_r2r (mm5, mm1); // remember current row for the next pass + movq_r2r (mm6, mm2); + + ref += stride; + dest += stride; + + } while (--height); +} + +static void MC_avg_xy16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_xy_8wide_mmx(height, dest, ref, stride); + MC_avg_xy_8wide_mmx(height, dest+8, ref+8, stride); +} + +static void MC_avg_xy8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_xy_8wide_mmx(height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_xy_8wide_mmx (int height, yuv_data_t * dest, + yuv_data_t * ref, int stride) +{ + pxor_r2r (mm0, mm0); + movq_m2r (round4, mm7); + + movq_m2r (*ref, mm1); // calculate first row ref[0] + ref[1] + movq_r2r (mm1, mm2); + + punpcklbw_r2r (mm0, mm1); + punpckhbw_r2r (mm0, mm2); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm3, mm4); + + punpcklbw_r2r (mm0, mm3); + punpckhbw_r2r (mm0, mm4); + + paddw_r2r (mm3, mm1); + paddw_r2r (mm4, mm2); + + ref += stride; + + do { + + movq_m2r (*ref, mm5); // calculate next row ref[0] + ref[1] + movq_r2r (mm5, mm6); + + punpcklbw_r2r (mm0, mm5); + punpckhbw_r2r (mm0, mm6); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm3, mm4); + + punpcklbw_r2r (mm0, mm3); + punpckhbw_r2r (mm0, mm4); + + paddw_r2r (mm3, mm5); + paddw_r2r (mm4, mm6); + + movq_r2r (mm7, mm3); // calculate round4 + previous row + current row + movq_r2r (mm7, mm4); + + paddw_r2r (mm1, mm3); + paddw_r2r (mm2, mm4); + + paddw_r2r (mm5, mm3); + paddw_r2r (mm6, mm4); + + psraw_i2r (2, mm3); // /4 + psraw_i2r (2, mm4); // /4 + + packuswb_r2r (mm4, mm3); // pack (w/ saturation) + movq_r2m (mm3, *dest); // store result in dest + + movq_r2r (mm5, mm1); // advance to the next row + movq_r2r (mm6, mm2); + + ref += stride; + dest += stride; + + } while (--height); +} + +static void MC_put_xy16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_xy_8wide_mmx(height, dest, ref, stride); + MC_put_xy_8wide_mmx(height, dest + 8, ref + 8, stride); +} + +static void MC_put_xy8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_xy_8wide_mmx(height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_avg_y_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + yuv_data_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_interp_average_2_U8 (dest, ref, ref_next); + + if (width == 16) + mmx_interp_average_2_U8 (dest+8, ref+8, ref_next+8); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_avg_y16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_y_mmx (16, height, dest, ref, stride); +} + +static void MC_avg_y8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg_y_mmx (8, height, dest, ref, stride); +} + +//----------------------------------------------------------------------- + +static inline void MC_put_y_mmx (int width, int height, + yuv_data_t * dest, yuv_data_t * ref, int stride) +{ + yuv_data_t * ref_next = ref+stride; + + mmx_zero_reg (); + + do { + mmx_average_2_U8 (dest, ref, ref_next); + + if (width == 16) + mmx_average_2_U8 (dest+8, ref+8, ref_next+8); + + dest += stride; + ref += stride; + ref_next += stride; + } while (--height); +} + +static void MC_put_y16_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_y_mmx (16, height, dest, ref, stride); +} + +static void MC_put_y8_mmx (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put_y_mmx (8, height, dest, ref, stride); +} + + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) = +{ + /* Copying functions */ + { + /* Width == 16 */ + { MC_put_16_mmx, MC_put_x16_mmx, MC_put_y16_mmx, MC_put_xy16_mmx }, + /* Width == 8 */ + { MC_put_8_mmx, MC_put_x8_mmx, MC_put_y8_mmx, MC_put_xy8_mmx } + }, + /* Averaging functions */ + { + /* Width == 16 */ + { MC_avg_16_mmx, MC_avg_x16_mmx, MC_avg_y16_mmx, MC_avg_xy16_mmx }, + /* Width == 8 */ + { MC_avg_8_mmx, MC_avg_x8_mmx, MC_avg_y8_mmx, MC_avg_xy8_mmx } + } +}; + +static int Open ( vlc_object_t *p_this ) +{ + p_this->p_private = ppppf_motion; + return VLC_SUCCESS; +} + diff --git a/modules/codec/mpeg_video/motion/motionmmxext.c b/modules/codec/mpeg_video/motion/motionmmxext.c new file mode 100644 index 0000000000..a33b63a135 --- /dev/null +++ b/modules/codec/mpeg_video/motion/motionmmxext.c @@ -0,0 +1,551 @@ +/***************************************************************************** + * motionmmxext.c : MMX EXT motion compensation module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: motionmmxext.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Aaron Holtzman + * Michel Lespinasse + * + * 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 /* malloc(), free() */ +#include + +#include + +#include "mmx.h" + +/***************************************************************************** + * Local prototype. + *****************************************************************************/ +static int Open ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MMX EXT motion compensation module") ); + set_capability( "motion compensation", 200 ); + add_requirement( MMXEXT ); + add_shortcut( "mmxext" ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Motion compensation in MMXEXT (OK I know this does 3DNow too and it's ugly) + *****************************************************************************/ + +#define CPU_MMXEXT 0 +#define CPU_3DNOW 1 + + +//CPU_MMXEXT/CPU_3DNOW adaptation layer + +#define pavg_r2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_r2r (src, dest); \ + else \ + pavgusb_r2r (src, dest); \ +} while (0) + +#define pavg_m2r(src,dest) \ +do { \ + if (cpu == CPU_MMXEXT) \ + pavgb_m2r (src, dest); \ + else \ + pavgusb_m2r (src, dest); \ +} while (0) + + +//CPU_MMXEXT code + + +static inline void MC_put1_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_r2m (mm0, *dest); + ref += stride; + dest += stride; + } while (--height); +} + +static inline void MC_put1_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg1_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_put2_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_put2_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + movq_r2m (mm0, *dest); + ref += stride; + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*dest, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg2_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int offset, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+8), mm1); + pavg_m2r (*(ref+offset), mm0); + pavg_m2r (*(ref+offset+8), mm1); + pavg_m2r (*dest, mm0); + pavg_m2r (*(dest+8), mm1); + ref += stride; + movq_r2m (mm0, *dest); + movq_r2m (mm1, *(dest+8)); + dest += stride; + } while (--height); +} + +static mmx_t mask_one = {0x0101010101010101LL}; + +static inline void MC_put4_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + movq_m2r (*ref, mm0); + movq_m2r (*(ref+1), mm1); + movq_r2r (mm0, mm7); + pxor_r2r (mm1, mm7); + pavg_r2r (mm1, mm0); + ref += stride; + + do { + movq_m2r (*ref, mm2); + movq_r2r (mm0, mm5); + + movq_m2r (*(ref+1), mm3); + movq_r2r (mm2, mm6); + + pxor_r2r (mm3, mm6); + pavg_r2r (mm3, mm2); + + por_r2r (mm6, mm7); + pxor_r2r (mm2, mm5); + + pand_r2r (mm5, mm7); + pavg_r2r (mm2, mm0); + + pand_m2r (mask_one, mm7); + + psubusb_r2r (mm7, mm0); + + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + + movq_r2r (mm6, mm7); // unroll ! + movq_r2r (mm2, mm0); // unroll ! + } while (--height); +} + +static inline void MC_put4_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_8 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *dest); + dest += stride; + } while (--height); +} + +static inline void MC_avg4_16 (int height, yuv_data_t * dest, yuv_data_t * ref, + int stride, int cpu) +{ + do { + movq_m2r (*ref, mm0); + movq_m2r (*(ref+stride+1), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+1), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*dest, mm1); + pavg_r2r (mm1, mm0); + movq_r2m (mm0, *dest); + + movq_m2r (*(ref+8), mm0); + movq_m2r (*(ref+stride+9), mm1); + movq_r2r (mm0, mm7); + movq_m2r (*(ref+9), mm2); + pxor_r2r (mm1, mm7); + movq_m2r (*(ref+stride+8), mm3); + movq_r2r (mm2, mm6); + pxor_r2r (mm3, mm6); + pavg_r2r (mm1, mm0); + pavg_r2r (mm3, mm2); + por_r2r (mm6, mm7); + movq_r2r (mm0, mm6); + pxor_r2r (mm2, mm6); + pand_r2r (mm6, mm7); + pand_m2r (mask_one, mm7); + pavg_r2r (mm2, mm0); + psubusb_r2r (mm7, mm0); + movq_m2r (*(dest+8), mm1); + pavg_r2r (mm1, mm0); + ref += stride; + movq_r2m (mm0, *(dest+8)); + dest += stride; + } while (--height); +} + +static void MC_avg_16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_x8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_put_x8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_MMXEXT); +} + +static void MC_avg_y16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_y8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_put_y8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_MMXEXT); +} + +static void MC_avg_xy16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_avg_xy8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy16_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_16 (height, dest, ref, stride, CPU_MMXEXT); +} + +static void MC_put_xy8_mmxext (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put4_8 (height, dest, ref, stride, CPU_MMXEXT); +} + + +static void MC_avg_16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_16 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_avg_8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg1_8 (height, dest, ref, stride, CPU_3DNOW); +} + +static void MC_put_16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_16 (height, dest, ref, stride); +} + +static void MC_put_8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put1_8 (height, dest, ref, stride); +} + +static void MC_avg_x16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_x8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_put_x8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, 1, CPU_3DNOW); +} + +static void MC_avg_y16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_avg_y8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_avg2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y16_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_16 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +static void MC_put_y8_3dnow (yuv_data_t * dest, yuv_data_t * ref, + int stride, int height) +{ + MC_put2_8 (height, dest, ref, stride, stride, CPU_3DNOW); +} + +/***************************************************************************** + * Functions exported as capabilities. They are declared as static so that + * we don't pollute the namespace too much. + *****************************************************************************/ +static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) = +{ + /* Copying functions */ + { + /* Width == 16 */ + { MC_put_16_mmxext, MC_put_x16_mmxext, MC_put_y16_mmxext, MC_put_xy16_mmxext }, + /* Width == 8 */ + { MC_put_8_mmxext, MC_put_x8_mmxext, MC_put_y8_mmxext, MC_put_xy8_mmxext } + }, + /* Averaging functions */ + { + /* Width == 16 */ + { MC_avg_16_mmxext, MC_avg_x16_mmxext, MC_avg_y16_mmxext, MC_avg_xy16_mmxext }, + /* Width == 8 */ + { MC_avg_8_mmxext, MC_avg_x8_mmxext, MC_avg_y8_mmxext, MC_avg_xy8_mmxext } + } +}; + +static int Open ( vlc_object_t *p_this ) +{ + p_this->p_private = ppppf_motion; + return VLC_SUCCESS; +} + diff --git a/modules/codec/mpeg_video/parser.c b/modules/codec/mpeg_video/parser.c new file mode 100644 index 0000000000..f129b41a70 --- /dev/null +++ b/modules/codec/mpeg_video/parser.c @@ -0,0 +1,424 @@ +/***************************************************************************** + * video_parser.c : video parser thread + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: parser.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Samuel Hocevar + * + * 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 /* malloc(), free() */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include /* getpid() */ +#endif + +#include +#include + +#ifdef HAVE_SYS_TIMES_H +# include +#endif + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" + +/* + * Local prototypes + */ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( vpar_thread_t * ); +static void EndThread ( vpar_thread_t * ); +static void BitstreamCallback ( bit_stream_t *, vlc_bool_t ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define VDEC_IDCT_TEXT N_("IDCT module") +#define VDEC_IDCT_LONGTEXT N_( \ + "This option allows you to select the IDCT module used by this video " \ + "decoder. The default behavior is to automatically select the best " \ + "module available.") + +#define VDEC_MOTION_TEXT N_("motion compensation module") +#define VDEC_MOTION_LONGTEXT N_( \ + "This option allows you to select the motion compensation module used by "\ + "this video decoder. The default behavior is to automatically select the "\ + "best module available.") + +#define VDEC_SMP_TEXT N_("use additional processors") +#define VDEC_SMP_LONGTEXT N_( \ + "This video decoder can benefit from a multiprocessor computer. If you " \ + "have one, you can specify the number of processors here.") + +#define VPAR_SYNCHRO_TEXT N_("force synchro algorithm {I|I+|IP|IP+|IPB}") +#define VPAR_SYNCHRO_LONGTEXT N_( \ + "This allows you to force the synchro algorithm, by directly selecting " \ + "the types of picture you want to decode. Please bear in mind that if " \ + "you select more pictures than what your CPU is capable to decode, " \ + "you won't get anything.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_module ( "mpeg-idct", "idct", NULL, NULL, + VDEC_IDCT_TEXT, VDEC_IDCT_LONGTEXT ); + add_module ( "mpeg-motion", "motion", NULL, NULL, + VDEC_MOTION_TEXT, VDEC_IDCT_LONGTEXT ); + add_integer ( "vdec-smp", 0, NULL, VDEC_SMP_TEXT, VDEC_SMP_LONGTEXT ); + add_string ( "vpar-synchro", NULL, NULL, VPAR_SYNCHRO_TEXT, + VPAR_SYNCHRO_LONGTEXT ); + set_description( _("MPEG I/II video decoder module") ); + set_capability( "decoder", 50 ); + 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 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('m','p','g','v') ) + { + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; + } + + return VLC_EGENERIC; +} + +/***************************************************************************** + * RunDecoder: this function is called just after the thread is created + *****************************************************************************/ +static int RunDecoder ( decoder_fifo_t * p_fifo ) +{ + vpar_thread_t * p_vpar; + vlc_bool_t b_error; + + /* Allocate the memory needed to store the thread's structure */ + if ( (p_vpar = (vpar_thread_t *)malloc( sizeof(vpar_thread_t) )) == NULL ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + + /* + * Initialize the thread properties + */ + p_vpar->p_fifo = p_fifo; + p_vpar->p_vout = NULL; + + /* + * Initialize thread + */ + p_vpar->p_fifo->b_error = InitThread( p_vpar ); + + /* + * Main loop - it is not executed if an error occured during + * initialization + */ + while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) ) + { + /* Find the next sequence header in the stream */ + p_vpar->p_fifo->b_error = vpar_NextSequenceHeader( p_vpar ); + + while( (!p_vpar->p_fifo->b_die) && (!p_vpar->p_fifo->b_error) ) + { + p_vpar->c_loops++; + + /* Parse the next sequence, group or picture header */ + if( vpar_ParseHeader( p_vpar ) ) + { + /* End of sequence */ + break; + } + } + } + + /* + * Error loop + */ + if( ( b_error = p_vpar->p_fifo->b_error ) ) + { + DecoderError( p_vpar->p_fifo ); + } + + /* End of thread */ + EndThread( p_vpar ); + + if( b_error ) + { + return( -1 ); + } + + return( 0 ); + +} + +/***************************************************************************** + * InitThread: initialize vpar output thread + ***************************************************************************** + * This function is called from Run and performs the second step + * of the initialization. It returns 0 on success. Note that the thread's + * flag are not modified inside this function. + *****************************************************************************/ +static int InitThread( vpar_thread_t *p_vpar ) +{ + char *psz_name; + + /* + * Choose the best motion compensation module + */ + psz_name = config_GetPsz( p_vpar->p_fifo, "mpeg-motion" ); + p_vpar->p_motion = + module_Need( p_vpar->p_fifo, "motion compensation", psz_name ); + if( psz_name ) free( psz_name ); + + if( p_vpar->p_motion == NULL ) + { + msg_Err( p_vpar->p_fifo, "no suitable motion compensation module" ); + free( p_vpar ); + return( -1 ); + } + + memcpy( p_vpar->pool.ppppf_motion, + p_vpar->p_fifo->p_private, sizeof(void *) * 16 ); + + /* + * Choose the best IDCT module + */ + psz_name = config_GetPsz( p_vpar->p_fifo, "mpeg-idct" ); + p_vpar->p_idct = module_Need( p_vpar->p_fifo, "idct", psz_name ); + if( psz_name ) free( psz_name ); + + if( p_vpar->p_idct == NULL ) + { + msg_Err( p_vpar->p_fifo, "no suitable IDCT module" ); + module_Unneed( p_vpar->p_fifo, p_vpar->p_motion ); + free( p_vpar ); + return( -1 ); + } + + p_vpar->pool.pf_idct_init = ((void**)p_vpar->p_fifo->p_private)[0]; + p_vpar->pf_norm_scan = ((void**)p_vpar->p_fifo->p_private)[1]; + p_vpar->pf_sparse_idct_add = ((void**)p_vpar->p_fifo->p_private)[2]; + p_vpar->pf_sparse_idct_copy = ((void**)p_vpar->p_fifo->p_private)[3]; + p_vpar->pf_idct_add = ((void**)p_vpar->p_fifo->p_private)[4]; + p_vpar->pf_idct_copy = ((void**)p_vpar->p_fifo->p_private)[5]; + + /* Initialize input bitstream */ + InitBitstream( &p_vpar->bit_stream, p_vpar->p_fifo, + BitstreamCallback, (void *)p_vpar ); + + /* Initialize parsing data */ + p_vpar->sequence.p_forward = NULL; + p_vpar->sequence.p_backward = NULL; + p_vpar->sequence.intra_quant.b_allocated = 0; + p_vpar->sequence.nonintra_quant.b_allocated = 0; + p_vpar->sequence.chroma_intra_quant.b_allocated = 0; + p_vpar->sequence.chroma_nonintra_quant.b_allocated = 0; + p_vpar->sequence.i_matrix_coefficients = 1; + p_vpar->sequence.next_pts = p_vpar->sequence.next_dts = 0; + p_vpar->sequence.b_expect_discontinuity = 0; + + p_vpar->sequence.i_width = 0; + p_vpar->sequence.i_height = 0; + p_vpar->sequence.i_frame_rate = 0; + p_vpar->sequence.i_scalable_mode = 0; + p_vpar->sequence.i_matrix_coefficients = 0; + p_vpar->sequence.b_mpeg2 = 0; + p_vpar->sequence.b_progressive = 0; + + /* Initialize copyright information */ + p_vpar->sequence.b_copyright_flag = 0; + p_vpar->sequence.b_original = 0; + p_vpar->sequence.i_copyright_id = 0; + p_vpar->sequence.i_copyright_nb = 0; + + p_vpar->picture.p_picture = NULL; + p_vpar->picture.i_current_structure = 0; + + /* Initialize other properties */ + p_vpar->c_loops = 0; + p_vpar->c_sequences = 0; + memset(p_vpar->pc_pictures, 0, sizeof(p_vpar->pc_pictures)); + memset(p_vpar->pc_decoded_pictures, 0, sizeof(p_vpar->pc_decoded_pictures)); + memset(p_vpar->pc_malformed_pictures, 0, + sizeof(p_vpar->pc_malformed_pictures)); + vpar_InitScanTable( p_vpar ); + + /* + * Initialize the synchro properties + */ + vpar_SynchroInit( p_vpar ); + + /* Spawn optional video decoder threads */ + vpar_InitPool( p_vpar ); + + /* Mark thread as running and return */ + return( 0 ); +} + +/***************************************************************************** + * EndThread: thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +static void EndThread( vpar_thread_t *p_vpar ) +{ +#ifdef HAVE_SYS_TIMES_H + struct tms cpu_usage; + times( &cpu_usage ); +#endif + + if( p_vpar->p_vout != NULL ) + { + /* Release used video buffers. */ + if( p_vpar->sequence.p_forward != NULL ) + { + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward ); + } + if( p_vpar->sequence.p_backward != NULL ) + { + vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward, + vpar_SynchroDate( p_vpar ) ); + vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_backward ); + } + if( p_vpar->picture.p_picture != NULL ) + { + vout_DestroyPicture( p_vpar->p_vout, p_vpar->picture.p_picture ); + } + + /* We are about to die. Reattach video output to p_vlc. */ + vlc_object_detach( p_vpar->p_vout, p_vpar->p_fifo ); + vlc_object_attach( p_vpar->p_vout, p_vpar->p_fifo->p_vlc ); + } + + msg_Dbg( p_vpar->p_fifo, "%d loops among %d sequence(s)", + p_vpar->c_loops, p_vpar->c_sequences ); + +#ifdef HAVE_SYS_TIMES_H + msg_Dbg( p_vpar->p_fifo, "cpu usage (user: %d, system: %d)", + cpu_usage.tms_utime, cpu_usage.tms_stime ); +#endif + + msg_Dbg( p_vpar->p_fifo, "read %d frames/fields (I %d/P %d/B %d)", + p_vpar->pc_pictures[I_CODING_TYPE] + + p_vpar->pc_pictures[P_CODING_TYPE] + + p_vpar->pc_pictures[B_CODING_TYPE], + p_vpar->pc_pictures[I_CODING_TYPE], + p_vpar->pc_pictures[P_CODING_TYPE], + p_vpar->pc_pictures[B_CODING_TYPE] ); + msg_Dbg( p_vpar->p_fifo, "decoded %d frames/fields (I %d/P %d/B %d)", + p_vpar->pc_decoded_pictures[I_CODING_TYPE] + + p_vpar->pc_decoded_pictures[P_CODING_TYPE] + + p_vpar->pc_decoded_pictures[B_CODING_TYPE], + p_vpar->pc_decoded_pictures[I_CODING_TYPE], + p_vpar->pc_decoded_pictures[P_CODING_TYPE], + p_vpar->pc_decoded_pictures[B_CODING_TYPE] ); + msg_Dbg( p_vpar->p_fifo, + "read %d malformed frames/fields (I %d/P %d/B %d)", + p_vpar->pc_malformed_pictures[I_CODING_TYPE] + + p_vpar->pc_malformed_pictures[P_CODING_TYPE] + + p_vpar->pc_malformed_pictures[B_CODING_TYPE], + p_vpar->pc_malformed_pictures[I_CODING_TYPE], + p_vpar->pc_malformed_pictures[P_CODING_TYPE], + p_vpar->pc_malformed_pictures[B_CODING_TYPE] ); +#define S p_vpar->sequence + msg_Dbg( p_vpar->p_fifo, "%s stream (%dx%d), %d.%d pi/s", + S.b_mpeg2 ? "MPEG-2" : "MPEG-1", + S.i_width, S.i_height, S.i_frame_rate/1001, + S.i_frame_rate % 1001 ); + msg_Dbg( p_vpar->p_fifo, "%s, %s, matrix_coeff: %d", + S.b_progressive ? "Progressive" : "Non-progressive", + S.i_scalable_mode ? "scalable" : "non-scalable", + S.i_matrix_coefficients ); +#undef S + + /* Dispose of matrices if they have been allocated. */ + if( p_vpar->sequence.intra_quant.b_allocated ) + { + free( p_vpar->sequence.intra_quant.pi_matrix ); + } + if( p_vpar->sequence.nonintra_quant.b_allocated ) + { + free( p_vpar->sequence.nonintra_quant.pi_matrix) ; + } + if( p_vpar->sequence.chroma_intra_quant.b_allocated ) + { + free( p_vpar->sequence.chroma_intra_quant.pi_matrix ); + } + if( p_vpar->sequence.chroma_nonintra_quant.b_allocated ) + { + free( p_vpar->sequence.chroma_nonintra_quant.pi_matrix ); + } + + vpar_EndPool( p_vpar ); + + module_Unneed( p_vpar->p_fifo, p_vpar->p_idct ); + module_Unneed( p_vpar->p_fifo, p_vpar->p_motion ); + + free( p_vpar ); +} + +/***************************************************************************** + * 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 ) +{ + vpar_thread_t * p_vpar = (vpar_thread_t *)p_bit_stream->p_callback_arg; + + if( b_new_pes ) + { + p_vpar->sequence.i_current_rate = + p_bit_stream->p_decoder_fifo->p_first->i_rate; + + if( p_bit_stream->p_decoder_fifo->p_first->b_discontinuity ) + { + /* Escape the current picture and reset the picture predictors. */ + p_vpar->sequence.b_expect_discontinuity = 1; + p_vpar->picture.b_error = 1; + } + } + + if( p_bit_stream->p_data->b_discard_payload ) + { + /* 1 packet messed up, trash the slice. */ + p_vpar->picture.b_error = 1; + } +} diff --git a/modules/codec/mpeg_video/parser.h b/modules/codec/mpeg_video/parser.h new file mode 100644 index 0000000000..f91da7e72a --- /dev/null +++ b/modules/codec/mpeg_video/parser.h @@ -0,0 +1,405 @@ +/***************************************************************************** + * video_parser.h : video parser thread + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: parser.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Jean-Marc Dressler + * Stéphane Borel + * + * 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. + *****************************************************************************/ + +/* + * Block parsing structures + */ + +/***************************************************************************** + * macroblock_parsing_t : macroblock context & predictors + *****************************************************************************/ +typedef struct motion_s +{ + u8 * pppi_ref[2][3]; + int ppi_pmv[2][2]; + int pi_f_code[2]; +} motion_t; + +typedef struct macroblock_parsing_s +{ + int i_offset; + + motion_t b_motion; + motion_t f_motion; + + /* Predictor for DC coefficients in intra blocks */ + u16 pi_dc_dct_pred[3]; + u8 i_quantizer_scale; /* scale of the quantization + * matrices */ +} macroblock_parsing_t; + +/***************************************************************************** + * Constants + *****************************************************************************/ +extern u8 pi_default_intra_quant[64]; +extern u8 pi_default_nonintra_quant[64]; +extern u8 pi_scan[2][64]; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +void vpar_InitScanTable( struct vpar_thread_s * p_vpar ); + +typedef void (*f_picture_data_t)( struct vpar_thread_s * p_vpar ); +#define PROTO_PICD( FUNCNAME ) \ +void FUNCNAME( struct vpar_thread_s * p_vpar ); + +PROTO_PICD( vpar_PictureDataGENERIC ) +#if (VPAR_OPTIM_LEVEL > 0) +PROTO_PICD( vpar_PictureData2IF ) +PROTO_PICD( vpar_PictureData2PF ) +PROTO_PICD( vpar_PictureData2BF ) +#endif +#if (VPAR_OPTIM_LEVEL > 1) +PROTO_PICD( vpar_PictureData2IT ) +PROTO_PICD( vpar_PictureData2PT ) +PROTO_PICD( vpar_PictureData2BT ) +PROTO_PICD( vpar_PictureData2IB ) +PROTO_PICD( vpar_PictureData2PB ) +PROTO_PICD( vpar_PictureData2BB ) +PROTO_PICD( vpar_PictureData1I ) +PROTO_PICD( vpar_PictureData1P ) +PROTO_PICD( vpar_PictureData1B ) +PROTO_PICD( vpar_PictureData1D ) +#endif + + +/* + * Headers parsing structures + */ + +/***************************************************************************** + * quant_matrix_t : Quantization Matrix + *****************************************************************************/ +typedef struct quant_matrix_s +{ + u8 * pi_matrix; + vlc_bool_t b_allocated; + /* Has the matrix been allocated by vpar_headers ? */ +} quant_matrix_t; + +/***************************************************************************** + * sequence_t : sequence descriptor + ***************************************************************************** + * This structure should only be changed when reading the sequence header, + * or exceptionnally some extension structures (like quant_matrix). + *****************************************************************************/ +typedef struct sequence_s +{ + u32 i_height, i_width; /* height and width of the lum + * comp of the picture */ + u32 i_size; /* total number of pel of the lum comp */ + u32 i_mb_height, i_mb_width, i_mb_size; + /* the same, in macroblock units */ + unsigned int i_aspect; /* height/width display ratio */ + unsigned int i_matrix_coefficients;/* coeffs of the YUV transform */ + int i_chroma_format, i_scalable_mode; + int i_chroma_nb_blocks; + vlc_bool_t b_chroma_h_subsampled, b_chroma_v_subsampled; + int i_frame_rate; /* theoritical frame rate in fps*1001 */ + vlc_bool_t b_mpeg2; /* guess */ + vlc_bool_t b_progressive; /* progressive (ie. + * non-interlaced) frame */ + quant_matrix_t intra_quant, nonintra_quant; + quant_matrix_t chroma_intra_quant, chroma_nonintra_quant; + /* current quantization matrices */ + + /* Parser context */ + picture_t * p_forward; /* current forward reference frame */ + picture_t * p_backward; /* current backward reference frame */ + mtime_t next_pts, next_dts; + int i_current_rate; + vlc_bool_t b_expect_discontinuity; /* reset the frame predictors + * after the current frame */ + + /* Copyright extension */ + vlc_bool_t b_copyright_flag; /* Whether the following + information is significant + or not. */ + u8 i_copyright_id; + vlc_bool_t b_original; + u64 i_copyright_nb; +} sequence_t; + +/***************************************************************************** + * picture_parsing_t : parser context descriptor + ***************************************************************************** + * This structure should only be changed when reading the picture header. + *****************************************************************************/ +typedef struct picture_parsing_s +{ + /* Values from the picture_coding_extension. */ + int ppi_f_code[2][2]; + int i_intra_dc_precision; + vlc_bool_t b_frame_pred_frame_dct, b_q_scale_type; + vlc_bool_t b_intra_vlc_format; + vlc_bool_t b_progressive; + u8 * pi_scan; + vlc_bool_t b_top_field_first, b_concealment_mv; + vlc_bool_t b_repeat_first_field; + /* Relative to the current field */ + int i_coding_type, i_structure, i_field_width; + vlc_bool_t b_frame_structure; /* i_structure == FRAME_STRUCTURE */ + vlc_bool_t b_current_field; /* i_structure == TOP_FIELD */ + vlc_bool_t b_second_field; + + picture_t * p_picture; /* picture buffer from vout */ + int i_current_structure; /* current parsed structure of + * p_picture (second field ?) */ + vlc_bool_t b_error; /* parsing error, try to recover */ + + /* Given by the video output */ + int i_lum_stride, i_chrom_stride; +} picture_parsing_t; + +/***************************************************************************** + * Standard codes + *****************************************************************************/ +#define PICTURE_START_CODE 0x100L +#define SLICE_START_CODE_MIN 0x101L +#define SLICE_START_CODE_MAX 0x1AFL +#define USER_DATA_START_CODE 0x1B2L +#define SEQUENCE_HEADER_CODE 0x1B3L +#define SEQUENCE_ERROR_CODE 0x1B4L +#define EXTENSION_START_CODE 0x1B5L +#define SEQUENCE_END_CODE 0x1B7L +#define GROUP_START_CODE 0x1B8L + +/* extension start code IDs */ +#define SEQUENCE_EXTENSION_ID 1 +#define SEQUENCE_DISPLAY_EXTENSION_ID 2 +#define QUANT_MATRIX_EXTENSION_ID 3 +#define COPYRIGHT_EXTENSION_ID 4 +#define SEQUENCE_SCALABLE_EXTENSION_ID 5 +#define PICTURE_DISPLAY_EXTENSION_ID 7 +#define PICTURE_CODING_EXTENSION_ID 8 +#define PICTURE_SPATIAL_SCALABLE_EXTENSION_ID 9 +#define PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID 10 + +/* scalable modes */ +#define SC_NONE 0 +#define SC_DP 1 +#define SC_SPAT 2 +#define SC_SNR 3 +#define SC_TEMP 4 + +/* Chroma types */ +#define CHROMA_NONE 0 +#define CHROMA_420 1 +#define CHROMA_422 2 +#define CHROMA_444 3 + +/* Pictures types */ +#define I_CODING_TYPE 1 +#define P_CODING_TYPE 2 +#define B_CODING_TYPE 3 +#define D_CODING_TYPE 4 /* MPEG-1 ONLY */ +/* other values are reserved */ + +/* Structures */ +#define TOP_FIELD 1 +#define BOTTOM_FIELD 2 +#define FRAME_STRUCTURE 3 + +/* Aspect ratio (ISO/IEC 13818-2 section 6.3.3, table 6-3) */ +#define AR_SQUARE_PICTURE 1 /* square pixels */ +#define AR_3_4_PICTURE 2 /* 3:4 picture (TV) */ +#define AR_16_9_PICTURE 3 /* 16:9 picture (wide screen) */ +#define AR_221_1_PICTURE 4 /* 2.21:1 picture (movie) */ + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +int vpar_NextSequenceHeader( struct vpar_thread_s * p_vpar ); +int vpar_ParseHeader( struct vpar_thread_s * p_vpar ); + + +/* + * Synchronization management + */ + +/***************************************************************************** + * video_synchro_t : timers for the video synchro + *****************************************************************************/ +#define MAX_PIC_AVERAGE 8 + +/* Read the discussion on top of vpar_synchro.c for more information. */ +typedef struct video_synchro_s +{ + /* synchro algorithm */ + int i_type; + + /* date of the beginning of the decoding of the current picture */ + mtime_t decoding_start; + + /* stream properties */ + unsigned int i_n_p, i_n_b; + + /* decoding values */ + mtime_t p_tau[4]; /* average decoding durations */ + unsigned int pi_meaningful[4]; /* number of durations read */ + /* and p_vout->render_time (read with p_vout->change_lock) */ + + /* stream context */ + unsigned int i_eta_p, i_eta_b; + vlc_bool_t b_dropped_last; /* for special synchros below */ + mtime_t backward_pts, current_pts; + int i_current_period; /* period to add to the next picture */ + int i_backward_period; /* period to add after the next + * reference picture + * (backward_period * period / 2) */ + + /* statistics */ + unsigned int i_trashed_pic, i_not_chosen_pic, i_pic; +} video_synchro_t; + +/* Synchro algorithms */ +#define VPAR_SYNCHRO_DEFAULT 0 +#define VPAR_SYNCHRO_I 1 +#define VPAR_SYNCHRO_Iplus 2 +#define VPAR_SYNCHRO_IP 3 +#define VPAR_SYNCHRO_IPplus 4 +#define VPAR_SYNCHRO_IPB 5 + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +void vpar_SynchroInit ( struct vpar_thread_s * p_vpar ); +vlc_bool_t vpar_SynchroChoose ( struct vpar_thread_s * p_vpar, + int i_coding_type, int i_structure ); +void vpar_SynchroTrash ( struct vpar_thread_s * p_vpar, + int i_coding_type, int i_structure ); +void vpar_SynchroDecode ( struct vpar_thread_s * p_vpar, + int i_coding_type, int i_structure ); +void vpar_SynchroEnd ( struct vpar_thread_s * p_vpar, + int i_coding_type, int i_structure, + int i_garbage ); +mtime_t vpar_SynchroDate ( struct vpar_thread_s * p_vpar ); +void vpar_SynchroNewPicture( struct vpar_thread_s * p_vpar, int i_coding_type, + int i_repeat_field ); + + +/* + * Video parser structures + */ + +/***************************************************************************** + * vpar_thread_t: video parser thread descriptor + *****************************************************************************/ +typedef struct vpar_thread_s +{ + bit_stream_t bit_stream; + + /* Thread properties and locks */ + vlc_thread_t thread_id; /* id for thread functions */ + + /* Input properties */ + decoder_fifo_t * p_fifo; /* PES input fifo */ + + /* Output properties */ + vout_thread_t * p_vout; /* video output thread */ + + /* Decoder properties */ + vdec_pool_t pool; + + /* Parser properties */ + sequence_t sequence; + picture_parsing_t picture; + macroblock_parsing_t mb; + video_synchro_t synchro; + + /* Scan table */ + u8 ppi_scan[2][64]; + /* Default quantization matrices */ + u8 pi_default_intra_quant[64]; + u8 pi_default_nonintra_quant[64]; + + /* Motion compensation plug-in used and shortcuts */ + module_t * p_motion; + + /* IDCT plug-in used and shortcuts */ + module_t * p_idct; + void ( * pf_sparse_idct_add )( dctelem_t *, yuv_data_t *, int, + void *, int ); + void ( * pf_idct_add ) ( dctelem_t *, yuv_data_t *, int, + void *, int ); + void ( * pf_sparse_idct_copy )( dctelem_t *, yuv_data_t *, int, + void *, int ); + void ( * pf_idct_copy ) ( dctelem_t *, yuv_data_t *, int, + void *, int ); + + void ( * pf_norm_scan ) ( u8 ppi_scan[2][64] ); + + /* Statistics */ + count_t c_loops; /* number of loops */ + count_t c_sequences; /* number of sequences */ + count_t pc_pictures[4]; /* number of (coding_type) pictures read */ + count_t pc_decoded_pictures[4]; /* number of (coding_type) + * pictures decoded */ + count_t pc_malformed_pictures[4]; /* number of pictures trashed + * during parsing */ +} vpar_thread_t; + +/***************************************************************************** + * NextStartCode : Find the next start code + *****************************************************************************/ +static inline void NextStartCode( bit_stream_t * p_bit_stream ) +{ + /* Re-align the buffer on an 8-bit boundary */ + RealignBits( p_bit_stream ); + + while( ShowBits( p_bit_stream, 24 ) != 0x01L + && !p_bit_stream->p_decoder_fifo->b_die ) + { + RemoveBits( p_bit_stream, 8 ); + } +} + +/***************************************************************************** + * LoadQuantizerScale + ***************************************************************************** + * Quantizer scale factor (ISO/IEC 13818-2 7.4.2.2) + *****************************************************************************/ +static inline void LoadQuantizerScale( struct vpar_thread_s * p_vpar ) +{ + /* Quantization coefficient table */ + static u8 pi_non_linear_quantizer_scale[32] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,12,14,16,18,20, 22, + 24,28,32,36,40,44,48,52,56,64,72,80,88,96,104,112 + }; + int i_q_scale_code = GetBits( &p_vpar->bit_stream, 5 ); + + if( p_vpar->picture.b_q_scale_type ) + { + p_vpar->mb.i_quantizer_scale = + pi_non_linear_quantizer_scale[i_q_scale_code]; + } + else + { + p_vpar->mb.i_quantizer_scale = i_q_scale_code << 1; + } +} + diff --git a/modules/codec/mpeg_video/pool.c b/modules/codec/mpeg_video/pool.c new file mode 100644 index 0000000000..7995217c7a --- /dev/null +++ b/modules/codec/mpeg_video/pool.c @@ -0,0 +1,332 @@ +/***************************************************************************** + * vpar_pool.c : management of the pool of decoder threads + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: pool.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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 /* memcpy(), memset() */ +#include /* realloc() */ + +#include +#include +#include + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" + +/* + * Local prototypes + */ +static void WaitDummy( vdec_pool_t * p_pool ); +static void WaitPool( vdec_pool_t * p_pool ); +static void FreeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb ); +static void FreeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb ); +static macroblock_t * NewMacroblockDummy( vdec_pool_t * p_pool ); +static macroblock_t * NewMacroblockPool( vdec_pool_t * p_pool ); +static void DecodeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb ); +static void DecodeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb ); + +/***************************************************************************** + * vpar_InitPool: Initializes the pool structure + *****************************************************************************/ +void vpar_InitPool( vpar_thread_t * p_vpar ) +{ + int j; + + /* Initialize mutex and cond. */ + vlc_mutex_init( p_vpar->p_fifo, &p_vpar->pool.lock ); + vlc_cond_init( p_vpar->p_fifo, &p_vpar->pool.wait_empty ); + vlc_cond_init( p_vpar->p_fifo, &p_vpar->pool.wait_undecoded ); + + /* Spawn optional video decoder threads. */ + p_vpar->pool.i_smp = 0; + p_vpar->pool.pp_vdec = NULL; + p_vpar->pool.p_macroblocks = NULL; + p_vpar->pool.pp_empty_macroblocks = NULL; + p_vpar->pool.pp_new_macroblocks = NULL; + p_vpar->pool.p_vpar = p_vpar; + vpar_SpawnPool( p_vpar ); + + /* Initialize fake video decoder structure (used when + * decoder == parser). */ + p_vpar->pool.p_vdec = vlc_object_create( p_vpar->p_fifo, + sizeof(vdec_thread_t) ); + if ( p_vpar->pool.p_vdec == NULL ) + { + msg_Err( p_vpar->p_fifo, "out of memory" ); + p_vpar->p_fifo->b_error = 1; + return; + } + p_vpar->pool.p_vdec->p_pool = &p_vpar->pool; + vdec_InitThread( p_vpar->pool.p_vdec ); + + vlc_object_attach( p_vpar->pool.p_vdec, p_vpar->p_fifo ); + + for( j = 0; j < 12; j++ ) + { + p_vpar->pool.mb.p_idcts[j].pi_block = + vlc_memalign( &p_vpar->pool.mb.p_idcts[j].pi_block_orig, + 16, 64 * sizeof(dctelem_t) ); + } +} + +/***************************************************************************** + * vpar_SpawnPool: Create and cancel video decoder threads at any time + ***************************************************************************** + * This function is called on startup, and everytime the user changes the + * number of threads to launch. Please note that *all* decoder threads must + * be idle during this operation, which only happens at the end of + * PictureHeader(). + *****************************************************************************/ +void vpar_SpawnPool( vpar_thread_t * p_vpar ) +{ + int i_new_smp; + stream_ctrl_t * p_control; + + p_control = p_vpar->p_fifo->p_stream_ctrl; + vlc_mutex_lock( &p_control->control_lock ); + i_new_smp = config_GetInt( p_vpar->p_fifo, "vdec-smp" ); + vlc_mutex_unlock( &p_control->control_lock ); + + /* FIXME: No error check because I'm tired. Come back later... */ + + /* No need to lock p_vpar->pool, since decoders MUST be idle here. */ + if( p_vpar->pool.i_smp != i_new_smp ) + { + int i; + + if( p_vpar->pool.i_smp > i_new_smp ) + { + /* The user reduces the number of threads. */ + + for( i = p_vpar->pool.i_smp - 1; i >= i_new_smp; i-- ) + { + int j; + + vlc_object_detach_all( p_vpar->pool.pp_vdec[i] ); + vdec_DestroyThread( p_vpar->pool.pp_vdec[i] ); + + for( j = 0; j < 12; j++ ) + { + free( p_vpar->pool.p_macroblocks[i].p_idcts[j].pi_block_orig ); + } + } + + p_vpar->pool.pp_vdec = realloc( p_vpar->pool.pp_vdec, + i_new_smp * sizeof(vdec_thread_t *) ); + p_vpar->pool.p_macroblocks = realloc( p_vpar->pool.p_macroblocks, + i_new_smp * sizeof(macroblock_t) ); + p_vpar->pool.pp_empty_macroblocks = realloc( p_vpar->pool.pp_empty_macroblocks, + i_new_smp * sizeof(macroblock_t *) ); + p_vpar->pool.i_index_empty = i_new_smp; + p_vpar->pool.pp_new_macroblocks = realloc( p_vpar->pool.pp_new_macroblocks, + i_new_smp * sizeof(macroblock_t *) ); + p_vpar->pool.i_index_new = 0; + } + else + { + /* The user raises the number of threads. */ + + p_vpar->pool.pp_vdec = realloc( p_vpar->pool.pp_vdec, + i_new_smp * sizeof(vdec_thread_t *) ); + p_vpar->pool.p_macroblocks = realloc( p_vpar->pool.p_macroblocks, + i_new_smp * sizeof(macroblock_t) ); + p_vpar->pool.pp_empty_macroblocks = realloc( p_vpar->pool.pp_empty_macroblocks, + i_new_smp * sizeof(macroblock_t *) ); + p_vpar->pool.i_index_empty = i_new_smp; + p_vpar->pool.pp_new_macroblocks = realloc( p_vpar->pool.pp_new_macroblocks, + i_new_smp * sizeof(macroblock_t *) ); + p_vpar->pool.i_index_new = 0; + + for( i = p_vpar->pool.i_smp; i < i_new_smp ; i++ ) + { + int j; + + for( j = 0; j < 12; j++ ) + { + p_vpar->pool.p_macroblocks[i].p_idcts[j].pi_block = + vlc_memalign( &p_vpar->pool.p_macroblocks[i].p_idcts[j].pi_block_orig, + 16, 64 * sizeof(dctelem_t) ); + } + + p_vpar->pool.pp_vdec[i] = vdec_CreateThread( &p_vpar->pool ); + vlc_object_attach( p_vpar->pool.pp_vdec[i], p_vpar->p_fifo ); + } + + } + for( i = 0; i < i_new_smp; i++ ) + { + p_vpar->pool.pp_empty_macroblocks[i] = + &p_vpar->pool.p_macroblocks[i]; + } + p_vpar->pool.i_smp = i_new_smp; + } + + if( i_new_smp ) + { + /* We have at least one decoder thread. */ + p_vpar->pool.pf_wait_pool = WaitPool; + p_vpar->pool.pf_new_mb = NewMacroblockPool; + p_vpar->pool.pf_free_mb = FreeMacroblockPool; + p_vpar->pool.pf_decode_mb = DecodeMacroblockPool; + } + else + { + /* No decoder pool. */ + p_vpar->pool.pf_wait_pool = WaitDummy; + p_vpar->pool.pf_new_mb = NewMacroblockDummy; + p_vpar->pool.pf_free_mb = FreeMacroblockDummy; + p_vpar->pool.pf_decode_mb = DecodeMacroblockDummy; + } +} + +/***************************************************************************** + * vpar_EndPool: Releases the pool structure + *****************************************************************************/ +void vpar_EndPool( vpar_thread_t * p_vpar ) +{ + int i; + + for( i = 0; i < 12; i++ ) + { + free( p_vpar->pool.mb.p_idcts[i].pi_block_orig ); + } + + for( i = 0; i < p_vpar->pool.i_smp; i++ ) + { + int j; + + vlc_object_detach_all( p_vpar->pool.pp_vdec[i] ); + vdec_DestroyThread( p_vpar->pool.pp_vdec[i] ); + + for( j = 0; j < 12; j++ ) + { + free( p_vpar->pool.p_macroblocks[i].p_idcts[j].pi_block_orig ); + } + } + + if( p_vpar->pool.i_smp ) + { + free( p_vpar->pool.pp_vdec ); + free( p_vpar->pool.p_macroblocks ); + free( p_vpar->pool.pp_new_macroblocks ); + } + + /* Free fake video decoder (used when parser == decoder). */ + vlc_object_detach_all( p_vpar->pool.p_vdec ); + vdec_EndThread( p_vpar->pool.p_vdec ); + vlc_object_destroy( p_vpar->pool.p_vdec ); + + /* Destroy lock and cond. */ + vlc_mutex_destroy( &p_vpar->pool.lock ); + vlc_cond_destroy( &p_vpar->pool.wait_empty ); + vlc_cond_destroy( &p_vpar->pool.wait_undecoded ); +} + +/***************************************************************************** + * WaitPool: Wait until all decoders are idle + *****************************************************************************/ +static void WaitPool( vdec_pool_t * p_pool ) +{ + vlc_mutex_lock( &p_pool->lock ); + while( p_pool->i_index_empty != p_pool->i_smp ) + { + vlc_cond_wait( &p_pool->wait_empty, &p_pool->lock ); + } + vlc_mutex_unlock( &p_pool->lock ); +} + +/***************************************************************************** + * WaitDummy: Placeholder used when parser == decoder + *****************************************************************************/ +static void WaitDummy( vdec_pool_t * p_pool ) +{ +} + +/***************************************************************************** + * NewMacroblockPool: Get an empty macroblock from the decoder pool + *****************************************************************************/ +static macroblock_t * NewMacroblockPool( vdec_pool_t * p_pool ) +{ + macroblock_t * p_mb; + + vlc_mutex_lock( &p_pool->lock ); + while( p_pool->i_index_empty == 0 ) + { + vlc_cond_wait( &p_pool->wait_empty, &p_pool->lock ); + } + p_mb = p_pool->pp_empty_macroblocks[ --p_pool->i_index_empty ]; + vlc_mutex_unlock( &p_pool->lock ); + return( p_mb ); +} + +/***************************************************************************** + * NewMacroblockDummy: Placeholder used when parser == decoder + *****************************************************************************/ +static macroblock_t * NewMacroblockDummy( vdec_pool_t * p_pool ) +{ + return( &p_pool->mb ); +} + +/***************************************************************************** + * FreeMacroblockPool: Free a macroblock + *****************************************************************************/ +static void FreeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb ) +{ + vlc_mutex_lock( &p_pool->lock ); + p_pool->pp_empty_macroblocks[ p_pool->i_index_empty++ ] = p_mb; + vlc_cond_signal( &p_pool->wait_empty ); + vlc_mutex_unlock( &p_pool->lock ); +} + +/***************************************************************************** + * FreeMacroblockDummy: Placeholder used when parser == decoder + *****************************************************************************/ +static void FreeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb ) +{ +} + +/***************************************************************************** + * DecodeMacroblockPool: Send a macroblock to a vdec thread + *****************************************************************************/ +static void DecodeMacroblockPool( vdec_pool_t * p_pool, macroblock_t * p_mb ) +{ + vlc_mutex_lock( &p_pool->lock ); + /* The undecoded macroblock LIFO cannot be full, because + * #macroblocks == size of the LIFO */ + p_pool->pp_new_macroblocks[ p_pool->i_index_new++ ] = p_mb; + vlc_cond_signal( &p_pool->wait_undecoded ); + vlc_mutex_unlock( &p_pool->lock ); +} + +/***************************************************************************** + * DecodeMacroblockDummy: Placeholder used when parser == decoder + *****************************************************************************/ +static void DecodeMacroblockDummy( vdec_pool_t * p_pool, macroblock_t * p_mb ) +{ + p_pool->pf_vdec_decode( p_pool->p_vdec, p_mb ); +} + diff --git a/modules/codec/mpeg_video/pool.h b/modules/codec/mpeg_video/pool.h new file mode 100644 index 0000000000..14347fd47e --- /dev/null +++ b/modules/codec/mpeg_video/pool.h @@ -0,0 +1,114 @@ +/***************************************************************************** + * vpar_pool.h : video parser/video decoders communication + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: pool.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * vdec_pool_t + ***************************************************************************** + * This structure is used for the communication between the parser and the + * decoders. + *****************************************************************************/ +typedef struct vdec_pool_s vdec_pool_t; + +struct vdec_pool_s +{ + /* Locks */ + vlc_mutex_t lock; /* Structure data lock */ + vlc_cond_t wait_empty; /* The parser blocks there when all + * decoder threads are busy */ + vlc_cond_t wait_undecoded; /* The decoders block there when no + * macroblock has been given by the + * parser */ + + /* Video decoder threads */ + vdec_thread_t ** pp_vdec; /* Array of video decoder threads */ + int i_smp; /* Number of symmetrical decoder threads, + * hence size of the pp_vdec, p_macroblocks + * and pp_new_macroblocks array */ + + /* Macroblocks */ + macroblock_t * p_macroblocks; + + /* Empty macroblocks */ + macroblock_t ** pp_empty_macroblocks; /* Empty macroblocks */ + int i_index_empty; /* Last empty macroblock */ + + /* Undecoded macroblocks, read by the decoders */ + macroblock_t ** pp_new_macroblocks; /* Undecoded macroblocks */ + int i_index_new; /* Last undecoded macroblock */ + + /* Undecoded macroblock, used when the parser and the decoder share the + * same thread */ + macroblock_t mb; + vdec_thread_t * p_vdec; /* Fake video decoder */ + + /* Pointers to usual pool functions */ + void (* pf_wait_pool) ( vdec_pool_t * ); + macroblock_t * (* pf_new_mb) ( vdec_pool_t * ); + void (* pf_free_mb) ( vdec_pool_t *, macroblock_t * ); + void (* pf_decode_mb) ( vdec_pool_t *, macroblock_t * ); + + /* Pointer to the decoding function - used for B&W switching */ + void (* pf_vdec_decode) ( struct vdec_thread_s *, + macroblock_t * ); + vlc_bool_t b_bw; /* Current value for B&W */ + + /* Access to the plug-ins needed by the video decoder thread */ + void ( * pf_idct_init ) ( void ** ); + void ( * ppppf_motion[2][2][4] ) ( yuv_data_t *, yuv_data_t *, + int, int ); + + struct vpar_thread_s * p_vpar; +}; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +void vpar_InitPool ( struct vpar_thread_s * ); +void vpar_SpawnPool ( struct vpar_thread_s * ); +void vpar_EndPool ( struct vpar_thread_s * ); + +/***************************************************************************** + * vpar_GetMacroblock: In a vdec thread, get the next available macroblock + *****************************************************************************/ +static inline macroblock_t * vpar_GetMacroblock( vdec_pool_t * p_pool, + volatile vlc_bool_t * pb_die ) +{ + macroblock_t * p_mb; + + vlc_mutex_lock( &p_pool->lock ); + while( p_pool->i_index_new == 0 && !*pb_die ) + { + vlc_cond_wait( &p_pool->wait_undecoded, &p_pool->lock ); + } + + if( *pb_die ) + { + vlc_mutex_unlock( &p_pool->lock ); + return( NULL ); + } + + p_mb = p_pool->pp_new_macroblocks[ --p_pool->i_index_new ]; + vlc_mutex_unlock( &p_pool->lock ); + return( p_mb ); +} + diff --git a/modules/codec/mpeg_video/synchro.c b/modules/codec/mpeg_video/synchro.c new file mode 100644 index 0000000000..748c3967cb --- /dev/null +++ b/modules/codec/mpeg_video/synchro.c @@ -0,0 +1,586 @@ +/***************************************************************************** + * vpar_synchro.c : frame dropping routines + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: synchro.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * Samuel Hocevar + * Jean-Marc Dressler + * + * 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. + *****************************************************************************/ + +/* + * DISCUSSION : How to Write an efficient Frame-Dropping Algorithm + * ========== + * + * This implementation is based on mathematical and statistical + * developments. Older implementations used an enslavement, considering + * that if we're late when reading an I picture, we will decode one frame + * less. It had a tendancy to derive, and wasn't responsive enough, which + * would have caused trouble with the stream control stuff. + * + * 1. Structure of a picture stream + * ============================= + * Between 2 I's, we have for instance : + * I B P B P B P B P B P B I + * t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 + * Please bear in mind that B's and IP's will be inverted when displaying + * (decoding order != presentation order). Thus, t1 < t0. + * + * 2. Definitions + * =========== + * t[0..12] : Presentation timestamps of pictures 0..12. + * t : Current timestamp, at the moment of the decoding. + * T : Picture period, T = 1/frame_rate. + * tau[I,P,B] : Mean time to decode an [I,P,B] picture. + * tauYUV : Mean time to render a picture (given by the video_output). + * tau´[I,P,B] = 2 * tau[I,P,B] + tauYUV + * : Mean time + typical difference (estimated to tau/2, that + * needs to be confirmed) + render time. + * DELTA : A given error margin. + * + * 3. General considerations + * ====================== + * We define three types of machines : + * 14T > tauI : machines capable of decoding all I pictures + * 2T > tauP : machines capable of decoding all P pictures + * T > tauB : machines capable of decoding all B pictures + * + * 4. Decoding of an I picture + * ======================== + * On fast machines, we decode all I's. + * Otherwise : + * We can decode an I picture if we simply have enough time to decode it + * before displaying : + * t0 - t > tau´I + DELTA + * + * 5. Decoding of a P picture + * ======================= + * On fast machines, we decode all P's. + * Otherwise : + * First criterion : have time to decode it. + * t2 - t > tau´P + DELTA + * + * Second criterion : it shouldn't prevent us from displaying the forthcoming + * I picture, which is more important. + * t12 - t > tau´P + tau´I + DELTA + * + * 6. Decoding of a B picture + * ======================= + * On fast machines, we decode all B's. Otherwise : + * t1 - t > tau´B + DELTA + * Since the next displayed I or P is already decoded, we don't have to + * worry about it. + * + * I hope you will have a pleasant flight and do not forget your life + * jacket. + * --Meuuh (2000-12-29) + */ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* free() */ +#include /* memcpy(), memset() */ + +#include +#include +#include + +#include "vdec_ext-plugins.h" + +#include "decoder.h" +#include "pool.h" +#include "parser.h" + +/* + * Local prototypes + */ +static int SynchroType( decoder_fifo_t * ); + +/* Error margins */ +#define DELTA (int)(0.075*CLOCK_FREQ) + +#define DEFAULT_NB_P 5 +#define DEFAULT_NB_B 1 + +/***************************************************************************** + * vpar_SynchroInit : You know what ? + *****************************************************************************/ +void vpar_SynchroInit( vpar_thread_t * p_vpar ) +{ + p_vpar->synchro.i_type = SynchroType( p_vpar->p_fifo ); + + /* We use a fake stream pattern, which is often right. */ + p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p = DEFAULT_NB_P; + p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b = DEFAULT_NB_B; + memset( p_vpar->synchro.p_tau, 0, 4 * sizeof(mtime_t) ); + memset( p_vpar->synchro.pi_meaningful, 0, 4 * sizeof(unsigned int) ); + p_vpar->synchro.b_dropped_last = 0; + p_vpar->synchro.current_pts = mdate() + DEFAULT_PTS_DELAY; + p_vpar->synchro.backward_pts = 0; + p_vpar->synchro.i_current_period = p_vpar->synchro.i_backward_period = 0; + p_vpar->synchro.i_trashed_pic = p_vpar->synchro.i_not_chosen_pic = + p_vpar->synchro.i_pic = 0; +} + +/***************************************************************************** + * vpar_SynchroChoose : Decide whether we will decode a picture or not + *****************************************************************************/ +vlc_bool_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type, + int i_structure ) +{ + /* For clarity reasons, we separated the special synchros code from the + * mathematical synchro */ + + if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT ) + { + switch( i_coding_type ) + { + case I_CODING_TYPE: + /* I, IP, IP+, IPB */ + if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus ) + { + p_vpar->synchro.b_dropped_last = 1; + } + return( 1 ); + + case P_CODING_TYPE: + if( p_vpar->synchro.i_type == VPAR_SYNCHRO_I ) /* I */ + { + return( 0 ); + } + + if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus ) /* I+ */ + { + if( p_vpar->synchro.b_dropped_last ) + { + p_vpar->synchro.b_dropped_last = 0; + return( 1 ); + } + else + { + return( 0 ); + } + } + + return( 1 ); /* IP, IP+, IPB */ + + case B_CODING_TYPE: + if( p_vpar->synchro.i_type <= VPAR_SYNCHRO_IP ) /* I, IP */ + { + return( 0 ); + } + else if( p_vpar->synchro.i_type == VPAR_SYNCHRO_IPB ) /* IPB */ + { + return( 1 ); + } + + p_vpar->synchro.b_dropped_last ^= 1; /* IP+ */ + return( !p_vpar->synchro.b_dropped_last ); + } + return( 0 ); /* never reached but gcc yells at me */ + } + else + { +#define TAU_PRIME( coding_type ) (p_vpar->synchro.p_tau[(coding_type)] \ + + (p_vpar->synchro.p_tau[(coding_type)] >> 1) \ + + tau_yuv) +#define S p_vpar->synchro + /* VPAR_SYNCHRO_DEFAULT */ + mtime_t now, period, tau_yuv; + mtime_t pts = 0; + vlc_bool_t b_decode = 0; + + now = mdate(); + period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate + * p_vpar->sequence.i_current_rate / DEFAULT_RATE; + + vlc_mutex_lock( &p_vpar->p_vout->change_lock ); + tau_yuv = p_vpar->p_vout->render_time; + vlc_mutex_unlock( &p_vpar->p_vout->change_lock ); + + switch( i_coding_type ) + { + case I_CODING_TYPE: + if( S.backward_pts ) + { + pts = S.backward_pts; + } + else + { + /* displaying order : B B P B B I + * ^ ^ + * | +- current picture + * +- current PTS + */ + pts = S.current_pts + period * (S.i_n_b + 2); + } + + if( (1 + S.i_n_p * (S.i_n_b + 1)) * period > + S.p_tau[I_CODING_TYPE] ) + { + b_decode = 1; + } + else + { + b_decode = (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA); + } + if( !b_decode ) + msg_Warn( p_vpar->p_fifo, + "synchro trashing I (%lld)", pts - now ); + break; + + case P_CODING_TYPE: + if( S.backward_pts ) + { + pts = S.backward_pts; + } + else + { + pts = S.current_pts + period * (S.i_n_b + 1); + } + + if( (1 + S.i_n_p * (S.i_n_b + 1)) * period > + S.p_tau[I_CODING_TYPE] ) + { + if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] ) + { + /* Security in case we're _really_ late */ + b_decode = (pts - now > 0); + } + else + { + b_decode = (pts - now) > (TAU_PRIME(P_CODING_TYPE) + DELTA); + /* next I */ + b_decode &= (pts - now + + period + * ( (S.i_n_p - S.i_eta_p) * (1 + S.i_n_b) - 1 )) + > (TAU_PRIME(P_CODING_TYPE) + + TAU_PRIME(I_CODING_TYPE) + DELTA); + } + } + else + { + b_decode = 0; + } + break; + + case B_CODING_TYPE: + pts = S.current_pts; + + if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] ) + { + b_decode = (pts - now) > (TAU_PRIME(B_CODING_TYPE) + DELTA); + } + else + { + b_decode = 0; + } + } + + if( !b_decode ) + { + S.i_not_chosen_pic++; + } + return( b_decode ); +#undef S +#undef TAU_PRIME + } +} + +/***************************************************************************** + * vpar_SynchroTrash : Update counters when we trash a picture + *****************************************************************************/ +void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type, + int i_structure ) +{ + p_vpar->synchro.i_trashed_pic++; +} + +/***************************************************************************** + * vpar_SynchroDecode : Update timers when we decide to decode a picture + *****************************************************************************/ +void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type, + int i_structure ) +{ + p_vpar->synchro.decoding_start = mdate(); +} + +/***************************************************************************** + * vpar_SynchroEnd : Called when the image is totally decoded + *****************************************************************************/ +void vpar_SynchroEnd( vpar_thread_t * p_vpar, int i_coding_type, + int i_structure, int i_garbage ) +{ + mtime_t tau; + + if( !i_garbage ) + { + tau = mdate() - p_vpar->synchro.decoding_start; + + /* If duration too high, something happened (pause ?), so don't + * take it into account. */ + if( tau < 3 * p_vpar->synchro.p_tau[i_coding_type] + || !p_vpar->synchro.pi_meaningful[i_coding_type] ) + { + /* Mean with average tau, to ensure stability. */ + p_vpar->synchro.p_tau[i_coding_type] = + (p_vpar->synchro.pi_meaningful[i_coding_type] + * p_vpar->synchro.p_tau[i_coding_type] + tau) + / (p_vpar->synchro.pi_meaningful[i_coding_type] + 1); + if( p_vpar->synchro.pi_meaningful[i_coding_type] < MAX_PIC_AVERAGE ) + { + p_vpar->synchro.pi_meaningful[i_coding_type]++; + } + } + } +} + +/***************************************************************************** + * vpar_SynchroDate : When an image has been decoded, ask for its date + *****************************************************************************/ +mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar ) +{ + /* No need to lock, since PTS are only used by the video parser. */ + return( p_vpar->synchro.current_pts ); +} + +/***************************************************************************** + * vpar_SynchroNewPicture: Update stream structure and PTS + *****************************************************************************/ +void vpar_SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type, + int i_repeat_field ) +{ + mtime_t period = 1000000 * 1001 / p_vpar->sequence.i_frame_rate + * p_vpar->sequence.i_current_rate / DEFAULT_RATE; +#if 0 + mtime_t now = mdate(); +#endif + + switch( i_coding_type ) + { + case I_CODING_TYPE: + if( p_vpar->synchro.i_eta_p + && p_vpar->synchro.i_eta_p != p_vpar->synchro.i_n_p ) + { + msg_Warn( p_vpar->p_fifo, + "stream periodicity changed from P[%d] to P[%d]", + p_vpar->synchro.i_n_p, p_vpar->synchro.i_eta_p ); + p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p; + } + p_vpar->synchro.i_eta_p = p_vpar->synchro.i_eta_b = 0; + + if( p_vpar->synchro.i_type == VPAR_SYNCHRO_DEFAULT ) + { + msg_Dbg( p_vpar->p_fifo, "I(%lld) P(%lld)[%d] B(%lld)[%d] YUV(%lld) : trashed %d:%d/%d", + p_vpar->synchro.p_tau[I_CODING_TYPE], + p_vpar->synchro.p_tau[P_CODING_TYPE], + p_vpar->synchro.i_n_p, + p_vpar->synchro.p_tau[B_CODING_TYPE], + p_vpar->synchro.i_n_b, + p_vpar->p_vout->render_time, + p_vpar->synchro.i_not_chosen_pic, + p_vpar->synchro.i_trashed_pic - + p_vpar->synchro.i_not_chosen_pic, + p_vpar->synchro.i_pic ); + p_vpar->synchro.i_trashed_pic = p_vpar->synchro.i_not_chosen_pic + = p_vpar->synchro.i_pic = 0; + } + break; + + case P_CODING_TYPE: + p_vpar->synchro.i_eta_p++; + if( p_vpar->synchro.i_eta_b + && p_vpar->synchro.i_eta_b != p_vpar->synchro.i_n_b ) + { + msg_Warn( p_vpar->p_fifo, + "stream periodicity changed from B[%d] to B[%d]", + p_vpar->synchro.i_n_b, p_vpar->synchro.i_eta_b ); + p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b; + } + p_vpar->synchro.i_eta_b = 0; + break; + case B_CODING_TYPE: + p_vpar->synchro.i_eta_b++; + break; + } + + p_vpar->synchro.current_pts += p_vpar->synchro.i_current_period + * (period >> 1); + +#define PTS_THRESHOLD (period >> 2) + if( i_coding_type == B_CODING_TYPE ) + { + /* A video frame can be displayed 1, 2 or 3 times, according to + * repeat_first_field, top_field_first, progressive_sequence and + * progressive_frame. */ + p_vpar->synchro.i_current_period = i_repeat_field; + + if( p_vpar->sequence.next_pts ) + { + if( p_vpar->sequence.next_pts - p_vpar->synchro.current_pts + > PTS_THRESHOLD + || p_vpar->synchro.current_pts - p_vpar->sequence.next_pts + > PTS_THRESHOLD ) + { + msg_Warn( p_vpar->p_fifo, + "vpar synchro warning: pts != current_date (%lld)", + p_vpar->synchro.current_pts + - p_vpar->sequence.next_pts ); + } + p_vpar->synchro.current_pts = p_vpar->sequence.next_pts; + p_vpar->sequence.next_pts = 0; + } + } + else + { + p_vpar->synchro.i_current_period = p_vpar->synchro.i_backward_period; + p_vpar->synchro.i_backward_period = i_repeat_field; + + if( p_vpar->synchro.backward_pts ) + { + if( p_vpar->sequence.next_dts && + (p_vpar->sequence.next_dts - p_vpar->synchro.backward_pts + > PTS_THRESHOLD + || p_vpar->synchro.backward_pts - p_vpar->sequence.next_dts + > PTS_THRESHOLD) ) + { + msg_Warn( p_vpar->p_fifo, "backward_pts != dts (%lld)", + p_vpar->sequence.next_dts + - p_vpar->synchro.backward_pts ); + } + if( p_vpar->synchro.backward_pts - p_vpar->synchro.current_pts + > PTS_THRESHOLD + || p_vpar->synchro.current_pts - p_vpar->synchro.backward_pts + > PTS_THRESHOLD ) + { + msg_Warn( p_vpar->p_fifo, + "backward_pts != current_pts (%lld)", + p_vpar->synchro.current_pts + - p_vpar->synchro.backward_pts ); + } + p_vpar->synchro.current_pts = p_vpar->synchro.backward_pts; + p_vpar->synchro.backward_pts = 0; + } + else if( p_vpar->sequence.next_dts ) + { + if( p_vpar->sequence.next_dts - p_vpar->synchro.current_pts + > PTS_THRESHOLD + || p_vpar->synchro.current_pts - p_vpar->sequence.next_dts + > PTS_THRESHOLD ) + { + msg_Warn( p_vpar->p_fifo, "dts != current_pts (%lld)", + p_vpar->synchro.current_pts + - p_vpar->sequence.next_dts ); + } + /* By definition of a DTS. */ + p_vpar->synchro.current_pts = p_vpar->sequence.next_dts; + p_vpar->sequence.next_dts = 0; + } + + if( p_vpar->sequence.next_pts ) + { + /* Store the PTS for the next time we have to date an I picture. */ + p_vpar->synchro.backward_pts = p_vpar->sequence.next_pts; + p_vpar->sequence.next_pts = 0; + } + } +#undef PTS_THRESHOLD + +#if 0 + /* Removed for incompatibility with slow motion */ + if( p_vpar->synchro.current_pts + DEFAULT_PTS_DELAY < now ) + { + /* We cannot be _that_ late, something must have happened, reinit + * the dates. */ + msg_Warn( p_vpar->p_fifo, "PTS << now (%lld), resetting", + now - p_vpar->synchro.current_pts - DEFAULT_PTS_DELAY ); + p_vpar->synchro.current_pts = now + DEFAULT_PTS_DELAY; + } + if( p_vpar->synchro.backward_pts + && p_vpar->synchro.backward_pts + DEFAULT_PTS_DELAY < now ) + { + /* The same. */ + p_vpar->synchro.backward_pts = 0; + } +#endif + + p_vpar->synchro.i_pic++; +} + +/***************************************************************************** + * SynchroType: Get the user's synchro type + ***************************************************************************** + * This function is called at initialization. + *****************************************************************************/ +static int SynchroType( decoder_fifo_t *p_this ) +{ + char psz_synchro_tmp[5]; + char * psz_synchro = config_GetPsz( p_this, "vpar-synchro" ); + + if( psz_synchro == NULL ) + { + return VPAR_SYNCHRO_DEFAULT; + } + + strncpy( psz_synchro_tmp, psz_synchro, 5); + free( psz_synchro ); + psz_synchro = psz_synchro_tmp; + + switch( *psz_synchro++ ) + { + case 'i': + case 'I': + switch( *psz_synchro++ ) + { + case '\0': + return VPAR_SYNCHRO_I; + + case '+': + if( *psz_synchro ) return 0; + return VPAR_SYNCHRO_Iplus; + + case 'p': + case 'P': + switch( *psz_synchro++ ) + { + case '\0': + return VPAR_SYNCHRO_IP; + + case '+': + if( *psz_synchro ) return 0; + return VPAR_SYNCHRO_IPplus; + + case 'b': + case 'B': + if( *psz_synchro ) return 0; + return VPAR_SYNCHRO_IPB; + + default: + return VPAR_SYNCHRO_DEFAULT; + + } + + default: + return VPAR_SYNCHRO_DEFAULT; + } + } + + return VPAR_SYNCHRO_DEFAULT; +} + diff --git a/modules/codec/spdif/.cvsignore b/modules/codec/spdif/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/spdif/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/spdif/Makefile b/modules/codec/spdif/Makefile new file mode 100644 index 0000000000..d5706048c4 --- /dev/null +++ b/modules/codec/spdif/Makefile @@ -0,0 +1 @@ +spdif_SOURCES = spdif.c diff --git a/modules/codec/spdif/spdif.c b/modules/codec/spdif/spdif.c new file mode 100644 index 0000000000..353a7bc4c8 --- /dev/null +++ b/modules/codec/spdif/spdif.c @@ -0,0 +1,431 @@ +/***************************************************************************** + * spdif.c: A52 pass-through to external decoder with enabled soundcard + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: spdif.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Stéphane Borel + * Juha Yrjola + * German Gomez Garcia + * + * 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 +#include +#include /* memcpy() */ +#include + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "spdif.h" + +/**************************************************************************** + * Local prototypes + ****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); + +static int InitThread ( spdif_thread_t * ); +static void EndThread ( spdif_thread_t * ); +static void BitstreamCallback ( bit_stream_t *, vlc_bool_t ); + +int parse_syncinfo ( spdif_thread_t * ); + +/**************************************************************************** + * Local structures and tables + ****************************************************************************/ +static const frame_size_t p_frame_size_code[64] = +{ + { 32 ,{64 ,69 ,96 } }, + { 32 ,{64 ,70 ,96 } }, + { 40 ,{80 ,87 ,120 } }, + { 40 ,{80 ,88 ,120 } }, + { 48 ,{96 ,104 ,144 } }, + { 48 ,{96 ,105 ,144 } }, + { 56 ,{112 ,121 ,168 } }, + { 56 ,{112 ,122 ,168 } }, + { 64 ,{128 ,139 ,192 } }, + { 64 ,{128 ,140 ,192 } }, + { 80 ,{160 ,174 ,240 } }, + { 80 ,{160 ,175 ,240 } }, + { 96 ,{192 ,208 ,288 } }, + { 96 ,{192 ,209 ,288 } }, + { 112 ,{224 ,243 ,336 } }, + { 112 ,{224 ,244 ,336 } }, + { 128 ,{256 ,278 ,384 } }, + { 128 ,{256 ,279 ,384 } }, + { 160 ,{320 ,348 ,480 } }, + { 160 ,{320 ,349 ,480 } }, + { 192 ,{384 ,417 ,576 } }, + { 192 ,{384 ,418 ,576 } }, + { 224 ,{448 ,487 ,672 } }, + { 224 ,{448 ,488 ,672 } }, + { 256 ,{512 ,557 ,768 } }, + { 256 ,{512 ,558 ,768 } }, + { 320 ,{640 ,696 ,960 } }, + { 320 ,{640 ,697 ,960 } }, + { 384 ,{768 ,835 ,1152 } }, + { 384 ,{768 ,836 ,1152 } }, + { 448 ,{896 ,975 ,1344 } }, + { 448 ,{896 ,976 ,1344 } }, + { 512 ,{1024 ,1114 ,1536 } }, + { 512 ,{1024 ,1115 ,1536 } }, + { 576 ,{1152 ,1253 ,1728 } }, + { 576 ,{1152 ,1254 ,1728 } }, + { 640 ,{1280 ,1393 ,1920 } }, + { 640 ,{1280 ,1394 ,1920 } } +}; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("SPDIF pass-through A52 decoder") ); + set_capability( "decoder", 0 ); + set_callbacks( OpenDecoder, NULL ); + add_shortcut( "pass_through" ); + add_shortcut( "pass" ); +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: the whole thing + **************************************************************************** + * This function is called just after the thread is launched. + ****************************************************************************/ +static int RunDecoder( decoder_fifo_t *p_fifo ) +{ + spdif_thread_t * p_spdif; + mtime_t i_frame_time; + vlc_bool_t b_sync; + /* PTS of the current frame */ + mtime_t i_current_pts = 0; + u16 i_length; + + /* Allocate the memory needed to store the thread's structure */ + p_spdif = malloc( sizeof(spdif_thread_t) ); + + if( p_spdif == NULL ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + + p_spdif->p_fifo = p_fifo; + + if (InitThread( p_spdif ) ) + { + + if( p_fifo->b_error ) + { + msg_Err( p_fifo, "could not initialize thread" ); + } + + DecoderError( p_fifo ); + free( p_spdif ); + return( -1 ); + } + + /* Compute the theorical duration of an A52 frame */ + i_frame_time = 1000000 * A52_FRAME_SIZE / + p_spdif->info.i_sample_rate; + i_length = p_spdif->info.i_frame_size; + + while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error ) + { + p_spdif->p_bytes[0] = 0x0b; + p_spdif->p_bytes[1] = 0x77; + + /* Handle the dates */ + if( p_spdif->i_real_pts ) + { + mtime_t i_delta = p_spdif->i_real_pts - i_current_pts - + i_frame_time; + if( i_delta > i_frame_time || i_delta < -i_frame_time ) + { + msg_Warn( p_fifo, + "date discontinuity (%d)", i_delta ); + } + i_current_pts = p_spdif->i_real_pts; + p_spdif->i_real_pts = 0; + } + else + { + i_current_pts += i_frame_time; + } + + // wait a little to avoid an input flood from the a52 input + mwait( i_current_pts - 500000 ); + + vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock); + + p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->i_end_frame] = + i_current_pts; + + p_spdif->p_aout_fifo->i_end_frame = + (p_spdif->p_aout_fifo->i_end_frame + 1 ) & AOUT_FIFO_SIZE; + + p_spdif->p_bytes = ((u8*)(p_spdif->p_aout_fifo->buffer)) + + (p_spdif->p_aout_fifo->i_end_frame * i_length ); + + vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock); + + /* Find syncword again in case of stream discontinuity */ + /* Here we have p_spdif->i_pts == 0 + * Therefore a non-zero value after a call to GetBits() means the PES + * has changed. */ + b_sync = 0; + while( !p_spdif->p_fifo->b_die + && !p_spdif->p_fifo->b_error + && !b_sync ) + { + while( !p_spdif->p_fifo->b_die + && !p_spdif->p_fifo->b_error + && GetBits( &p_spdif->bit_stream, 8 ) != 0x0b ); + p_spdif->i_real_pts = p_spdif->i_pts; + p_spdif->i_pts = 0; + b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 ); + } + RemoveBits( &p_spdif->bit_stream, 8 ); + + /* Read data from bitstream */ + GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + 2, i_length - 2 ); + } + + /* If b_error is set, the spdif thread enters the error loop */ + if( p_spdif->p_fifo->b_error ) + { + DecoderError( p_spdif->p_fifo ); + } + + /* End of the spdif decoder thread */ + EndThread( p_spdif ); + + return( 0 ); +} + +/**************************************************************************** + * InitThread: initialize thread data and create output fifo + ****************************************************************************/ +static int InitThread( spdif_thread_t * p_spdif ) +{ + vlc_bool_t b_sync = 0; + + /* Temporary buffer to store first A52 frame */ + p_spdif->p_bytes = malloc( SPDIF_FRAME_SIZE ); + + if( p_spdif->p_bytes == NULL ) + { + free( p_spdif->p_bytes ); + return( -1 ); + } + + /* + * Initialize the thread properties + */ + p_spdif->p_fifo = p_spdif->p_fifo; + + InitBitstream( &p_spdif->bit_stream, p_spdif->p_fifo, + BitstreamCallback, (void*)p_spdif ); + + /* Find syncword */ + while( !p_spdif->p_fifo->b_die + && !p_spdif->p_fifo->b_error + && !b_sync ) + { + while( !p_spdif->p_fifo->b_die + && !p_spdif->p_fifo->b_error + && GetBits( &p_spdif->bit_stream, 8 ) != 0x0b ); + p_spdif->i_real_pts = p_spdif->i_pts; + p_spdif->i_pts = 0; + b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 ); + } + + if( p_spdif->p_fifo->b_die || p_spdif->p_fifo->b_error ) + { + return -1; + } + + RemoveBits( &p_spdif->bit_stream, 8 ); + + /* Check stream properties */ + if( parse_syncinfo( p_spdif ) < 0 ) + { + msg_Err( p_spdif->p_fifo, "stream not valid" ); + + return( -1 ); + } + + /* Check that we can handle the rate + * FIXME: we should check that we have the same rate for all fifos + * but all rates should be supported by the decoder (32, 44.1, 48) */ + if( p_spdif->info.i_sample_rate != 48000 ) + { + msg_Err( p_spdif->p_fifo, + "only 48000 Hz streams tested, expect weird things!" ); + } + + /* The audio output need to be ready for an A52 stream */ + p_spdif->i_previous_format = config_GetInt( p_spdif->p_fifo, + "audio-format" ); + config_PutInt( p_spdif->p_fifo, "audio-format", 8 ); + + /* Creating the audio output fifo */ + p_spdif->p_aout_fifo = + aout_CreateFifo( p_spdif->p_fifo, AOUT_FIFO_SPDIF, + 1, p_spdif->info.i_sample_rate, + p_spdif->info.i_frame_size, NULL ); + + if( p_spdif->p_aout_fifo == NULL ) + { + return( -1 ); + } + + msg_Dbg( p_spdif->p_fifo, "aout fifo #%d created", + p_spdif->p_aout_fifo->i_fifo ); + + /* Put read data into fifo */ + memcpy( (u8*)(p_spdif->p_aout_fifo->buffer) + + (p_spdif->p_aout_fifo->i_end_frame * + p_spdif->info.i_frame_size ), + p_spdif->p_bytes, sizeof(sync_frame_t) ); + free( p_spdif->p_bytes ); + p_spdif->p_bytes = ((u8*)(p_spdif->p_aout_fifo->buffer) + + (p_spdif->p_aout_fifo->i_end_frame * + p_spdif->info.i_frame_size )); + + GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + sizeof(sync_frame_t), + p_spdif->info.i_frame_size - sizeof(sync_frame_t) ); + + return( 0 ); +} + +/***************************************************************************** + * EndThread : spdif thread destruction + *****************************************************************************/ +static void EndThread( spdif_thread_t * p_spdif ) +{ + /* If the audio output fifo was created, we destroy it */ + if( p_spdif->p_aout_fifo != NULL ) + { + aout_DestroyFifo( p_spdif->p_aout_fifo ); + + /* Make sure the output thread leaves the NextFrame() function */ + vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) ); + vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) ); + vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) ); + + } + + /* restore previous setting for output format */ + config_PutInt( p_spdif->p_fifo, "audio-format", + p_spdif->i_previous_format ); + + /* Destroy descriptor */ + free( p_spdif ); +} + +/***************************************************************************** + * 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 ) +{ + spdif_thread_t * p_spdif; + + if( b_new_pes ) + { + p_spdif = (spdif_thread_t *)p_bit_stream->p_callback_arg; + +/* p_bit_stream->p_byte += 3; */ + + p_spdif->i_pts = + p_bit_stream->p_decoder_fifo->p_first->i_pts; + p_bit_stream->p_decoder_fifo->p_first->i_pts = 0; + } +} + +/**************************************************************************** + * parse_syncinfo: parse A52 sync info + ****************************************************************************/ +int parse_syncinfo( spdif_thread_t *p_spdif ) +{ + int p_sample_rates[4] = { 48000, 44100, 32000, -1 }; + int i_frame_rate_code; + int i_frame_size_code; + sync_frame_t * p_sync_frame; + + /* Read sync frame */ + GetChunk( &p_spdif->bit_stream, p_spdif->p_bytes + 2, + sizeof(sync_frame_t) - 2 ); + if( p_spdif->p_fifo->b_die ) return -1; + + p_sync_frame = (sync_frame_t*)p_spdif->p_bytes; + + /* Compute frame rate */ + i_frame_rate_code = (p_sync_frame->syncinfo.code >> 6) & 0x03; + p_spdif->info.i_sample_rate = p_sample_rates[i_frame_rate_code]; + if( p_spdif->info.i_sample_rate == -1 ) + { + return -1; + } + + /* Compute frame size */ + i_frame_size_code = p_sync_frame->syncinfo.code & 0x3f; + p_spdif->info.i_frame_size = 2 * + p_frame_size_code[i_frame_size_code].i_frame_size[i_frame_rate_code]; + p_spdif->info.i_bit_rate = + p_frame_size_code[i_frame_size_code].i_bit_rate; + + if( ( ( p_sync_frame->bsi.bsidmod >> 3 ) & 0x1f ) != 0x08 ) + { + return -1; + } + + p_spdif->info.i_bs_mod = p_sync_frame->bsi.bsidmod & 0x7; + + return 0; +} diff --git a/modules/codec/spdif/spdif.h b/modules/codec/spdif/spdif.h new file mode 100644 index 0000000000..39b5019c04 --- /dev/null +++ b/modules/codec/spdif/spdif.h @@ -0,0 +1,93 @@ +/***************************************************************************** + * spdif.h: header for A52 pass-through + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: spdif.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Stéphane Borel + * + * 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. + ****************************************************************************/ + +/**************************************************************************** + * information about A52 frame + ****************************************************************************/ +typedef struct sync_frame_s +{ + struct syncinfo + { + u8 syncword[2]; + u8 crc1[2]; + u8 code; + } syncinfo; + + struct bsi + { + u8 bsidmod; + u8 acmod; + } bsi; +} sync_frame_t; + +typedef struct frame_size_s +{ + u16 i_bit_rate; + u16 i_frame_size[3]; +} frame_size_t; + +typedef struct info_s +{ + int i_bit_rate; + int i_frame_size; + int i_sample_rate; + int i_bs_mod; +} info_t; + +/***************************************************************************** + * spdif_thread_t : A52 pass-through thread descriptor + *****************************************************************************/ +typedef struct spdif_thread_s +{ + /* + * 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; + + /* + * Decoder properties + */ + info_t info; + u8 * p_bytes; + + /* current pes date */ + mtime_t i_pts; + mtime_t i_real_pts; + + /* + * Output properties + */ + int i_previous_format; + aout_fifo_t * p_aout_fifo; /* stores the decompressed audio frames */ + +} spdif_thread_t; + diff --git a/modules/codec/spudec/.cvsignore b/modules/codec/spudec/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/codec/spudec/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/codec/spudec/Makefile b/modules/codec/spudec/Makefile new file mode 100644 index 0000000000..51c3d309a3 --- /dev/null +++ b/modules/codec/spudec/Makefile @@ -0,0 +1 @@ +spudec_SOURCES = spudec.c diff --git a/modules/codec/spudec/spudec.c b/modules/codec/spudec/spudec.c new file mode 100644 index 0000000000..a2712a5884 --- /dev/null +++ b/modules/codec/spudec/spudec.c @@ -0,0 +1,1210 @@ +/***************************************************************************** + * spudec.c : spu decoder thread + ***************************************************************************** + * Copyright (C) 2000-2001 VideoLAN + * $Id: spudec.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Samuel Hocevar + * Rudolf Cornelissen + * + * 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 /* malloc(), free() */ +#include /* memcpy(), memset() */ + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include /* getpid() */ +#endif + +#ifdef WIN32 /* getpid() for win32 is located in process.h */ +# include +#endif + +#include "spudec.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static int RunDecoder ( decoder_fifo_t * ); +static int InitThread ( spudec_thread_t * ); +static void EndThread ( spudec_thread_t * ); + +static int SyncPacket ( spudec_thread_t * ); +static void ParsePacket ( spudec_thread_t * ); +static int ParseControlSequences( spudec_thread_t *, subpicture_t * ); +static int ParseRLE ( spudec_thread_t *, subpicture_t *, u8 * ); +static void RenderSPU ( vout_thread_t *, picture_t *, + const subpicture_t * ); +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin(); + set_description( _("DVD subtitles decoder module") ); + set_capability( "decoder", 50 ); + 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 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('s','p','u',' ') ) + { + p_fifo->pf_run = RunDecoder; + return VLC_SUCCESS; + } + + return VLC_EGENERIC; +} + +/***************************************************************************** + * RunDecoder: this function is called just after the thread is created + *****************************************************************************/ +static int RunDecoder( decoder_fifo_t * p_fifo ) +{ + spudec_thread_t * p_spudec; + + /* Allocate the memory needed to store the thread's structure */ + p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) ); + + if ( p_spudec == NULL ) + { + msg_Err( p_fifo, "out of memory" ); + DecoderError( p_fifo ); + return( -1 ); + } + + /* + * Initialize the thread properties + */ + p_spudec->p_vout = NULL; + p_spudec->p_fifo = p_fifo; + + /* + * Initialize thread and free configuration + */ + p_spudec->p_fifo->b_error = InitThread( p_spudec ); + + /* + * Main loop - it is not executed if an error occured during + * initialization + */ + while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) ) + { + if( !SyncPacket( p_spudec ) ) + { + ParsePacket( p_spudec ); + } + } + + /* + * Error loop + */ + if( p_spudec->p_fifo->b_error ) + { + DecoderError( p_spudec->p_fifo ); + + /* End of thread */ + EndThread( p_spudec ); + return -1; + } + + /* End of thread */ + EndThread( p_spudec ); + return 0; +} + +/* following functions are local */ + +/***************************************************************************** + * InitThread: initialize spu decoder thread + ***************************************************************************** + * This function is called from RunThread and performs the second step of the + * initialization. It returns 0 on success. Note that the thread's flag are not + * modified inside this function. + *****************************************************************************/ +static int InitThread( spudec_thread_t *p_spudec ) +{ + /* Find an available video output */ + do + { + if( p_spudec->p_fifo->b_die || p_spudec->p_fifo->b_error ) + { + return -1; + } + + p_spudec->p_vout = vlc_object_find( p_spudec->p_fifo, VLC_OBJECT_VOUT, + FIND_ANYWHERE ); + + if( p_spudec->p_vout ) + { + break; + } + + msleep( VOUT_OUTMEM_SLEEP ); + } + while( 1 ); + + InitBitstream( &p_spudec->bit_stream, p_spudec->p_fifo, NULL, NULL ); + + /* Mark thread as running and return */ + return 0; +} + +/***************************************************************************** + * EndThread: thread destruction + ***************************************************************************** + * This function is called when the thread ends after a sucessful + * initialization. + *****************************************************************************/ +static void EndThread( spudec_thread_t *p_spudec ) +{ + if( p_spudec->p_vout != NULL + && p_spudec->p_vout->p_subpicture != NULL ) + { + subpicture_t * p_subpic; + int i_subpic; + + for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ ) + { + p_subpic = &p_spudec->p_vout->p_subpicture[i_subpic]; + + if( p_subpic != NULL && + ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) + || ( p_subpic->i_status == READY_SUBPICTURE ) ) ) + { + vout_DestroySubPicture( p_spudec->p_vout, p_subpic ); + } + } + + vlc_object_release( p_spudec->p_vout ); + } + + free( p_spudec ); +} + +/***************************************************************************** + * SyncPacket: get in sync with the stream + ***************************************************************************** + * This function makes a few sanity checks and returns 0 if it looks like we + * are at the beginning of a subpicture packet. + *****************************************************************************/ +static int SyncPacket( spudec_thread_t *p_spudec ) +{ + /* Re-align the buffer on an 8-bit boundary */ + RealignBits( &p_spudec->bit_stream ); + + /* The total SPU packet size, often bigger than a PS packet */ + p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 ); + + /* The RLE stuff size (remove 4 because we just read 32 bits) */ + p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4; + + /* If the values we got are a bit strange, skip packet */ + if( !p_spudec->i_spu_size + || ( p_spudec->i_rle_size >= p_spudec->i_spu_size ) ) + { + return( 1 ); + } + + RemoveBits( &p_spudec->bit_stream, 16 ); + + return( 0 ); +} + +/***************************************************************************** + * ParsePacket: parse an SPU packet and send it to the video output + ***************************************************************************** + * This function parses the SPU packet and, if valid, sends it to the + * video output. + *****************************************************************************/ +static void ParsePacket( spudec_thread_t *p_spudec ) +{ + subpicture_t * p_spu; + u8 * p_src; + unsigned int i_offset; + + msg_Dbg( p_spudec->p_fifo, "trying to gather a 0x%.2x long subtitle", + p_spudec->i_spu_size ); + + /* We cannot display a subpicture with no date */ + if( p_spudec->p_fifo->p_first->i_pts == 0 ) + { + msg_Warn( p_spudec->p_fifo, "subtitle without a date" ); + return; + } + + /* Allocate the subpicture internal data. */ + p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE, + sizeof( subpicture_sys_t ) + + p_spudec->i_rle_size * 4 ); + /* Rationale for the "p_spudec->i_rle_size * 4": we are going to + * expand the RLE stuff so that we won't need to read nibbles later + * on. This will speed things up a lot. Plus, we'll only need to do + * this stupid interlacing stuff once. */ + + if( p_spu == NULL ) + { + return; + } + + /* Fill the p_spu structure */ + p_spu->pf_render = RenderSPU; + p_spu->p_sys->p_data = (u8*)p_spu->p_sys + sizeof( subpicture_sys_t ); + p_spu->p_sys->b_palette = 0; + + /* Get display time now. If we do it later, we may miss the PTS. */ + p_spu->p_sys->i_pts = p_spudec->p_fifo->p_first->i_pts; + + /* Allocate the temporary buffer we will parse */ + p_src = malloc( p_spudec->i_rle_size ); + + if( p_src == NULL ) + { + msg_Err( p_spudec->p_fifo, "out of memory" ); + vout_DestroySubPicture( p_spudec->p_vout, p_spu ); + return; + } + + /* Get RLE data */ + for( i_offset = 0; i_offset < p_spudec->i_rle_size; + i_offset += SPU_CHUNK_SIZE ) + { + GetChunk( &p_spudec->bit_stream, p_src + i_offset, + ( i_offset + SPU_CHUNK_SIZE < p_spudec->i_rle_size ) ? + SPU_CHUNK_SIZE : p_spudec->i_rle_size - i_offset ); + + /* Abort subtitle parsing if we were requested to stop */ + if( p_spudec->p_fifo->b_die ) + { + free( p_src ); + vout_DestroySubPicture( p_spudec->p_vout, p_spu ); + return; + } + } + +#if 0 + /* Dump the subtitle info */ + intf_WarnHexDump( 5, p_spu->p_sys->p_data, p_spudec->i_rle_size ); +#endif + + /* Getting the control part */ + if( ParseControlSequences( p_spudec, p_spu ) ) + { + /* There was a parse error, delete the subpicture */ + free( p_src ); + vout_DestroySubPicture( p_spudec->p_vout, p_spu ); + return; + } + + /* At this point, no more GetBit() command is needed, so we have all + * the data we need to tell whether the subtitle is valid. Thus we + * try to display it and we ignore b_die. */ + + if( ParseRLE( p_spudec, p_spu, p_src ) ) + { + /* There was a parse error, delete the subpicture */ + free( p_src ); + vout_DestroySubPicture( p_spudec->p_vout, p_spu ); + return; + } + + msg_Dbg( p_spudec->p_fifo, "total size: 0x%x, RLE offsets: 0x%x 0x%x", + p_spudec->i_spu_size, + p_spu->p_sys->pi_offset[0], p_spu->p_sys->pi_offset[1] ); + + /* SPU is finished - we can ask the video output to display it */ + vout_DisplaySubPicture( p_spudec->p_vout, p_spu ); + + /* Clean up */ + free( p_src ); +} + +/***************************************************************************** + * ParseControlSequences: parse all SPU control sequences + ***************************************************************************** + * This is the most important part in SPU decoding. We get dates, palette + * information, coordinates, and so on. For more information on the + * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html + *****************************************************************************/ +static int ParseControlSequences( spudec_thread_t *p_spudec, + subpicture_t * p_spu ) +{ + /* Our current index in the SPU packet */ + int i_index = p_spudec->i_rle_size + 4; + + /* The next start-of-control-sequence index and the previous one */ + int i_next_seq, i_cur_seq; + + /* Command time and date */ + u8 i_command; + int i_date; + + int i, pi_alpha[4]; + + /* XXX: temporary variables */ + vlc_bool_t b_force_display = 0; + + /* Initialize the structure */ + p_spu->i_start = p_spu->i_stop = 0; + p_spu->b_ephemer = 0; + + do + { + /* Get the control sequence date */ + i_date = GetBits( &p_spudec->bit_stream, 16 ); + + /* Next offset */ + i_cur_seq = i_index; + i_next_seq = GetBits( &p_spudec->bit_stream, 16 ); + + /* Skip what we just read */ + i_index += 4; + + do + { + i_command = GetBits( &p_spudec->bit_stream, 8 ); + i_index++; + + switch( i_command ) + { + case SPU_CMD_FORCE_DISPLAY: + + /* 00 (force displaying) */ + p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 ); + b_force_display = 1; + + break; + + /* Convert the dates in seconds to PTS values */ + case SPU_CMD_START_DISPLAY: + + /* 01 (start displaying) */ + p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 ); + + break; + + case SPU_CMD_STOP_DISPLAY: + + /* 02 (stop displaying) */ + p_spu->i_stop = p_spu->p_sys->i_pts + ( i_date * 11000 ); + + break; + + case SPU_CMD_SET_PALETTE: + + /* 03xxxx (palette) */ + if( p_spudec->p_fifo->p_demux_data && + *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF ) + { + u32 i_color; + + p_spu->p_sys->b_palette = 1; + for( i = 0; i < 4 ; i++ ) + { + i_color = ((u32*)((char*)p_spudec->p_fifo-> + p_demux_data + sizeof(int)))[ + GetBits(&p_spudec->bit_stream, 4) ]; + + /* FIXME: this job should be done sooner */ +#ifndef WORDS_BIGENDIAN + p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>16) & 0xff; + p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>0) & 0xff; + p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>8) & 0xff; +#else + p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>8) & 0xff; + p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>24) & 0xff; + p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>16) & 0xff; +#endif + } + } + else + { + RemoveBits( &p_spudec->bit_stream, 16 ); + } + i_index += 2; + + break; + + case SPU_CMD_SET_ALPHACHANNEL: + + /* 04xxxx (alpha channel) */ + pi_alpha[3] = GetBits( &p_spudec->bit_stream, 4 ); + pi_alpha[2] = GetBits( &p_spudec->bit_stream, 4 ); + pi_alpha[1] = GetBits( &p_spudec->bit_stream, 4 ); + pi_alpha[0] = GetBits( &p_spudec->bit_stream, 4 ); + + /* Ignore blank alpha palette. Sometimes spurious blank + * alpha palettes are present - dunno why. */ + if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] ) + { + p_spu->p_sys->pi_alpha[0] = pi_alpha[0]; + p_spu->p_sys->pi_alpha[1] = pi_alpha[1]; + p_spu->p_sys->pi_alpha[2] = pi_alpha[2]; + p_spu->p_sys->pi_alpha[3] = pi_alpha[3]; + } + else + { + msg_Warn( p_spudec->p_fifo, + "ignoring blank alpha palette" ); + } + + i_index += 2; + + break; + + case SPU_CMD_SET_COORDINATES: + + /* 05xxxyyyxxxyyy (coordinates) */ + p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 ); + p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 ) + - p_spu->i_x + 1; + + p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 ); + p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 ) + - p_spu->i_y + 1; + + i_index += 6; + + break; + + case SPU_CMD_SET_OFFSETS: + + /* 06xxxxyyyy (byte offsets) */ + p_spu->p_sys->pi_offset[0] = + GetBits( &p_spudec->bit_stream, 16 ) - 4; + + p_spu->p_sys->pi_offset[1] = + GetBits( &p_spudec->bit_stream, 16 ) - 4; + + i_index += 4; + + break; + + case SPU_CMD_END: + + /* ff (end) */ + break; + + default: + + /* xx (unknown command) */ + msg_Err( p_spudec->p_fifo, "unknown command 0x%.2x", + i_command ); + return( 1 ); + } + + /* We need to check for quit commands here */ + if( p_spudec->p_fifo->b_die ) + { + return( 1 ); + } + + } while( i_command != SPU_CMD_END ); + + } while( i_index == i_next_seq ); + + /* Check that the next sequence index matches the current one */ + if( i_next_seq != i_cur_seq ) + { + msg_Err( p_spudec->p_fifo, "index mismatch (0x%.4x != 0x%.4x)", + i_next_seq, i_cur_seq ); + return( 1 ); + } + + if( i_index > p_spudec->i_spu_size ) + { + msg_Err( p_spudec->p_fifo, "uh-oh, we went too far (0x%.4x > 0x%.4x)", + i_index, p_spudec->i_spu_size ); + return( 1 ); + } + + if( !p_spu->i_start ) + { + msg_Err( p_spudec->p_fifo, "no `start display' command" ); + } + + if( !p_spu->i_stop ) + { + /* This subtitle will live for 5 seconds or until the next subtitle */ + p_spu->i_stop = p_spu->i_start + 500 * 11000; + p_spu->b_ephemer = 1; + } + + /* Get rid of padding bytes */ + switch( p_spudec->i_spu_size - i_index ) + { + /* Zero or one padding byte, quite usual */ + case 1: + RemoveBits( &p_spudec->bit_stream, 8 ); + i_index++; + case 0: + break; + + /* More than one padding byte - this is very strange, but + * we can deal with it */ + default: + msg_Warn( p_spudec->p_fifo, + "%i padding bytes, we usually get 0 or 1 of them", + p_spudec->i_spu_size - i_index ); + + while( i_index < p_spudec->i_spu_size ) + { + RemoveBits( &p_spudec->bit_stream, 8 ); + i_index++; + } + + break; + } + + if( b_force_display ) + { + msg_Err( p_spudec->p_fifo, "\"force display\" command" ); + msg_Err( p_spudec->p_fifo, "send mail to if you " + "want to help debugging this" ); + } + + /* Successfully parsed ! */ + return( 0 ); +} + +/***************************************************************************** + * ParseRLE: parse the RLE part of the subtitle + ***************************************************************************** + * This part parses the subtitle graphical data and stores it in a more + * convenient structure for later decoding. For more information on the + * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html + *****************************************************************************/ +static int ParseRLE( spudec_thread_t *p_spudec, + subpicture_t * p_spu, u8 * p_src ) +{ + unsigned int i_code; + + unsigned int i_width = p_spu->i_width; + unsigned int i_height = p_spu->i_height; + unsigned int i_x, i_y; + + u16 *p_dest = (u16 *)p_spu->p_sys->p_data; + + /* The subtitles are interlaced, we need two offsets */ + unsigned int i_id = 0; /* Start on the even SPU layer */ + unsigned int pi_table[ 2 ]; + unsigned int *pi_offset; + + vlc_bool_t b_empty_top = 1, + b_empty_bottom = 0; + unsigned int i_skipped_top = 0, + i_skipped_bottom = 0; + + /* Colormap statistics */ + int i_border = -1; + int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0; + + pi_table[ 0 ] = p_spu->p_sys->pi_offset[ 0 ] << 1; + pi_table[ 1 ] = p_spu->p_sys->pi_offset[ 1 ] << 1; + + for( i_y = 0 ; i_y < i_height ; i_y++ ) + { + pi_offset = pi_table + i_id; + + for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 ) + { + i_code = AddNibble( 0, p_src, pi_offset ); + + if( i_code < 0x04 ) + { + i_code = AddNibble( i_code, p_src, pi_offset ); + + if( i_code < 0x10 ) + { + i_code = AddNibble( i_code, p_src, pi_offset ); + + if( i_code < 0x040 ) + { + i_code = AddNibble( i_code, p_src, pi_offset ); + + if( i_code < 0x0100 ) + { + /* If the 14 first bits are set to 0, then it's a + * new line. We emulate it. */ + if( i_code < 0x0004 ) + { + i_code |= ( i_width - i_x ) << 2; + } + else + { + /* We have a boo boo ! */ + msg_Err( p_spudec->p_fifo, "unknown RLE code " + "0x%.4x", i_code ); + return( 1 ); + } + } + } + } + } + + if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width ) + { + msg_Err( p_spudec->p_fifo, + "out of bounds, %i at (%i,%i) is out of %ix%i", + i_code >> 2, i_x, i_y, i_width, i_height ); + return( 1 ); + } + + /* Try to find the border color */ + if( p_spu->p_sys->pi_alpha[ i_code & 0x3 ] != 0x00 ) + { + i_border = i_code & 0x3; + stats[i_border] += i_code >> 2; + } + + if( (i_code >> 2) == i_width + && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 ) + { + if( b_empty_top ) + { + /* This is a blank top line, we skip it */ + i_skipped_top++; + } + else + { + /* We can't be sure the current lines will be skipped, + * so we store the code just in case. */ + *p_dest++ = i_code; + + b_empty_bottom = 1; + i_skipped_bottom++; + } + } + else + { + /* We got a valid code, store it */ + *p_dest++ = i_code; + + /* Valid code means no blank line */ + b_empty_top = 0; + b_empty_bottom = 0; + i_skipped_bottom = 0; + } + } + + /* Check that we didn't go too far */ + if( i_x > i_width ) + { + msg_Err( p_spudec->p_fifo, "i_x overflowed, %i > %i", + i_x, i_width ); + return( 1 ); + } + + /* Byte-align the stream */ + if( *pi_offset & 0x1 ) + { + (*pi_offset)++; + } + + /* Swap fields */ + i_id = ~i_id & 0x1; + } + + /* We shouldn't get any padding bytes */ + if( i_y < i_height ) + { + msg_Err( p_spudec->p_fifo, "padding bytes found in RLE sequence" ); + msg_Err( p_spudec->p_fifo, "send mail to if you " + "want to help debugging this" ); + + /* Skip them just in case */ + while( i_y < i_height ) + { + *p_dest++ = i_width << 2; + i_y++; + } + + return( 1 ); + } + + msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i", + p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y ); + + /* Crop if necessary */ + if( i_skipped_top || i_skipped_bottom ) + { + p_spu->i_y += i_skipped_top; + p_spu->i_height -= i_skipped_top + i_skipped_bottom; + + msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i", + p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y ); + } + + /* Handle color if no palette was found */ + if( !p_spu->p_sys->b_palette ) + { + int i, i_inner = -1, i_shade = -1; + + /* Set the border color */ + p_spu->p_sys->pi_yuv[i_border][0] = 0x00; + p_spu->p_sys->pi_yuv[i_border][1] = 0x80; + p_spu->p_sys->pi_yuv[i_border][2] = 0x80; + stats[i_border] = 0; + + /* Find the inner colors */ + for( i = 0 ; i < 4 && i_inner == -1 ; i++ ) + { + if( stats[i] ) + { + i_inner = i; + } + } + + for( ; i < 4 && i_shade == -1 ; i++ ) + { + if( stats[i] ) + { + if( stats[i] > stats[i_inner] ) + { + i_shade = i_inner; + i_inner = i; + } + else + { + i_shade = i; + } + } + } + + /* Set the inner color */ + if( i_inner != -1 ) + { + p_spu->p_sys->pi_yuv[i_inner][0] = 0xff; + p_spu->p_sys->pi_yuv[i_inner][1] = 0x80; + p_spu->p_sys->pi_yuv[i_inner][2] = 0x80; + } + + /* Set the anti-aliasing color */ + if( i_shade != -1 ) + { + p_spu->p_sys->pi_yuv[i_shade][0] = 0x80; + p_spu->p_sys->pi_yuv[i_shade][1] = 0x80; + p_spu->p_sys->pi_yuv[i_shade][2] = 0x80; + } + + msg_Dbg( p_spudec->p_fifo, + "using custom palette (border %i, inner %i, shade %i)", + i_border, i_inner, i_shade ); + } + + return( 0 ); +} + +/***************************************************************************** + * RenderSPU: draw an SPU on a picture + ***************************************************************************** + * This is a fast implementation of the subpicture drawing code. The data + * has been preprocessed once, so we don't need to parse the RLE buffer again + * and again. Most sanity checks are already done so that this routine can be + * as fast as possible. + *****************************************************************************/ +static void RenderSPU( vout_thread_t *p_vout, picture_t *p_pic, + const subpicture_t *p_spu ) +{ + /* Common variables */ + u16 p_clut16[4]; + u32 p_clut32[4]; + u8 *p_dest; + u8 *p_destptr = (u8 *)p_dest; + u16 *p_source = (u16 *)p_spu->p_sys->p_data; + + int i_x, i_y; + int i_len, i_color, i_colprecomp, i_destalpha; + u8 i_cnt; + + /* RGB-specific */ + int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext; + + switch( p_vout->output.i_chroma ) + { + /* I420 target, no scaling */ + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + case VLC_FOURCC('Y','V','1','2'): + + p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width + + p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height ); + + /* Draw until we reach the bottom of the subtitle */ + for( i_y = p_spu->i_height * p_pic->Y_PITCH ; + i_y ; + i_y -= p_pic->Y_PITCH ) + { + /* Draw until we reach the end of the line */ + for( i_x = p_spu->i_width ; i_x ; ) + { + /* Get the RLE part, then draw the line */ + i_color = *p_source & 0x3; + i_len = *p_source++ >> 2; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + break; + + case 0x0f: + memset( p_dest - i_x - i_y, + p_spu->p_sys->pi_yuv[i_color][0], i_len ); + break; + + default: + /* To be able to divide by 16 (>>4) we add 1 to the alpha. + * This means Alpha 0 won't be completely transparent, but + * that's handled in a special case above anyway. */ + i_colprecomp = p_spu->p_sys->pi_yuv[i_color][0] + * (p_spu->p_sys->pi_alpha[ i_color ] + 1); + i_destalpha = 15 - p_spu->p_sys->pi_alpha[ i_color ]; + + for ( p_destptr = p_dest - i_x - i_y; + p_destptr < p_dest - i_x - i_y + i_len; + p_destptr++ ) + { + *p_destptr = ( i_colprecomp + + *p_destptr * i_destalpha ) >> 4; + } + break; + + } + i_x -= i_len; + } + } + + break; + + /* RV16 target, scaling */ + case VLC_FOURCC('R','V','1','6'): + + /* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */ + /* FIXME: get this from the DVD */ + for( i_color = 0; i_color < 4; i_color++ ) + { + p_clut16[i_color] = 0x1111 + * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 ); + } + + i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width; + i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height; + + i_width = p_spu->i_width * i_xscale; + i_height = p_spu->i_height * i_yscale; + + p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 2 + /* Add the picture coordinates and the SPU coordinates */ + + ( (p_spu->i_x * i_xscale) >> 6 ) * 2 + + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch; + + /* Draw until we reach the bottom of the subtitle */ + for( i_y = 0 ; i_y < i_height ; ) + { + i_ytmp = i_y >> 6; + i_y += i_yscale; + + /* Check whether we need to draw one line or more than one */ + if( i_ytmp + 1 >= ( i_y >> 6 ) ) + { + /* Just one line : we precalculate i_y >> 6 */ + i_yreal = p_pic->p->i_pitch * i_ytmp; + + /* Draw until we reach the end of the line */ + for( i_x = i_width ; i_x ; ) + { + /* Get the RLE part, then draw the line */ + i_color = *p_source & 0x3; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + i_x -= i_xscale * ( *p_source++ >> 2 ); + break; + + case 0x0f: + i_len = i_xscale * ( *p_source++ >> 2 ); + memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal, + p_clut16[ i_color ], + 2 * ( ( i_len >> 6 ) + 1 ) ); + i_x -= i_len; + break; + + default: + /* FIXME: we should do transparency */ + i_len = i_xscale * ( *p_source++ >> 2 ); + memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal, + p_clut16[ i_color ], + 2 * ( ( i_len >> 6 ) + 1 ) ); + i_x -= i_len; + break; + } + + } + } + else + { + i_yreal = p_pic->p->i_pitch * i_ytmp; + i_ynext = p_pic->p->i_pitch * i_y >> 6; + + /* Draw until we reach the end of the line */ + for( i_x = i_width ; i_x ; ) + { + /* Get the RLE part, then draw as many lines as needed */ + i_color = *p_source & 0x3; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + i_x -= i_xscale * ( *p_source++ >> 2 ); + break; + + case 0x0f: + i_len = i_xscale * ( *p_source++ >> 2 ); + for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; + i_ytmp += p_pic->p->i_pitch ) + { + memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp, + p_clut16[ i_color ], + 2 * ( ( i_len >> 6 ) + 1 ) ); + } + i_x -= i_len; + break; + + default: + /* FIXME: we should do transparency */ + i_len = i_xscale * ( *p_source++ >> 2 ); + for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; + i_ytmp += p_pic->p->i_pitch ) + { + memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp, + p_clut16[ i_color ], + 2 * ( ( i_len >> 6 ) + 1 ) ); + } + i_x -= i_len; + break; + } + } + } + } + + break; + + /* RV32 target, scaling */ + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + + /* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */ + /* FIXME: get this from the DVD */ + for( i_color = 0; i_color < 4; i_color++ ) + { + p_clut32[i_color] = 0x11111111 + * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 ); + } + + i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width; + i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height; + + i_width = p_spu->i_width * i_xscale; + i_height = p_spu->i_height * i_yscale; + + p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4 + /* Add the picture coordinates and the SPU coordinates */ + + ( (p_spu->i_x * i_xscale) >> 6 ) * 4 + + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch; + + /* Draw until we reach the bottom of the subtitle */ + for( i_y = 0 ; i_y < i_height ; ) + { + i_ytmp = i_y >> 6; + i_y += i_yscale; + + /* Check whether we need to draw one line or more than one */ + if( i_ytmp + 1 >= ( i_y >> 6 ) ) + { + /* Just one line : we precalculate i_y >> 6 */ + i_yreal = p_pic->p->i_pitch * i_ytmp; + + /* Draw until we reach the end of the line */ + for( i_x = i_width ; i_x ; ) + { + /* Get the RLE part, then draw the line */ + i_color = *p_source & 0x3; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + i_x -= i_xscale * ( *p_source++ >> 2 ); + break; + + case 0x0f: + i_len = i_xscale * ( *p_source++ >> 2 ); + memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal, + p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) ); + i_x -= i_len; + break; + + default: + /* FIXME: we should do transparency */ + i_len = i_xscale * ( *p_source++ >> 2 ); + memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal, + p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) ); + i_x -= i_len; + break; + } + + } + } + else + { + i_yreal = p_pic->p->i_pitch * i_ytmp; + i_ynext = p_pic->p->i_pitch * i_y >> 6; + + /* Draw until we reach the end of the line */ + for( i_x = i_width ; i_x ; ) + { + /* Get the RLE part, then draw as many lines as needed */ + i_color = *p_source & 0x3; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + i_x -= i_xscale * ( *p_source++ >> 2 ); + break; + + case 0x0f: + i_len = i_xscale * ( *p_source++ >> 2 ); + for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; + i_ytmp += p_pic->p->i_pitch ) + { + memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp, + p_clut32[ i_color ], + 4 * ( ( i_len >> 6 ) + 1 ) ); + } + i_x -= i_len; + break; + + default: + /* FIXME: we should do transparency */ + i_len = i_xscale * ( *p_source++ >> 2 ); + for( i_ytmp = i_yreal ; i_ytmp < i_ynext ; + i_ytmp += p_pic->p->i_pitch ) + { + memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp, + p_clut32[ i_color ], + 4 * ( ( i_len >> 6 ) + 1 ) ); + } + i_x -= i_len; + break; + } + } + } + } + + break; + + /* NVidia overlay, no scaling */ + case VLC_FOURCC('Y','U','Y','2'): + + p_dest = p_pic->p->p_pixels + + (p_spu->i_x + p_spu->i_width + + p_vout->output.i_width * ( p_spu->i_y + p_spu->i_height )) * 2; + /* Draw until we reach the bottom of the subtitle */ + for( i_y = p_spu->i_height * p_vout->output.i_width; + i_y ; + i_y -= p_vout->output.i_width ) + { + /* Draw until we reach the end of the line */ + for( i_x = p_spu->i_width ; i_x ; ) + { + /* Get the RLE part, then draw the line */ + i_color = *p_source & 0x3; + + switch( p_spu->p_sys->pi_alpha[ i_color ] ) + { + case 0x00: + i_x -= *p_source++ >> 2; + break; + + case 0x0f: + i_len = *p_source++ >> 2; + for( i_cnt = 0; i_cnt < i_len; i_cnt++ ) + { + /* draw a pixel */ + /* Y */ + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2, + p_spu->p_sys->pi_yuv[i_color][0], 1); + + if (!(i_cnt & 0x01)) + { + /* U and V */ + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1, + 0x80, 1); + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3, + 0x80, 1); + } + } + i_x -= i_len; + break; + + default: + /* FIXME: we should do transparency */ + i_len = *p_source++ >> 2; + for( i_cnt = 0; i_cnt < i_len; i_cnt++ ) + { + /* draw a pixel */ + /* Y */ + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2, + p_spu->p_sys->pi_yuv[i_color][0], 1); + + if (!(i_cnt & 0x01)) + { + /* U and V */ + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1, + 0x80, 1); + memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3, + 0x80, 1); + } + } + i_x -= i_len; + break; + } + } + } + + break; + + + default: + msg_Err( p_vout, "unknown chroma, can't render SPU" ); + break; + } +} diff --git a/modules/codec/spudec/spudec.h b/modules/codec/spudec/spudec.h new file mode 100644 index 0000000000..99d371ea7e --- /dev/null +++ b/modules/codec/spudec/spudec.h @@ -0,0 +1,104 @@ +/***************************************************************************** + * spudec.h : sub picture unit decoder thread interface + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: spudec.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 subpicture_sys_t +{ + mtime_t i_pts; /* presentation timestamp */ + + int pi_offset[2]; /* byte offsets to data */ + void *p_data; + + /* Color information */ + vlc_bool_t b_palette; + u8 pi_alpha[4]; + u8 pi_yuv[4][3]; +}; + +/***************************************************************************** + * spudec_thread_t : sub picture unit decoder thread descriptor + *****************************************************************************/ +typedef struct spudec_thread_t +{ + /* + * Thread properties and locks + */ + 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; + + /* + * Output properties + */ + vout_thread_t * p_vout; /* needed to create the spu objects */ + + /* + * Private properties + */ + int i_spu_size; /* size of current SPU packet */ + int i_rle_size; /* size of the RLE part */ + +} spudec_thread_t; + +/***************************************************************************** + * Amount of bytes we GetChunk() in one go + *****************************************************************************/ +#define SPU_CHUNK_SIZE 0x200 + +/***************************************************************************** + * SPU commands + *****************************************************************************/ +#define SPU_CMD_FORCE_DISPLAY 0x00 +#define SPU_CMD_START_DISPLAY 0x01 +#define SPU_CMD_STOP_DISPLAY 0x02 +#define SPU_CMD_SET_PALETTE 0x03 +#define SPU_CMD_SET_ALPHACHANNEL 0x04 +#define SPU_CMD_SET_COORDINATES 0x05 +#define SPU_CMD_SET_OFFSETS 0x06 +#define SPU_CMD_END 0xff + +/***************************************************************************** + * AddNibble: read a nibble from a source packet and add it to our integer. + *****************************************************************************/ +static inline unsigned int AddNibble( unsigned int i_code, + u8 *p_src, int *pi_index ) +{ + if( *pi_index & 0x1 ) + { + return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) ); + } + else + { + return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 ); + } +} + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +vlc_thread_t spudec_CreateThread( decoder_fifo_t * p_fifo ); + diff --git a/modules/control/lirc/.cvsignore b/modules/control/lirc/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/control/lirc/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/control/lirc/Makefile b/modules/control/lirc/Makefile new file mode 100644 index 0000000000..139372dd1f --- /dev/null +++ b/modules/control/lirc/Makefile @@ -0,0 +1 @@ +lirc_SOURCES = lirc.c diff --git a/modules/control/lirc/lirc.c b/modules/control/lirc/lirc.c new file mode 100644 index 0000000000..230e5d0db1 --- /dev/null +++ b/modules/control/lirc/lirc.c @@ -0,0 +1,252 @@ +/***************************************************************************** + * lirc.c : lirc plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: lirc.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Sigmund Augdal + * + * 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 /* malloc(), free() */ +#include + +#include + +#include +#include +#include + +#include + +/***************************************************************************** + * intf_sys_t: description and status of FB interface + *****************************************************************************/ +struct intf_sys_t +{ + struct lirc_config *config; + vlc_mutex_t change_lock; + + input_thread_t * p_input; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); +static void Run ( intf_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("infrared remote control module") ); + set_capability( "interface", 0 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Open: initialize interface + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + int i_fd; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return 1; + } + + p_intf->pf_run = Run; + + i_fd = lirc_init( "vlc", 1 ); + if( i_fd == -1 ) + { + msg_Err( p_intf, "lirc_init failed" ); + free( p_intf->p_sys ); + return 1; + } + + /* We want polling */ + fcntl( i_fd, F_SETFL, fcntl( i_fd, F_GETFL ) | O_NONBLOCK ); + + if( lirc_readconfig( NULL, &p_intf->p_sys->config, NULL ) != 0 ) + { + msg_Err( p_intf, "lirc_readconfig failed" ); + lirc_deinit(); + free( p_intf->p_sys ); + return 1; + } + + p_intf->p_sys->p_input = NULL; + + return 0; +} + +/***************************************************************************** + * Close: destroy interface + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + /* Destroy structure */ + lirc_freeconfig( p_intf->p_sys->config ); + lirc_deinit(); + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: main loop + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + char *code, *c; + playlist_t *p_playlist; + input_thread_t *p_input; + + while( !p_intf->b_die ) + { + /* Sleep a bit */ + msleep( INTF_IDLE_SLEEP ); + + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + /* We poll the lircsocket */ + if( lirc_nextcode(&code) != 0 ) + { + break; + } + + if( code == NULL ) + { + continue; + } + + while( !p_intf->b_die + && lirc_code2char( p_intf->p_sys->config, code, &c ) == 0 + && c != NULL ) + { + if( !strcmp( c, "QUIT" ) ) + { + p_intf->p_vlc->b_die = VLC_TRUE; + continue; + } + + if( !strcmp( c, "FULLSCREEN" ) ) + { + vout_thread_t *p_vout; + p_vout = vlc_object_find( p_intf->p_sys->p_input, + VLC_OBJECT_VOUT, FIND_CHILD ); + if( p_vout ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_object_release( p_vout ); + } + continue; + } + + if( !strcmp( c, "PLAY" ) ) + { + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + } + } + else if( p_intf->p_sys->p_input ) + { + p_input = p_intf->p_sys->p_input; + + if( !strcmp( c, "PAUSE" ) ) + { + input_SetStatus( p_input, INPUT_STATUS_PAUSE ); + } + else if( !strcmp( c, "NEXT" ) ) + { + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); + } + } + else if( !strcmp( c, "PREV" ) ) + { + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); + } + } + else if( !strcmp( c, "STOP" ) ) + { + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + } + } + else if( !strcmp( c, "FAST" ) ) + { + input_SetStatus( p_input, INPUT_STATUS_FASTER ); + } + else if( !strcmp( c, "SLOW" ) ) + { + input_SetStatus( p_input, INPUT_STATUS_SLOWER ); + } + } + } + + free( code ); + } +} + diff --git a/modules/control/rc/.cvsignore b/modules/control/rc/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/control/rc/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/control/rc/Makefile b/modules/control/rc/Makefile new file mode 100644 index 0000000000..fbb6f2b07c --- /dev/null +++ b/modules/control/rc/Makefile @@ -0,0 +1 @@ +rc_SOURCES = rc.c diff --git a/modules/control/rc/rc.c b/modules/control/rc/rc.c new file mode 100644 index 0000000000..727dfcb839 --- /dev/null +++ b/modules/control/rc/rc.c @@ -0,0 +1,331 @@ +/***************************************************************************** + * rc.c : remote control stdin/stdout plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: rc.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Peter Surda + * + * 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 /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include +#include + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#if defined( WIN32 ) +#include /* select() */ +#endif + +#define MAX_LINE_LENGTH 256 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static void Run ( intf_thread_t *p_intf ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("remote control interface module") ); + set_capability( "interface", 20 ); + set_callbacks( Activate, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Activate: initialize and create stuff + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*)p_this; + +#ifdef HAVE_ISATTY + /* Check that stdin is a TTY */ + if( !isatty( 0 ) ) + { + msg_Warn( p_intf, "fd 0 is not a TTY" ); + return 1; + } +#endif + + /* Non-buffered stdout */ + setvbuf( stdout, (char *)NULL, _IOLBF, 0 ); + + p_intf->pf_run = Run; + +#ifdef WIN32 + AllocConsole(); + freopen( "CONOUT$", "w", stdout ); + freopen( "CONOUT$", "w", stderr ); + freopen( "CONIN$", "r", stdin ); + printf( VERSION_MESSAGE "\n" ); +#endif + + printf( "remote control interface initialized, `h' for help\n" ); + return 0; +} + +/***************************************************************************** + * Run: rc thread + ***************************************************************************** + * This part of the interface is in a separate thread so that we can call + * exec() from within it without annoying the rest of the program. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + input_thread_t * p_input; + + char p_buffer[ MAX_LINE_LENGTH + 1 ]; + vlc_bool_t b_complete = 0; + input_info_category_t * p_category; + input_info_t * p_info; + + int i_dummy; + off_t i_oldpos = 0; + off_t i_newpos; + fd_set fds; /* stdin changed? */ + struct timeval tv; /* how long to wait */ + + double f_ratio = 1; + char psz_dashes[81]; + + memset(psz_dashes, '-', 80); + psz_dashes[80] = '\0'; + + p_input = NULL; + + while( !p_intf->b_die ) + { + b_complete = 0; + + /* Check stdin */ + tv.tv_sec = 0; + tv.tv_usec = 50000; + FD_ZERO( &fds ); + FD_SET( STDIN_FILENO, &fds ); + + i_dummy = select( 32, &fds, NULL, NULL, &tv ); + if( i_dummy > 0 ) + { + int i_size = 0; + + while( !p_intf->b_die + && i_size < MAX_LINE_LENGTH + && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0 + && p_buffer[ i_size ] != '\r' + && p_buffer[ i_size ] != '\n' ) + { + i_size++; + } + + if( i_size == MAX_LINE_LENGTH + || p_buffer[ i_size ] == '\r' + || p_buffer[ i_size ] == '\n' ) + { + p_buffer[ i_size ] = 0; + b_complete = 1; + } + } + + /* Manage the input part */ + if( p_input == NULL ) + { + p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_input->b_dead ) + { + vlc_object_release( p_input ); + p_input = NULL; + } + + if( p_input ) + { + /* Get position */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( !p_input->b_die && p_input->stream.i_mux_rate ) + { +#define A p_input->stream.p_selected_area + f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate ); + i_newpos = A->i_tell * f_ratio; + + if( i_oldpos != i_newpos ) + { + i_oldpos = i_newpos; + printf( "pos: %li s / %li s\n", (long int)i_newpos, + (long int)(f_ratio * A->i_size) ); + } +#undef S + } + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + + /* Is there something to do? */ + if( b_complete == 1 ) + { + char *p_cmd = p_buffer; + + switch( p_cmd[0] ) + { + case 'a': + case 'A': + if( p_cmd[1] == ' ' ) + { + playlist_t *p_playlist; + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Add( p_playlist, p_cmd + 2, + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } + } + break; + + case 'd': + case 'D': + vlc_dumpstructure( p_intf->p_vlc ); + break; + + case 'p': + case 'P': + if( p_input ) + { + input_SetStatus( p_input, INPUT_STATUS_PAUSE ); + } + break; + + case 'f': + case 'F': + if( p_input ) + { + vout_thread_t *p_vout; + p_vout = vlc_object_find( p_input, + VLC_OBJECT_VOUT, FIND_CHILD ); + + if( p_vout ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_object_release( p_vout ); + } + } + break; + + case 's': + case 'S': + ; + break; + + case 'q': + case 'Q': + p_intf->p_vlc->b_die = VLC_TRUE; + break; + + case 'r': + case 'R': + if( p_input ) + { + for( i_dummy = 1; + i_dummy < MAX_LINE_LENGTH && p_cmd[ i_dummy ] >= '0' + && p_cmd[ i_dummy ] <= '9'; + i_dummy++ ) + { + ; + } + + p_cmd[ i_dummy ] = 0; + input_Seek( p_input, (off_t)atoi( p_cmd + 1 ), + INPUT_SEEK_SECONDS | INPUT_SEEK_SET ); + /* rcreseek(f_cpos); */ + } + break; + + case '?': + case 'h': + case 'H': + printf( "help for remote control commands\n" ); + printf( "h . . . . . . . . . . . . . . . . . . . . . help\n" ); + printf( "a XYZ . . . . . . . . . . append XYZ to playlist\n" ); + printf( "p . . . . . . . . . . . . . . . . . toggle pause\n" ); + printf( "f . . . . . . . . . . . . . . toggle fullscreen\n" ); + printf( "r X . . . seek in seconds, for instance `r 3.5'\n" ); + printf( "q . . . . . . . . . . . . . . . . . . . . . quit\n" ); + printf( "end of help\n" ); + break; + case 'i': + case 'I': + printf( "Dumping stream info\n" ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_category = p_input->stream.p_info; + while ( p_category ) + { + psz_dashes[72 - strlen(p_category->psz_name) ] = '\0'; + printf( "+--| %s |%s+\n", p_category->psz_name, psz_dashes); + psz_dashes[72 - strlen(p_category->psz_name) ] = '-'; + p_info = p_category->p_info; + while ( p_info ) + { + printf( "| %s: %s\n", p_info->psz_name, + p_info->psz_value ); + p_info = p_info->p_next; + } + printf("|\n"); + p_category = p_category->p_next; + } + psz_dashes[78] = '\0'; + printf( "+%s+\n", psz_dashes ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + break; + case '\0': + /* Ignore empty lines */ + break; + default: + printf( "unknown command `%s'\n", p_cmd ); + break; + } + } + + msleep( INTF_IDLE_SLEEP ); + } + + if( p_input ) + { + vlc_object_release( p_input ); + p_input = NULL; + } +} + diff --git a/modules/demux/a52/.cvsignore b/modules/demux/a52/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/demux/a52/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/demux/a52/Makefile b/modules/demux/a52/Makefile new file mode 100644 index 0000000000..2872efc6c3 --- /dev/null +++ b/modules/demux/a52/Makefile @@ -0,0 +1 @@ +a52_SOURCES = demux.c diff --git a/modules/demux/a52/demux.c b/modules/demux/a52/demux.c new file mode 100644 index 0000000000..f38c0738c9 --- /dev/null +++ b/modules/demux/a52/demux.c @@ -0,0 +1,174 @@ +/***************************************************************************** + * a52_system.c : A52 input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: demux.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Arnaud de Bossoreille de Ribou + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include + +#include +#include + +#include + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define A52_PACKET_SIZE 16384 +#define MAX_PACKETS_IN_FIFO 3 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Init ( vlc_object_t * ); +static int Demux ( input_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( "A52 demuxer" ); + set_capability( "demux", 150 ); + set_callbacks( Init, NULL ); + add_shortcut( "a52sys" ); +vlc_module_end(); + +/***************************************************************************** + * Init: initializes ES structures + *****************************************************************************/ +static int Init( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + es_descriptor_t * p_es; + byte_t * p_peek; + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + p_input->pf_demux = Demux; + p_input->pf_rewind = NULL; + + /* Have a peep at the show. */ + if( input_Peek( p_input, &p_peek, 2 ) < 2 ) + { + /* Stream shorter than 4 bytes... */ + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } + + if( *p_peek != 0x0b || *(p_peek + 1) != 0x77 ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "a52sys", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this doesn't look like an a52 stream, continuing" ); + } + else + { + msg_Warn( p_input, "a52 module discarded (no startcode)" ); + return( -1 ); + } + } + + if( input_InitStream( p_input, 0 ) == -1 ) + { + return( -1 ); + } + input_AddProgram( p_input, 0, 0 ); + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xBD, 0 ); + p_es->i_stream_id = 0xBD; + p_es->i_fourcc = VLC_FOURCC('a','5','2',' '); + p_es->i_cat = AUDIO_ES; + input_SelectES( p_input, p_es ); + p_input->stream.p_selected_area->i_tell = 0; + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Demux( input_thread_t * p_input ) +{ + ssize_t i_read; + decoder_fifo_t * p_fifo = + p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo; + pes_packet_t * p_pes; + data_packet_t * p_data; + + i_read = input_SplitBuffer( p_input, &p_data, A52_PACKET_SIZE ); + + if ( i_read <= 0 ) + { + return( i_read ); + } + + p_pes = input_NewPES( p_input->p_method_data ); + + if( p_pes == NULL ) + { + msg_Err( p_input, "out of memory" ); + input_DeletePacket( p_input->p_method_data, p_data ); + return( -1 ); + } + + p_pes->i_rate = p_input->stream.control.i_rate; + p_pes->p_first = p_pes->p_last = p_data; + p_pes->i_nb_data = 1; + + vlc_mutex_lock( &p_fifo->data_lock ); + if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO ) + { + /* Wait for the decoder. */ + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + vlc_mutex_unlock( &p_fifo->data_lock ); + + if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT) + |(p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_START) + | (input_ClockManageControl( p_input, + p_input->stream.p_selected_program, + (mtime_t)0 ) == PAUSE_S) ) + { + msg_Warn( p_input, "synchro reinit" ); + p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY; + p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK; + } + + input_DecodePES( p_fifo, p_pes ); + + return( 1 ); +} + diff --git a/modules/demux/avi/.cvsignore b/modules/demux/avi/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/demux/avi/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/demux/avi/Makefile b/modules/demux/avi/Makefile new file mode 100644 index 0000000000..1983576f12 --- /dev/null +++ b/modules/demux/avi/Makefile @@ -0,0 +1 @@ +avi_SOURCES = avi.c libioRIFF.c diff --git a/modules/demux/avi/avi.c b/modules/demux/avi/avi.c new file mode 100644 index 0000000000..6c67e71668 --- /dev/null +++ b/modules/demux/avi/avi.c @@ -0,0 +1,2228 @@ +/***************************************************************************** + * avi.c : AVI file Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: avi.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include +#include + +#include +#include + +#include "video.h" + +#include "libioRIFF.h" +#include "avi.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int AVIInit ( vlc_object_t * ); +static void __AVIEnd ( vlc_object_t * ); +static int AVIDemux ( input_thread_t * ); + +#define AVIEnd(a) __AVIEnd(VLC_OBJECT(a)) + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( "RIFF-AVI demuxer" ); + set_capability( "demux", 150 ); + set_callbacks( AVIInit, __AVIEnd ); +vlc_module_end(); + +/***************************************************************************** + * Some usefull functions to manipulate memory + *****************************************************************************/ +static u16 GetWLE( byte_t *p_buff ) +{ + u16 i; + i = (*p_buff) + ( *(p_buff + 1) <<8 ); + return ( i ); +} +static u32 GetDWLE( byte_t *p_buff ) +{ + u32 i; + i = (*p_buff) + ( *(p_buff + 1) <<8 ) + + ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 ); + return ( i ); +} +static u32 GetDWBE( byte_t *p_buff ) +{ + u32 i; + i = ((*p_buff)<<24) + ( *(p_buff + 1) <<16 ) + + ( *(p_buff + 2) <<8 ) + ( *(p_buff + 3) ); + return ( i ); +} +static inline off_t __EVEN( off_t i ) +{ + return( (i & 1) ? i+1 : i ); +} + + +/***************************************************************************** + * Functions for parsing the headers in an avi file + *****************************************************************************/ +static void AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff ) +{ + p_avih->i_microsecperframe = GetDWLE( p_buff ); + p_avih->i_maxbytespersec = GetDWLE( p_buff + 4); + p_avih->i_reserved1 = GetDWLE( p_buff + 8); + p_avih->i_flags = GetDWLE( p_buff + 12); + p_avih->i_totalframes = GetDWLE( p_buff + 16); + p_avih->i_initialframes = GetDWLE( p_buff + 20); + p_avih->i_streams = GetDWLE( p_buff + 24); + p_avih->i_suggestedbuffersize = GetDWLE( p_buff + 28); + p_avih->i_width = GetDWLE( p_buff + 32 ); + p_avih->i_height = GetDWLE( p_buff + 36 ); + p_avih->i_scale = GetDWLE( p_buff + 40 ); + p_avih->i_rate = GetDWLE( p_buff + 44 ); + p_avih->i_start = GetDWLE( p_buff + 48); + p_avih->i_length = GetDWLE( p_buff + 52); +} +static void AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff ) +{ + p_strh->i_type = GetDWLE( p_buff ); + p_strh->i_handler = GetDWLE( p_buff + 4 ); + p_strh->i_flags = GetDWLE( p_buff + 8 ); + p_strh->i_reserved1 = GetDWLE( p_buff + 12); + p_strh->i_initialframes = GetDWLE( p_buff + 16); + p_strh->i_scale = GetDWLE( p_buff + 20); + p_strh->i_rate = GetDWLE( p_buff + 24); + p_strh->i_start = GetDWLE( p_buff + 28); + p_strh->i_length = GetDWLE( p_buff + 32); + p_strh->i_suggestedbuffersize = GetDWLE( p_buff + 36); + p_strh->i_quality = GetDWLE( p_buff + 40); + p_strh->i_samplesize = GetDWLE( p_buff + 44); +} +static void AVI_Parse_BitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data ) +{ + h->i_size = GetDWLE( p_data ); + h->i_width = GetDWLE( p_data + 4 ); + h->i_height = GetDWLE( p_data + 8 ); + h->i_planes = GetWLE( p_data + 12 ); + h->i_bitcount = GetWLE( p_data + 14 ); + h->i_compression = GetDWLE( p_data + 16 ); + h->i_sizeimage = GetDWLE( p_data + 20 ); + h->i_xpelspermeter = GetDWLE( p_data + 24 ); + h->i_ypelspermeter = GetDWLE( p_data + 28 ); + h->i_clrused = GetDWLE( p_data + 32 ); + h->i_clrimportant = GetDWLE( p_data + 36 ); +} +static void AVI_Parse_WaveFormatEx( waveformatex_t *h, byte_t *p_data ) +{ + h->i_formattag = GetWLE( p_data ); + h->i_channels = GetWLE( p_data + 2 ); + h->i_samplespersec = GetDWLE( p_data + 4 ); + h->i_avgbytespersec= GetDWLE( p_data + 8 ); + h->i_blockalign = GetWLE( p_data + 12 ); + h->i_bitspersample = GetWLE( p_data + 14 ); + h->i_size = GetWLE( p_data + 16 ); +} + +static inline int AVI_GetESTypeFromTwoCC( u16 i_type ) +{ + switch( i_type ) + { + case( TWOCC_wb ): + return( AUDIO_ES ); + case( TWOCC_dc ): + case( TWOCC_db ): + return( VIDEO_ES ); + default: + return( UNKNOWN_ES ); + } +} + +static vlc_fourcc_t AVI_AudioGetType( u32 i_type ) +{ + switch( i_type ) + { +/* case( WAVE_FORMAT_PCM ): + return VLC_FOURCC('l','p','c','m'); */ + case( WAVE_FORMAT_A52 ): + return VLC_FOURCC('a','5','2',' '); + case( WAVE_FORMAT_MPEG): + case( WAVE_FORMAT_MPEGLAYER3): + return VLC_FOURCC('m','p','g','a'); /* for mpeg2 layer 1 2 ou 3 */ + default: + return 0; + } +} + +/* Test if it seems that it's a key frame */ +static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte ) +{ + switch( i_fourcc ) + { + case FOURCC_DIV1: + case FOURCC_div1: + case FOURCC_MPG4: + case FOURCC_mpg4: + if( GetDWBE( p_byte ) != 0x00000100 ) + /* startcode perhaps swapped, I haven't tested */ + { + /* it's seems it's not an msmpegv1 stream + but perhaps I'm wrong so return yes */ + return( AVIIF_KEYFRAME ); + } + else + { + return( (*(p_byte+4))&0x06 ? 0 : AVIIF_KEYFRAME); + } + case FOURCC_DIV2: + case FOURCC_div2: + case FOURCC_MP42: + case FOURCC_mp42: + case FOURCC_MPG3: + case FOURCC_mpg3: + case FOURCC_div3: + case FOURCC_MP43: + case FOURCC_mp43: + case FOURCC_DIV3: + case FOURCC_DIV4: + case FOURCC_div4: + case FOURCC_DIV5: + case FOURCC_div5: + case FOURCC_DIV6: + case FOURCC_div6: + case FOURCC_AP41: + case FOURCC_3IV1: + return( (*p_byte)&0xC0 ? 0 : AVIIF_KEYFRAME ); + case FOURCC_DIVX: + case FOURCC_divx: + case FOURCC_MP4S: + case FOURCC_mp4s: + case FOURCC_M4S2: + case FOURCC_m4s2: + case FOURCC_xvid: + case FOURCC_XVID: + case FOURCC_XviD: + case FOURCC_DX50: + case FOURCC_mp4v: + case FOURCC_4: + if( GetDWBE( p_byte ) != 0x000001b6 ) + { + /* not true , need to find the first VOP header + but, I'm lazy */ + return( AVIIF_KEYFRAME ); + } + else + { + return( (*(p_byte+4))&0xC0 ? 0 : AVIIF_KEYFRAME ); + } + default: + /* I can't do it, so said yes */ + return( AVIIF_KEYFRAME ); + } + +} +/***************************************************************************** + * Data and functions to manipulate pes buffer + *****************************************************************************/ +#define BUFFER_MAXTOTALSIZE 512*1024 /* 1/2 Mo */ +#define BUFFER_MAXSPESSIZE 1024*200 +static int AVI_PESBuffer_IsFull( AVIStreamInfo_t *p_info ) +{ + return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0); +} +static void AVI_PESBuffer_Add( input_buffers_t *p_method_data, + AVIStreamInfo_t *p_info, + pes_packet_t *p_pes, + int i_posc, + int i_posb ) +{ + AVIESBuffer_t *p_buffer_pes; + + if( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ) + { + input_DeletePES( p_method_data, p_pes ); + return; + } + + if( !( p_buffer_pes = malloc( sizeof( AVIESBuffer_t ) ) ) ) + { + input_DeletePES( p_method_data, p_pes ); + return; + } + p_buffer_pes->p_next = NULL; + p_buffer_pes->p_pes = p_pes; + p_buffer_pes->i_posc = i_posc; + p_buffer_pes->i_posb = i_posb; + + if( p_info->p_pes_last ) + { + p_info->p_pes_last->p_next = p_buffer_pes; + } + p_info->p_pes_last = p_buffer_pes; + if( !p_info->p_pes_first ) + { + p_info->p_pes_first = p_buffer_pes; + } + p_info->i_pes_count++; + p_info->i_pes_totalsize += p_pes->i_pes_size; +} +static pes_packet_t *AVI_PESBuffer_Get( AVIStreamInfo_t *p_info ) +{ + AVIESBuffer_t *p_buffer_pes; + pes_packet_t *p_pes; + if( p_info->p_pes_first ) + { + p_buffer_pes = p_info->p_pes_first; + p_info->p_pes_first = p_buffer_pes->p_next; + if( !p_info->p_pes_first ) + { + p_info->p_pes_last = NULL; + } + p_pes = p_buffer_pes->p_pes; + + free( p_buffer_pes ); + p_info->i_pes_count--; + p_info->i_pes_totalsize -= p_pes->i_pes_size; + return( p_pes ); + } + else + { + return( NULL ); + } +} +static int AVI_PESBuffer_Drop( input_buffers_t *p_method_data, + AVIStreamInfo_t *p_info ) +{ + pes_packet_t *p_pes = AVI_PESBuffer_Get( p_info ); + if( p_pes ) + { + input_DeletePES( p_method_data, p_pes ); + return( 1 ); + } + else + { + return( 0 ); + } +} +static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data, + AVIStreamInfo_t *p_info ) +{ + while( p_info->p_pes_first ) + { + AVI_PESBuffer_Drop( p_method_data, p_info ); + } +} + +static void AVI_ParseStreamHeader( u32 i_id, int *i_number, int *i_type ) +{ + int c1,c2; + + c1 = ( i_id ) & 0xFF; + c2 = ( i_id >> 8 ) & 0xFF; + + if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' ) + { + *i_number = 100; /* > max stream number */ + *i_type = 0; + } + else + { + *i_number = (c1 - '0') * 10 + (c2 - '0' ); + *i_type = ( i_id >> 16 ) & 0xFFFF; + } +} + +/* Function to manipulate stream easily */ +static off_t AVI_TellAbsolute( input_thread_t *p_input ) +{ + off_t i_pos; + vlc_mutex_lock( &p_input->stream.stream_lock ); + i_pos= p_input->stream.p_selected_area->i_tell - + ( p_input->p_last_data - p_input->p_current_data ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( i_pos ); +} + +static int AVI_SeekAbsolute( input_thread_t *p_input, + off_t i_pos) +{ + off_t i_filepos; + /* FIXME add support for not seekable stream */ + + i_filepos = AVI_TellAbsolute( p_input ); + if( i_pos != i_filepos ) + { +// msg_Err( p_input, "Seek --> delta %d", i_pos - i_filepos ); + p_input->pf_seek( p_input, i_pos ); + input_AccessReinit( p_input ); + } + return( 1 ); +} + + +static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info, + AVIIndexEntry_t *p_index) +{ + AVIIndexEntry_t *p_tmp; + if( p_info->p_index == NULL ) + { + p_info->i_idxmax = 16384; + p_info->i_idxnb = 0; + p_info->p_index = calloc( p_info->i_idxmax, + sizeof( AVIIndexEntry_t ) ); + if( p_info->p_index == NULL ) {return;} + } + if( p_info->i_idxnb >= p_info->i_idxmax ) + { + p_info->i_idxmax += 16384; + p_tmp = realloc( (void*)p_info->p_index, + p_info->i_idxmax * + sizeof( AVIIndexEntry_t ) ); + if( !p_tmp ) + { + p_info->i_idxmax -= 16384; + return; + } + p_info->p_index = p_tmp; + } + /* calculate cumulate length */ + if( p_info->i_idxnb > 0 ) + { + p_index->i_lengthtotal = p_info->p_index[p_info->i_idxnb-1].i_length + + p_info->p_index[p_info->i_idxnb-1].i_lengthtotal; + } + else + { + p_index->i_lengthtotal = 0; + } + + p_info->p_index[p_info->i_idxnb] = *p_index; + p_info->i_idxnb++; +} + +static void __AVI_GetIndex( input_thread_t *p_input ) +{ + AVIIndexEntry_t index; + byte_t *p_buff; + riffchunk_t *p_idx1; + int i_read; + int i; + int i_number; + int i_type; + int i_totalentry = 0; + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data ; + + if( RIFF_FindAndGotoDataChunk( p_input, + p_avi_demux->p_riff, + &p_idx1, + FOURCC_idx1)!=0 ) + { + msg_Warn( p_input, "cannot find index" ); + RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl ); + return; + } + p_avi_demux->p_idx1 = p_idx1; + msg_Dbg( p_input, "loading index" ); + for(;;) + { + i_read = __MIN( 16*1024, p_idx1->i_size - i_totalentry *16); + if( ((i_read = input_Peek( p_input, &p_buff, i_read )) < 16 ) + ||( i_totalentry *16 >= p_idx1->i_size ) ) + { + msg_Dbg( p_input, "read %d idx entries", i_totalentry ); + return; + } + i_read /= 16 ; + for( i = 0; i < i_read; i++ ) + { + byte_t *p_peek = p_buff + i * 16; + i_totalentry++; + index.i_id = GetDWLE( p_peek ); + index.i_flags = GetDWLE( p_peek+4)&(~AVIIF_FIXKEYFRAME); + index.i_pos = GetDWLE( p_peek+8); + index.i_length = GetDWLE(p_peek+12); + AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ); + + if( ( i_number < p_avi_demux->i_streams ) + &&(p_avi_demux->pp_info[i_number]->i_cat == + AVI_GetESTypeFromTwoCC( i_type ))) + { + __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number], + &index ); + } + } + __RIFF_SkipBytes( p_input, 16 * i_read ); + } + +} + +/* XXX call after get p_movi */ +static void __AVI_UpdateIndexOffset( input_thread_t *p_input ) +{ + int i_stream; + int b_start = 1;/* if index pos is based on start of file or not (p_movi) */ + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + +/* FIXME some work to do : + * test in the file if it's true, if not do a RIFF_Find... +*/ +#define p_info p_avi_demux->pp_info[i_stream] + for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ ) + { + if( ( p_info->p_index ) + && ( p_info->p_index[0].i_pos < p_avi_demux->p_movi->i_pos + 8 )) + { + b_start = 0; + break; + } + } + if( !b_start ) + { + for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ ) + { + int i; + if( p_info->p_index ) + { + for( i = 0; i < p_info->i_idxnb; i++ ) + { + p_info->p_index[i].i_pos += p_avi_demux->p_movi->i_pos + 8; + } + } + } + } +#undef p_info +} + +/***************************************************************************** + * AVIEnd: frees unused data + *****************************************************************************/ +static void __AVIEnd ( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + int i; + demux_data_avi_file_t *p_avi_demux; + p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data ; + + if( p_avi_demux->p_riff ) + RIFF_DeleteChunk( p_input, p_avi_demux->p_riff ); + if( p_avi_demux->p_hdrl ) + RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl ); + if( p_avi_demux->p_movi ) + RIFF_DeleteChunk( p_input, p_avi_demux->p_movi ); + if( p_avi_demux->p_idx1 ) + RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 ); + if( p_avi_demux->pp_info ) + { + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { + if( p_avi_demux->pp_info[i] ) + { + if( p_avi_demux->pp_info[i]->p_index ) + { + free( p_avi_demux->pp_info[i]->p_index ); + AVI_PESBuffer_Flush( p_input->p_method_data, + p_avi_demux->pp_info[i] ); + } + free( p_avi_demux->pp_info[i] ); + } + } + free( p_avi_demux->pp_info ); + } +} + +/***************************************************************************** + * AVIInit: check file and initializes AVI structures + *****************************************************************************/ +static int AVIInit( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + riffchunk_t *p_riff,*p_hdrl,*p_movi; + riffchunk_t *p_avih; + riffchunk_t *p_strl,*p_strh,*p_strf; + demux_data_avi_file_t *p_avi_demux; + es_descriptor_t *p_es = NULL; /* for not warning */ + int i; + + p_input->pf_demux = AVIDemux; + + if( !( p_input->p_demux_data = + p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) ) + { + msg_Err( p_input, "out of memory" ); + return( -1 ); + } + memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) ); + p_avi_demux->i_rate = DEFAULT_RATE; + p_avi_demux->b_seekable = ( ( p_input->stream.b_seekable ) + &&( p_input->stream.i_method == INPUT_METHOD_FILE ) ); + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 ) + { + AVIEnd( p_input ); + msg_Warn( p_input, "RIFF-AVI module discarded" ); + return( -1 ); + } + p_avi_demux->p_riff = p_riff; + + if ( RIFF_DescendChunk(p_input) != 0 ) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot look for subchunk" ); + return ( -1 ); + } + + /* it's a riff-avi file, so search for LIST-hdrl */ + if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 ) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot find \"LIST-hdrl\"" ); + return( -1 ); + } + p_avi_demux->p_hdrl = p_hdrl; + + if( RIFF_DescendChunk(p_input) != 0 ) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot look for subchunk" ); + return ( -1 ); + } + /* in LIST-hdrl search avih */ + if( RIFF_FindAndLoadChunk( p_input, p_hdrl, + &p_avih, FOURCC_avih ) != 0 ) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot find \"avih\" chunk" ); + return( -1 ); + } + AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start ); + RIFF_DeleteChunk( p_input, p_avih ); + + if( p_avi_demux->avih.i_streams == 0 ) + /* no stream found, perhaps it would be cool to find it */ + { + AVIEnd( p_input ); + msg_Err( p_input, "no stream defined!" ); + return( -1 ); + } + + /* create one program */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( input_InitStream( p_input, 0 ) == -1) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + AVIEnd( p_input ); + msg_Err( p_input, "cannot init stream" ); + return( -1 ); + } + if( input_AddProgram( p_input, 0, 0) == NULL ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + AVIEnd( p_input ); + msg_Err( p_input, "cannot add program" ); + return( -1 ); + } + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + /* now read info on each stream and create ES */ + p_avi_demux->i_streams = p_avi_demux->avih.i_streams; + + p_avi_demux->pp_info = calloc( p_avi_demux->i_streams, + sizeof( AVIStreamInfo_t* ) ); + memset( p_avi_demux->pp_info, + 0, + sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams ); + + for( i = 0 ; i < p_avi_demux->i_streams; i++ ) + { +#define p_info p_avi_demux->pp_info[i] + p_info = malloc( sizeof(AVIStreamInfo_t ) ); + memset( p_info, 0, sizeof( AVIStreamInfo_t ) ); + + if( ( RIFF_FindListChunk(p_input, + &p_strl,p_hdrl, FOURCC_strl) != 0 ) + ||( RIFF_DescendChunk(p_input) != 0 )) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot find \"LIST-strl\"" ); + return( -1 ); + } + + /* in LIST-strl search strh */ + if( RIFF_FindAndLoadChunk( p_input, p_hdrl, + &p_strh, FOURCC_strh ) != 0 ) + { + RIFF_DeleteChunk( p_input, p_strl ); + AVIEnd( p_input ); + msg_Err( p_input, "cannot find \"strh\"" ); + return( -1 ); + } + AVI_Parse_Header( &p_info->header, + p_strh->p_data->p_payload_start); + RIFF_DeleteChunk( p_input, p_strh ); + + /* in LIST-strl search strf */ + if( RIFF_FindAndLoadChunk( p_input, p_hdrl, + &p_strf, FOURCC_strf ) != 0 ) + { + RIFF_DeleteChunk( p_input, p_strl ); + AVIEnd( p_input ); + msg_Err( p_input, "cannot find \"strf\"" ); + return( -1 ); + } + /* we don't get strd, it's useless for divx,opendivx,mepgaudio */ + if( RIFF_AscendChunk(p_input, p_strl) != 0 ) + { + RIFF_DeleteChunk( p_input, p_strf ); + RIFF_DeleteChunk( p_input, p_strl ); + AVIEnd( p_input ); + msg_Err( p_input, "cannot go out (\"strl\")" ); + return( -1 ); + } + + /* add one ES */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_es = input_AddES( p_input, + p_input->stream.p_selected_program, 1+i, + p_strf->i_size ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + p_es->i_stream_id =i; /* XXX: i don't use it */ + + switch( p_info->header.i_type ) + { + case( FOURCC_auds ): + p_es->i_cat = AUDIO_ES; + AVI_Parse_WaveFormatEx( &p_info->audio_format, + p_strf->p_data->p_payload_start ); + p_es->i_fourcc = AVI_AudioGetType( + p_info->audio_format.i_formattag ); + break; + + case( FOURCC_vids ): + p_es->i_cat = VIDEO_ES; + AVI_Parse_BitMapInfoHeader( &p_info->video_format, + p_strf->p_data->p_payload_start ); + + /* XXX quick hack for playing ffmpeg video, I don't know + who is doing something wrong */ + p_info->header.i_samplesize = 0; + p_es->i_fourcc = p_info->video_format.i_compression; + break; + default: + msg_Err( p_input, "unknown stream(%d) type", i ); + p_es->i_cat = UNKNOWN_ES; + break; + } + p_info->p_es = p_es; + p_info->i_cat = p_es->i_cat; + /* We copy strf for decoder in p_es->p_demux_data */ + memcpy( p_es->p_demux_data, + p_strf->p_data->p_payload_start, + p_strf->i_size ); + RIFF_DeleteChunk( p_input, p_strf ); + RIFF_DeleteChunk( p_input, p_strl ); +#undef p_info + } + + + + /* go out of p_hdrl */ + if( RIFF_AscendChunk(p_input, p_hdrl) != 0) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot go out (\"hdrl\")" ); + return( -1 ); + } + + /* go to movi chunk to get it*/ + if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 ) + { + msg_Err( p_input, "cannot find \"LIST-movi\"" ); + AVIEnd( p_input ); + return( -1 ); + } + p_avi_demux->p_movi = p_movi; + + /* get index XXX need to have p_movi */ + if( p_avi_demux->b_seekable ) + { + /* get index */ + __AVI_GetIndex( p_input ); + /* try to get i_idxoffset for each stream */ + __AVI_UpdateIndexOffset( p_input ); + /* to make sure to go the begining unless demux will see a seek */ + RIFF_GoToChunk( p_input, p_avi_demux->p_movi ); + + } + else + { + msg_Warn( p_input, "no index!" ); + } + + if( RIFF_DescendChunk( p_input ) != 0 ) + { + AVIEnd( p_input ); + msg_Err( p_input, "cannot go in (\"movi\")" ); + return( -1 ); + } + + /* print informations on streams */ + msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ", + p_avi_demux->i_streams, + p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"", + p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"", + p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"", + p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" ); + + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { +#define p_info p_avi_demux->pp_info[i] + switch( p_info->p_es->i_cat ) + { + case( VIDEO_ES ): + + msg_Dbg( p_input, "video(%4.4s) %dx%d %dbpp %ffps", + (char*)&p_info->video_format.i_compression, + p_info->video_format.i_width, + p_info->video_format.i_height, + p_info->video_format.i_bitcount, + (float)p_info->header.i_rate / + (float)p_info->header.i_scale ); + if( (p_avi_demux->p_info_video == NULL) ) + { + p_avi_demux->p_info_video = p_info; + /* TODO add test to see if a decoder has been found */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + input_SelectES( p_input, p_info->p_es ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + break; + + case( AUDIO_ES ): + msg_Dbg( p_input, "audio(0x%x) %d channels %dHz %dbits", + p_info->audio_format.i_formattag, + p_info->audio_format.i_channels, + p_info->audio_format.i_samplespersec, + p_info->audio_format.i_bitspersample ); + if( (p_avi_demux->p_info_audio == NULL) ) + { + p_avi_demux->p_info_audio = p_info; + vlc_mutex_lock( &p_input->stream.stream_lock ); + input_SelectES( p_input, p_info->p_es ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + break; + default: + break; + } +#undef p_info + } + + + /* we select the first audio and video ES */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( !p_avi_demux->p_info_video ) + { + msg_Warn( p_input, "no video stream found" ); + } + if( !p_avi_demux->p_info_audio ) + { + msg_Warn( p_input, "no audio stream found!" ); + } + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); +} + + + + + + +/***************************************************************************** + * Function to convert pts to chunk or byte + *****************************************************************************/ + +static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info, + mtime_t i_pts ) +{ + return( (mtime_t)((s64)i_pts * + (s64)p_info->header.i_rate / + (s64)p_info->header.i_scale / + (s64)1000000 ) ); +} +static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info, + mtime_t i_pts ) +{ + return( (mtime_t)((s64)i_pts * + (s64)p_info->header.i_samplesize * + (s64)p_info->header.i_rate / + (s64)p_info->header.i_scale / + (s64)1000000 ) ); + +} +static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info ) +{ + + if( p_info->header.i_samplesize ) + { + /* we need a valid entry we will emulate one */ + int i_len; + if( p_info->i_idxposc == p_info->i_idxnb ) + { + if( p_info->i_idxposc ) + { + /* use the last entry */ + i_len = p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal + + p_info->p_index[p_info->i_idxnb - 1].i_length + + p_info->i_idxposb; /* should be 0 */ + } + else + { + i_len = p_info->i_idxposb; + /* no valid entry use only offset*/ + } + } + else + { + i_len = p_info->p_index[p_info->i_idxposc].i_lengthtotal + + p_info->i_idxposb; + } + return( (mtime_t)( (s64)1000000 * + (s64)i_len * + (s64)p_info->header.i_scale / + (s64)p_info->header.i_rate / + (s64)p_info->header.i_samplesize ) ); + } + else + { + /* even if p_info->i_idxposc isn't valid, there isn't any probllem */ + return( (mtime_t)( (s64)1000000 * + (s64)(p_info->i_idxposc ) * + (s64)p_info->header.i_scale / + (s64)p_info->header.i_rate) ); + } +} + + +/***************************************************************************** + * Functions to acces streams data + * Uses it, because i plane to read unseekable stream + * Don't work for the moment for unseekable stream + * XXX NEVER set directly i_idxposc and i_idxposb unless you know what you do + *****************************************************************************/ + +/* FIXME FIXME change b_pad to number of bytes to skipp after reading */ +static int __AVI_GetDataInPES( input_thread_t *p_input, + pes_packet_t **pp_pes, + int i_size, + int b_pad ) +{ + + int i_read; + data_packet_t *p_data; + + + if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) ) + { + return( 0 ); + } + + + if( !i_size ) + { + p_data = input_NewPacket( p_input->p_method_data, 0 ); + (*pp_pes)->p_first = (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data = 1; + (*pp_pes)->i_pes_size = 0; + return( 0 ); + } + + if( ( i_size&1 )&&( b_pad ) ) + { + b_pad = 1; + i_size++; + } + else + { + b_pad = 0; + } + + do + { + i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size - + (*pp_pes)->i_pes_size, 1024 ) ); + if( i_read < 0 ) + { + return( (*pp_pes)->i_pes_size ); + } + if( !(*pp_pes)->p_first ) + { + (*pp_pes)->p_first = + (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data = 1; + (*pp_pes)->i_pes_size = i_read; + } + else + { + (*pp_pes)->p_last->p_next = + (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data++; + (*pp_pes)->i_pes_size += i_read; + } + } while( ((*pp_pes)->i_pes_size < i_size)&&( i_read ) ); + + if( b_pad ) + { + (*pp_pes)->i_pes_size--; + (*pp_pes)->p_last->p_payload_end--; + i_size--; + } + + return( i_size ); +} + +static int __AVI_SeekAndGetChunk( input_thread_t *p_input, + AVIStreamInfo_t *p_info ) +{ + pes_packet_t *p_pes; + int i_length, i_ret; + + i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length + - p_info->i_idxposb, + BUFFER_MAXSPESSIZE ); + + AVI_SeekAbsolute( p_input, + (off_t)p_info->p_index[p_info->i_idxposc].i_pos + + p_info->i_idxposb + 8); + + i_ret = __AVI_GetDataInPES( p_input, &p_pes, i_length , 0); + + if( i_ret != i_length ) + { + return( 0 ); + } + /* TODO test key frame if i_idxposb == 0*/ + AVI_PESBuffer_Add( p_input->p_method_data, + p_info, + p_pes, + p_info->i_idxposc, + p_info->i_idxposb ); + return( 1 ); +} +/* TODO check if it's correct (humm...) and optimisation ... */ +/* return 0 if we choose to get only the ck we want + * 1 if index is invalid + * 2 if there is a ck_other before ck_info and the last proced ck_info*/ +/* XXX XXX XXX avi file is some BIG shit, and sometime index give + * a refenrence to the same chunk BUT with a different size ( usually 0 ) + */ + +static inline int __AVI_GetChunkMethod( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + AVIStreamInfo_t *p_other ) +{ + int i_info_pos; + int i_other_pos; + + int i_info_pos_last; + int i_other_pos_last; + + /*If we don't have a valid entry we need to parse from last + defined chunk and it's the only way that we return 1*/ + if( p_info->i_idxposc >= p_info->i_idxnb ) + { + return( 1 ); + } + + /* KNOW we have a valid entry for p_info */ + /* we return 0 if we haven't an valid entry for p_other */ + if( ( !p_other )||( p_other->i_idxposc >= p_other->i_idxnb ) ) + { + return( 0 ); + } + + /* KNOW there are 2 streams with valid entry */ + + /* we return 0 if for one of the two streams we will not read + chunk-aligned */ + if( ( p_info->i_idxposb )||( p_other->i_idxposb ) ) + { + return( 0 ); + } + + /* KNOW we have a valid entry for the 2 streams + and for the 2 we want an aligned chunk (given by i_idxposc )*/ + /* if in stream, the next chunk is back than the one we + have just read, it's useless to parse */ + i_info_pos = p_info->p_index[p_info->i_idxposc].i_pos; + i_other_pos = p_other->p_index[p_other->i_idxposc].i_pos ; + + i_info_pos_last = p_info->i_idxposc ? + p_info->p_index[p_info->i_idxposc - 1].i_pos : 0; + i_other_pos_last = p_other->i_idxposc ? + p_other->p_index[p_other->i_idxposc - 1].i_pos : 0 ; + + + if( ( ( p_info->i_idxposc )&&( i_info_pos <= i_info_pos_last ) ) || + ( ( p_other->i_idxposc )&&( i_other_pos <= i_other_pos_last ) ) ) + { + return( 0 ); + } + + /* KNOW for the 2 streams, the ck we want are after the last read + or it's the first */ + + /* if the first ck_other we want isn't between ck_info_last + and ck_info, don't parse */ + /* TODO fix this, use also number in buffered PES */ + if( ( i_other_pos > i_info_pos) /* ck_other too far */ + ||( i_other_pos < i_info_pos_last ) ) /* it's too late for ck_other */ + { + return( 0 ); + } + + /* we Know we will find ck_other, and before ck_info + "if ck_info is too far" will be handle after */ + return( 2 ); +} + + +static inline int __AVI_ChooseSize( int l1, int l2 ) +{ + /* XXX l2 is prefered if 0 otherwise min not equal to 0 */ + if( !l2 ) + { + return( 0 ); + } + return( !l1 ? l2 : __MIN( l1,l2 ) ); +} + +/* We know we will read chunk align */ +static int __AVI_GetAndPutChunkInBuffer( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + int i_size, + int i_ck ) +{ + + pes_packet_t *p_pes; + int i_length; + + i_length = __MIN( i_size, BUFFER_MAXSPESSIZE ); + + /* Skip chunk header */ + + if( __AVI_GetDataInPES( p_input, &p_pes, i_length + 8,1 ) != i_length +8 ) + { + return( 0 ); + } + p_pes->p_first->p_payload_start += 8; + p_pes->i_pes_size -= 8; + + i_size = GetDWLE( p_pes->p_first->p_demux_start + 4); + + AVI_PESBuffer_Add( p_input->p_method_data, + p_info, + p_pes, + i_ck, + 0 ); + /* skip unwanted bytes */ + if( i_length != i_size) + { + msg_Err( p_input, "Chunk Size mismatch" ); + AVI_SeekAbsolute( p_input, + __EVEN( AVI_TellAbsolute( p_input ) + + i_size - i_length ) ); + } + return( 1 ); +} + +/* XXX Don't use this function directly ! XXX */ +static int __AVI_GetChunk( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + int b_load ) +{ + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + AVIStreamInfo_t *p_other; + int i_method; + off_t i_posmax; + int i; + +#define p_info_i p_avi_demux->pp_info[i] + while( p_info->p_pes_first ) + { + if( ( p_info->p_pes_first->i_posc == p_info->i_idxposc ) + &&( p_info->i_idxposb >= p_info->p_pes_first->i_posb ) + &&( p_info->i_idxposb < p_info->p_pes_first->i_posb + + p_info->p_pes_first->p_pes->i_pes_size ) ) + + { + return( 1 ); /* we have it in buffer */ + } + else + { + AVI_PESBuffer_Drop( p_input->p_method_data, p_info ); + } + } + /* up to now we handle only one audio and video streams at the same time */ + p_other = (p_info == p_avi_demux->p_info_video ) ? + p_avi_demux->p_info_audio : p_avi_demux->p_info_video ; + + i_method = __AVI_GetChunkMethod( p_input, p_info, p_other ); + + if( !i_method ) + { + /* get directly the good chunk */ + return( b_load ? __AVI_SeekAndGetChunk( p_input, p_info ) : 1 ); + } + /* We will parse + * because invalid index + * or will find ck_other before ck_info + */ +// msg_Warn( p_input, "method %d", i_method ); + /* we will calculate the better position we have to reach */ + if( i_method == 1 ) + { + /* invalid index */ + /* the position max we have already reached */ + /* FIXME this isn't the better because sometime will fail to + put in buffer p_other since it could be too far */ + AVIStreamInfo_t *p_info_max = p_info; + + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { + if( p_info_i->i_idxnb ) + { + if( p_info_max->i_idxnb ) + { + if( p_info_i->p_index[p_info_i->i_idxnb -1 ].i_pos > + p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos ) + { + p_info_max = p_info_i; + } + } + else + { + p_info_max = p_info_i; + } + } + } + if( p_info_max->i_idxnb ) + { + /* be carefull that size between index and ck can sometime be + different without any error (and other time it's an error) */ + i_posmax = p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos; + /* so choose this, and I know that we have already reach it */ + } + else + { + i_posmax = p_avi_demux->p_movi->i_pos + 12; + } + } + else + { + if( !b_load ) + { + return( 1 ); /* all is ok */ + } + /* valid index */ + /* we know that the entry and the last one are valid for the 2 stream */ + /* and ck_other will come *before* index so go directly to it*/ + i_posmax = p_other->p_index[p_other->i_idxposc].i_pos; + } + + AVI_SeekAbsolute( p_input, i_posmax ); + /* the first chunk we will see is : + * the last chunk that we have already seen for broken index + * the first ck for other with good index */ + for( ; ; ) /* infinite parsing until the ck we want */ + { + riffchunk_t *p_ck; + int i_type; + + /* Get the actual chunk in the stream */ + if( !(p_ck = RIFF_ReadChunk( p_input )) ) + { + return( 0 ); + } +// msg_Dbg( p_input, "ck: %4.4s len %d", &p_ck->i_id, p_ck->i_size ); + /* special case for LIST-rec chunk */ + if( ( p_ck->i_id == FOURCC_LIST )&&( p_ck->i_type == FOURCC_rec ) ) + { + RIFF_DescendChunk( p_input ); + RIFF_DeleteChunk( p_input, p_ck ); + continue; + } + AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type ); + /* littles checks but not too much if you want to read all file */ + if( i >= p_avi_demux->i_streams ) + /* (AVI_GetESTypeFromTwoCC(i_type) != p_info_i->i_cat) perhaps add it*/ + + { + RIFF_DeleteChunk( p_input, p_ck ); + if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 ) + { + return( 0 ); + } + } + else + { + int i_size; + + /* have we found a new entry (not present in index)? */ + if( ( !p_info_i->i_idxnb ) + ||(p_info_i->p_index[p_info_i->i_idxnb-1].i_pos < p_ck->i_pos)) + { + AVIIndexEntry_t index; + + index.i_id = p_ck->i_id; + index.i_flags = AVI_GetKeyFlag( p_info_i->p_es->i_fourcc, + (u8*)&p_ck->i_8bytes); + index.i_pos = p_ck->i_pos; + index.i_length = p_ck->i_size; + __AVI_AddEntryIndex( p_info_i, &index ); + } + + + /* TODO check if p_other is full and then if is possible + go directly to the good chunk */ + if( ( p_info_i == p_other ) + &&( !AVI_PESBuffer_IsFull( p_other ) ) + &&( ( !p_other->p_pes_last )|| + ( p_other->p_pes_last->p_pes->i_pes_size != + BUFFER_MAXSPESSIZE ) ) ) + { + int i_ck = p_other->p_pes_last ? + p_other->p_pes_last->i_posc + 1 : p_other->i_idxposc; + i_size = __AVI_ChooseSize( p_ck->i_size, + p_other->p_index[i_ck].i_length); + + if( p_other->p_index[i_ck].i_pos == p_ck->i_pos ) + { + if( !__AVI_GetAndPutChunkInBuffer( p_input, p_other, + i_size, i_ck ) ) + { + RIFF_DeleteChunk( p_input, p_ck ); + return( 0 ); + } + } + else + { + if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 ) + { + RIFF_DeleteChunk( p_input, p_ck ); + + return( 0 ); + } + + } + + RIFF_DeleteChunk( p_input, p_ck ); + } + else + if( ( p_info_i == p_info) + &&( p_info->i_idxposc < p_info->i_idxnb ) ) + { + /* the first ck_info is ok otherwise it should be + loaded without parsing */ + i_size = __AVI_ChooseSize( p_ck->i_size, + p_info->p_index[p_info->i_idxposc].i_length); + + + RIFF_DeleteChunk( p_input, p_ck ); + + return( b_load ? __AVI_GetAndPutChunkInBuffer( p_input, + p_info, + i_size, + p_info->i_idxposc ) : 1 ); + } + else + { + /* skip it */ + RIFF_DeleteChunk( p_input, p_ck ); + if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 ) + { + return( 0 ); + } + } + } + + + } + +#undef p_info_i +} + +/* be sure that i_ck will be a valid index entry */ +static int AVI_SetStreamChunk( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + int i_ck ) +{ + + p_info->i_idxposc = i_ck; + p_info->i_idxposb = 0; + + if( i_ck < p_info->i_idxnb ) + { + return( 1 ); + } + else + { + p_info->i_idxposc = p_info->i_idxnb - 1; + do + { + p_info->i_idxposc++; + if( !__AVI_GetChunk( p_input, p_info, 0 ) ) + { + return( 0 ); + } + } while( p_info->i_idxposc < i_ck ); + + return( 1 ); + } +} + + +/* XXX FIXME up to now, we assume that all chunk are one after one */ +static int AVI_SetStreamBytes( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + off_t i_byte ) +{ + if( ( p_info->i_idxnb > 0 ) + &&( i_byte < p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal + + p_info->p_index[p_info->i_idxnb - 1].i_length ) ) + { + /* index is valid to find the ck */ + /* uses dichototmie to be fast enougth */ + int i_idxposc = __MIN( p_info->i_idxposc, p_info->i_idxnb - 1 ); + int i_idxmax = p_info->i_idxnb; + int i_idxmin = 0; + for( ;; ) + { + if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte ) + { + i_idxmax = i_idxposc ; + i_idxposc = ( i_idxmin + i_idxposc ) / 2 ; + } + else + { + if( p_info->p_index[i_idxposc].i_lengthtotal + + p_info->p_index[i_idxposc].i_length <= i_byte) + { + i_idxmin = i_idxposc ; + i_idxposc = (i_idxmax + i_idxposc ) / 2 ; + } + else + { + p_info->i_idxposc = i_idxposc; + p_info->i_idxposb = i_byte - + p_info->p_index[i_idxposc].i_lengthtotal; + return( 1 ); + } + } + } + + } + else + { + p_info->i_idxposc = p_info->i_idxnb - 1; + p_info->i_idxposb = 0; + do + { + p_info->i_idxposc++; + if( !__AVI_GetChunk( p_input, p_info, 0 ) ) + { + return( 0 ); + } + } while( p_info->p_index[p_info->i_idxposc].i_lengthtotal + + p_info->p_index[p_info->i_idxposc].i_length <= i_byte ); + + p_info->i_idxposb = i_byte - + p_info->p_index[p_info->i_idxposc].i_lengthtotal; + return( 1 ); + } +} + +static pes_packet_t *AVI_ReadStreamChunkInPES( input_thread_t *p_input, + AVIStreamInfo_t *p_info ) + +{ + if( p_info->i_idxposc > p_info->i_idxnb ) + { + return( NULL ); + } + + /* we want chunk (p_info->i_idxposc,0) */ + p_info->i_idxposb = 0; + if( !__AVI_GetChunk( p_input, p_info, 1) ) + { + msg_Err( p_input, "Got one chunk : failed" ); + return( NULL ); + } + p_info->i_idxposc++; + return( AVI_PESBuffer_Get( p_info ) ); +} + +static pes_packet_t *AVI_ReadStreamBytesInPES( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + int i_byte ) +{ + pes_packet_t *p_pes; + data_packet_t *p_data; + int i_count = 0; + int i_read; + + + if( !( p_pes = input_NewPES( p_input->p_method_data ) ) ) + { + return( NULL ); + } + if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) ) + { + input_DeletePES( p_input->p_method_data, p_pes ); + return( NULL ); + } + + p_pes->p_first = + p_pes->p_last = p_data; + p_pes->i_nb_data = 1; + p_pes->i_pes_size = i_byte; + + while( i_byte > 0 ) + { + if( !__AVI_GetChunk( p_input, p_info, 1) ) + { + msg_Err( p_input, "Got one chunk : failed" ); + + input_DeletePES( p_input->p_method_data, p_pes ); + return( NULL ); + } + + i_read = __MIN( p_info->p_pes_first->p_pes->i_pes_size - + ( p_info->i_idxposb - p_info->p_pes_first->i_posb ), + i_byte); + /* FIXME FIXME FIXME follow all data packet */ + memcpy( p_data->p_payload_start + i_count, + p_info->p_pes_first->p_pes->p_first->p_payload_start + + p_info->i_idxposb - p_info->p_pes_first->i_posb, + i_read ); + + AVI_PESBuffer_Drop( p_input->p_method_data, p_info ); + i_byte -= i_read; + i_count += i_read; + + p_info->i_idxposb += i_read; + if( p_info->p_index[p_info->i_idxposc].i_length <= p_info->i_idxposb ) + { + p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length; + p_info->i_idxposc++; + } + } + return( p_pes ); +} + + + +/* try to realign after a seek */ +static int AVI_ReAlign( input_thread_t *p_input, + AVIStreamInfo_t *p_info ) +{ + int i; + off_t i_pos; + int b_after = 0; + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + + + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { + AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] ); + } + /* Reinit clock + TODO use input_ClockInit instead but need to be exported + p_input->stream.p_selected_program->last_cr = 0; + p_input->stream.p_selected_program->last_syscr = 0; + p_input->stream.p_selected_program->cr_ref = 0; + p_input->stream.p_selected_program->sysdate_ref = 0; + p_input->stream.p_selected_program->delta_cr = 0; + p_input->stream.p_selected_program->c_average_count = 0; */ + + i_pos = AVI_TellAbsolute( p_input ); + + p_info->i_idxposc--; /* in fact p_info->i_idxposc is for ck to be read */ + + + if( ( p_info->i_idxposc <= 0) + ||( i_pos <= p_info->p_index[0].i_pos ) ) + { + /* before beginning of stream */ + return( p_info->header.i_samplesize ? + AVI_SetStreamBytes( p_input, p_info, 0 ) : + AVI_SetStreamChunk( p_input, p_info, 0 ) ); + } + + b_after = ( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos ); + /* now find in what chunk we are */ + while( ( i_pos < p_info->p_index[p_info->i_idxposc].i_pos ) + &&( p_info->i_idxposc > 0 ) ) + { + /* search before i_idxposc */ + + if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc - 1 ) ) + { + return( 0 ); + } + } + + while( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos + + p_info->p_index[p_info->i_idxposc].i_length + 8 ) + { + /* search after i_idxposc */ + + if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 ) ) + { + return( 0 ); + } + } + + /* search nearest key frame, only for video */ + if( p_info->i_cat == VIDEO_ES ) + { + if( b_after ) + { + while(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME) ) + { + if( !AVI_SetStreamChunk( p_input, p_info, + p_info->i_idxposc + 1 ) ) + { + return( 0 ); + } + } + } + else + { + while( ( p_info->i_idxposc > 0 ) && + (!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) ) + { + + if( !AVI_SetStreamChunk( p_input, p_info, + p_info->i_idxposc - 1 ) ) + { + + return( 0 ); + } + } + } + } + return( 1 ); +} + +/* make difference between audio and video pts as little as possible */ +static void AVI_SynchroReInit( input_thread_t *p_input ) +{ + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + +#define p_info_video p_avi_demux->p_info_video +#define p_info_audio p_avi_demux->p_info_audio + if( ( !p_info_audio )||( !p_info_video ) ) + { + return; + } + /* now resynch audio video video */ + /*don't care of AVIF_KEYFRAME */ + if( !p_info_audio->header.i_samplesize ) + { + AVI_SetStreamChunk( p_input, + p_info_audio, + AVI_PTSToChunk( p_info_audio, + AVI_GetPTS( p_info_video ) ) ); + } + else + { + AVI_SetStreamBytes( p_input, + p_info_audio, + AVI_PTSToByte( p_info_audio, + AVI_GetPTS( p_info_video ) ) ); + } +#undef p_info_video +#undef p_info_audio +} + +/***************************************************************************** + * AVI_GetFrameInPES : get dpts length(µs) in pes from stream + ***************************************************************************** + * Handle multiple pes, and set pts to the good value + *****************************************************************************/ +static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + mtime_t i_dpts) +{ + int i; + pes_packet_t *p_pes = NULL; + pes_packet_t *p_pes_tmp = NULL; + pes_packet_t *p_pes_first = NULL; + mtime_t i_pts; + + if( i_dpts < 1000 ) + { + return( NULL ) ; + } + + if( !p_info->header.i_samplesize ) + { + int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 ); + p_pes_first = NULL; + for( i = 0; i < i_chunk; i++ ) + { + /* get pts while is valid */ + i_pts = AVI_GetPTS( p_info ); + + p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info ); + + if( !p_pes_tmp ) + { + return( p_pes_first ); + } + p_pes_tmp->i_pts = i_pts; + if( !p_pes_first ) + { + p_pes_first = p_pes_tmp; + } + else + { + p_pes->p_next = p_pes_tmp; + } + p_pes = p_pes_tmp; + } + return( p_pes_first ); + } + else + { + /* stream is byte based */ + int i_byte = AVI_PTSToByte( p_info, i_dpts); + if( i_byte < 50 ) /* to avoid some problem with audio */ + { + return( NULL ); + } + i_pts = AVI_GetPTS( p_info ); /* ok even with broken index */ + p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte); + + if( p_pes ) + { + p_pes->i_pts = i_pts; + } + return( p_pes ); + } +} +/***************************************************************************** + * AVI_DecodePES : send a pes to decoder + ***************************************************************************** + * Handle multiple pes, and update pts to the good value + *****************************************************************************/ +static inline void AVI_DecodePES( input_thread_t *p_input, + AVIStreamInfo_t *p_info, + pes_packet_t *p_pes ) +{ + pes_packet_t *p_pes_next; + /* input_decode want only one pes, but AVI_GetFrameInPES give + multiple pes so send one by one */ + while( p_pes ) + { + p_pes_next = p_pes->p_next; + p_pes->p_next = NULL; + p_pes->i_pts = input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + p_pes->i_pts * 9/100); + input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes ); + p_pes = p_pes_next; + } + +} + +/***************************************************************************** + * AVIDemux_Seekable: reads and demuxes data packets for stream seekable + ***************************************************************************** + * Called by AVIDemux, that make common work + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int AVIDemux_Seekable( input_thread_t *p_input, + AVIStreamInfo_t *p_info_master, + AVIStreamInfo_t *p_info_slave ) +{ + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + + pes_packet_t *p_pes_master; + pes_packet_t *p_pes_slave; + + /* check for signal from interface */ + if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT ) + { + /* we can supposed that is a seek */ + /* first wait for empty buffer, arbitrary time */ + msleep( DEFAULT_PTS_DELAY ); + /* then try to realign in stream */ + if( !AVI_ReAlign( p_input, p_info_master ) ) + { + return( 0 ); /* assume EOF */ + } + AVI_SynchroReInit( p_input ); + } + + /* take care of newly selected audio ES */ + if( p_info_master->b_selected ) + { + p_info_master->b_selected = 0; + AVI_SynchroReInit( p_input ); + } + if( ( p_info_slave )&&( p_info_slave->b_selected ) ) + { + p_info_slave->b_selected = 0; + AVI_SynchroReInit( p_input ); + } + + /* wait for the good time */ + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); + /* calculate pcr, time when we must read the next data */ + /* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */ + if( p_info_slave ) + { + p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ), + AVI_GetPTS( p_info_slave ) ) * 9/100; + } + else + { + p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100; + } + + /* get video and audio frames */ + p_pes_master = AVI_GetFrameInPES( p_input, + p_info_master, + 100000 ); /* 100 ms */ + AVI_DecodePES( p_input, + p_info_master, + p_pes_master); + + + if( p_info_slave ) + { + p_pes_slave = AVI_GetFrameInPES( p_input, + p_info_slave, + AVI_GetPTS( p_info_master ) - + AVI_GetPTS( p_info_slave) ); + AVI_DecodePES( p_input, + p_info_slave, + p_pes_slave ); + } + + + /* at the end ? */ + return( p_pes_master ? 1 : 0 ); + +} + +/***************************************************************************** + * AVIDemux_NotSeekable: reads and demuxes data packets for stream seekable + ***************************************************************************** + * Called by AVIDemux, that makes common work + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ + +/* 0 if can be load/updated, 1 if skip, 2 if descend into, 3 if exit, 4 if error and need recover */ +static int __AVIDemux_ChunkAction( int i_streams_max, + riffchunk_t *p_ck ) +{ + int i_stream; + int i_type; + + AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type ); + if( i_stream < i_streams_max ) + { + return( 0 ); /* read and/or update stream info */ + } + + if( i_stream <= 99 ) + { + /* should not happen but ... */ + return( 1 ); + } + + /* now we know that it's not a stream */ + + switch( p_ck->i_id ) + { + case( FOURCC_JUNK ): + return( 1 ); + case( FOURCC_idx1 ): + return( 3 ); + case( FOURCC_LIST ): + if( p_ck->i_type == FOURCC_rec ) + { + return( 2 ); + } + else + { + return( 1 ); + } + default: + break; + } + /* test for ix?? */ + + if( ( p_ck->i_id & 0xFFFF ) == VLC_TWOCC( 'i','x' ) ) + { + return( 1 ); + } + + return( 4 ); +} + +static int AVI_NotSeekableRecover( input_thread_t *p_input ) +{ + byte_t *p_id; + u32 i_id; + int i_number, i_type; + data_packet_t *p_pack; + + for( ; ; ) + { + if( input_Peek( p_input, &p_id, 4 ) < 4 ) + { + return( 0 ); /* Failed */ + } + i_id = GetDWLE( p_id ); + switch( i_id ) + { + case( FOURCC_idx1 ): + case( FOURCC_JUNK ): + case( FOURCC_LIST ): + return( 1 ); + default: + AVI_ParseStreamHeader( i_id, &i_number, &i_type ); + if( i_number <= 99 ) + { + switch( i_type ) + { + case( TWOCC_wb ): + case( TWOCC_db ): + case( TWOCC_dc ): + case( TWOCC_pc ): + return( 1 ); + } + } + else + { + + } + } + /* Read 1 byte VERY unoptimised */ + if( input_SplitBuffer( p_input, &p_pack, 1) < 1 ) + { + return( 0 ); + } + input_DeletePacket( p_input->p_method_data, p_pack); + } + +} + +static int AVIDemux_NotSeekable( input_thread_t *p_input, + AVIStreamInfo_t *p_info_master, + AVIStreamInfo_t *p_info_slave ) +{ + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + int i_loop; + int i_stream; + int i_type; + + riffchunk_t *p_ck; + pes_packet_t *p_pes; + +/* + i_filepos = AVI_TellAbsolute( p_input ); + p_input->pf_seek( p_input, i_filepos ); + input_AccessReinit( p_input ); +*/ + +#define p_info p_avi_demux->pp_info[i_stream] + + /* The managment is very basic, we will read packets, caclulate pts + and send it to decoder, synchro made on video, and audio is very less + important */ + + /* wait the good time */ + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); + /* TODO be smart, seeing if we can wait for min( audio, video ) + or there is a too big deep */ + if( !p_info_slave ) + { + p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100; + } + else + { + p_avi_demux->i_pcr = __MIN( AVI_GetPTS( p_info_master ), + AVI_GetPTS( p_info_slave ) ) * 9/100; + p_avi_demux->i_pcr = AVI_GetPTS( p_info_master ) * 9/100; + } + + for( i_loop = 0; i_loop < 10; i_loop++ ) + { + int b_load =0; + + /* first find a ck for master or slave */ + do + { + + if( !(p_ck = RIFF_ReadChunk( p_input ) ) ) + { + msg_Err( p_input, "Badd" ); + return( 0 ); /* assume EOF */ + } + //msg_Err( p_input,"Looking ck: %4.4s %d",&p_ck->i_id, p_ck->i_size ); + + switch( __AVIDemux_ChunkAction( p_avi_demux->i_streams, p_ck ) ) + { + case( 0 ): /* load it if possible */ + b_load = 1; + break; + case( 1 ): /* skip it */ + RIFF_DeleteChunk( p_input, p_ck ); + if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 ) + { + return( 0 ); + } + b_load = 0; + break; + case( 2 ): /* descend into */ + RIFF_DeleteChunk( p_input, p_ck ); + RIFF_DescendChunk( p_input ); + b_load = 0; + break; + case( 3 ): /* exit */ + RIFF_DeleteChunk( p_input, p_ck ); + return( 0 ); + case( 4 ): /* Error */ + RIFF_DeleteChunk( p_input, p_ck ); + msg_Warn( p_input, "unknown chunk id 0x%8.8x, trying to recover", p_ck->i_id ); + if( !AVI_NotSeekableRecover( p_input ) ) + { + msg_Err( p_input, "cannot recover, dying" ); + return( -1 ); + } + else + { + msg_Warn( p_input, "recovered sucessfully" ); + } + b_load = 0; + break; + } + + } while( !b_load ); + + AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type ); + /* now check if we really have to load it */ + if( ( p_info != p_info_master )&&( p_info != p_info_slave ) ) + { + b_load = 0; + } + else + { + if( p_info == p_info_master ) + { + b_load = 1; + } + else + { + mtime_t i_dpts; + i_dpts = AVI_GetPTS( p_info_slave ) - + AVI_GetPTS( p_info_master ); + if( i_dpts < 0 ) {i_dpts = - i_dpts; } + if( i_dpts < 600000 ) + { + b_load = 1; + } + else + { + b_load = 0; + } + } + + } + + /* now do we can load this chunk ? */ + if( b_load ) + { + + if( __AVI_GetDataInPES( p_input, &p_pes, p_ck->i_size + 8, 1) != p_ck->i_size + 8) + { + return( 0 ); + } + p_pes->p_first->p_payload_start += 8; + p_pes->i_pes_size -= 8; + /* get PTS */ + p_pes->i_pts = AVI_GetPTS( p_info ); + AVI_DecodePES( p_input, p_info, p_pes ); + } + else + { + + if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 ) + { + RIFF_DeleteChunk( p_input, p_ck ); + return( 0 ); + } + } + + /* finaly update stream information */ + if( p_info->header.i_samplesize ) + { + p_info->i_idxposb += p_ck->i_size; + } + else + { + p_info->i_idxposc++; + } + + RIFF_DeleteChunk( p_input, p_ck ); + } + + return( 1 ); +#undef p_info +} +/***************************************************************************** + * AVIDemux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + * TODO add support for unstreable file, just read a chunk and send it + * to the right decoder, very easy + *****************************************************************************/ + +static int AVIDemux( input_thread_t *p_input ) +{ + int i; + AVIStreamInfo_t *p_info_master; + AVIStreamInfo_t *p_info_slave; + + demux_data_avi_file_t *p_avi_demux = + (demux_data_avi_file_t*)p_input->p_demux_data; + + /* search new video and audio stream selected + if current have been unselected*/ + if( ( !p_avi_demux->p_info_video ) + || ( !p_avi_demux->p_info_video->p_es->p_decoder_fifo ) ) + { + p_avi_demux->p_info_video = NULL; + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { + if( ( p_avi_demux->pp_info[i]->i_cat == VIDEO_ES ) + &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) ) + { + p_avi_demux->p_info_video = p_avi_demux->pp_info[i]; + p_avi_demux->p_info_video->b_selected = 1; + break; + } + } + } + if( ( !p_avi_demux->p_info_audio ) + ||( !p_avi_demux->p_info_audio->p_es->p_decoder_fifo ) ) + { + p_avi_demux->p_info_audio = NULL; + for( i = 0; i < p_avi_demux->i_streams; i++ ) + { + if( ( p_avi_demux->pp_info[i]->i_cat == AUDIO_ES ) + &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) ) + { + p_avi_demux->p_info_audio = p_avi_demux->pp_info[i]; + p_avi_demux->p_info_audio->b_selected = 1; + break; + } + } + } + /* by default video is master for resync audio (after a seek .. ) */ + if( p_avi_demux->p_info_video ) + { + p_info_master = p_avi_demux->p_info_video; + p_info_slave = p_avi_demux->p_info_audio; + } + else + { + p_info_master = p_avi_demux->p_info_audio; + p_info_slave = NULL; + } + + if( !p_info_master ) + { + msg_Err( p_input, "no stream selected" ); + return( -1 ); + } + + /* manage rate, if not default: skeep audio */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( p_input->stream.control.i_rate != p_avi_demux->i_rate ) + { + if( p_avi_demux->p_info_audio) + { + p_avi_demux->p_info_audio->b_selected = 1; + } + p_avi_demux->i_rate = p_input->stream.control.i_rate; + } + vlc_mutex_unlock( &p_input->stream.stream_lock ); + p_avi_demux->i_rate = DEFAULT_RATE; + if( p_avi_demux->i_rate != DEFAULT_RATE ) + { + p_info_slave = NULL; + } + + if( p_avi_demux->b_seekable ) + { + return( AVIDemux_Seekable( p_input, + p_info_master, + p_info_slave) ); + } + else + { + return( AVIDemux_NotSeekable( p_input, + p_info_master, + p_info_slave ) ); + } +} + + + diff --git a/modules/demux/avi/avi.h b/modules/demux/avi/avi.h new file mode 100644 index 0000000000..4f169c05e6 --- /dev/null +++ b/modules/demux/avi/avi.h @@ -0,0 +1,263 @@ +/***************************************************************************** + * avi.h : AVI file Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: avi.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define MAX_PACKETS_IN_FIFO 2 + +/* flags for use in in AVIFileHdr */ +#define AVIF_HASINDEX 0x00000010 /* Index at end of file? */ +#define AVIF_MUSTUSEINDEX 0x00000020 +#define AVIF_ISINTERLEAVED 0x00000100 +#define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames? */ +#define AVIF_WASCAPTUREFILE 0x00010000 +#define AVIF_COPYRIGHTED 0x00020000 + +/* Flags for index */ +#define AVIIF_LIST 0x00000001L /* chunk is a 'LIST' */ +#define AVIIF_KEYFRAME 0x00000010L /* this frame is a key frame.*/ +#define AVIIF_NOTIME 0x00000100L /* this frame doesn't take any time */ +#define AVIIF_COMPUSE 0x0FFF0000L /* these bits are for compressor use */ + +#define AVIIF_FIXKEYFRAME 0x00001000L /* invented; used to say that + the keyframe flag isn't a true flag + but have to be verified */ + +/* AVI stuff */ +#define FOURCC_RIFF VLC_FOURCC('R','I','F','F') +#define FOURCC_LIST VLC_FOURCC('L','I','S','T') +#define FOURCC_JUNK VLC_FOURCC('J','U','N','K') +#define FOURCC_AVI VLC_FOURCC('A','V','I',' ') +#define FOURCC_WAVE VLC_FOURCC('W','A','V','E') + +#define FOURCC_avih VLC_FOURCC('a','v','i','h') +#define FOURCC_hdrl VLC_FOURCC('h','d','r','l') +#define FOURCC_movi VLC_FOURCC('m','o','v','i') +#define FOURCC_idx1 VLC_FOURCC('i','d','x','1') + +#define FOURCC_strl VLC_FOURCC('s','t','r','l') +#define FOURCC_strh VLC_FOURCC('s','t','r','h') +#define FOURCC_strf VLC_FOURCC('s','t','r','f') +#define FOURCC_strd VLC_FOURCC('s','t','r','d') + +#define FOURCC_rec VLC_FOURCC('r','e','c',' ') +#define FOURCC_auds VLC_FOURCC('a','u','d','s') +#define FOURCC_vids VLC_FOURCC('v','i','d','s') + +#define TWOCC_wb VLC_TWOCC('w','b') +#define TWOCC_db VLC_TWOCC('d','b') +#define TWOCC_dc VLC_TWOCC('d','c') +#define TWOCC_pc VLC_TWOCC('p','c') + +/* MPEG4 video */ +#define FOURCC_DIVX VLC_FOURCC('D','I','V','X') +#define FOURCC_divx VLC_FOURCC('d','i','v','x') +#define FOURCC_DIV1 VLC_FOURCC('D','I','V','1') +#define FOURCC_div1 VLC_FOURCC('d','i','v','1') +#define FOURCC_MP4S VLC_FOURCC('M','P','4','S') +#define FOURCC_mp4s VLC_FOURCC('m','p','4','s') +#define FOURCC_M4S2 VLC_FOURCC('M','4','S','2') +#define FOURCC_m4s2 VLC_FOURCC('m','4','s','2') +#define FOURCC_xvid VLC_FOURCC('x','v','i','d') +#define FOURCC_XVID VLC_FOURCC('X','V','I','D') +#define FOURCC_XviD VLC_FOURCC('X','v','i','D') +#define FOURCC_DX50 VLC_FOURCC('D','X','5','0') +#define FOURCC_mp4v VLC_FOURCC('m','p','4','v') +#define FOURCC_4 VLC_FOURCC( 4, 0, 0, 0 ) + +/* MSMPEG4 v2 */ +#define FOURCC_MPG4 VLC_FOURCC('M','P','G','4') +#define FOURCC_mpg4 VLC_FOURCC('m','p','g','4') +#define FOURCC_DIV2 VLC_FOURCC('D','I','V','2') +#define FOURCC_div2 VLC_FOURCC('d','i','v','2') +#define FOURCC_MP42 VLC_FOURCC('M','P','4','2') +#define FOURCC_mp42 VLC_FOURCC('m','p','4','2') + +/* MSMPEG4 v3 / M$ mpeg4 v3 */ +#define FOURCC_MPG3 VLC_FOURCC('M','P','G','3') +#define FOURCC_mpg3 VLC_FOURCC('m','p','g','3') +#define FOURCC_div3 VLC_FOURCC('d','i','v','3') +#define FOURCC_MP43 VLC_FOURCC('M','P','4','3') +#define FOURCC_mp43 VLC_FOURCC('m','p','4','3') + +/* DivX 3.20 */ +#define FOURCC_DIV3 VLC_FOURCC('D','I','V','3') +#define FOURCC_DIV4 VLC_FOURCC('D','I','V','4') +#define FOURCC_div4 VLC_FOURCC('d','i','v','4') +#define FOURCC_DIV5 VLC_FOURCC('D','I','V','5') +#define FOURCC_div5 VLC_FOURCC('d','i','v','5') +#define FOURCC_DIV6 VLC_FOURCC('D','I','V','6') +#define FOURCC_div6 VLC_FOURCC('d','i','v','6') + +/* AngelPotion stuff */ +#define FOURCC_AP41 VLC_FOURCC('A','P','4','1') + +/* ?? */ +#define FOURCC_3IV1 VLC_FOURCC('3','I','V','1') +/* H263 and H263i */ +#define FOURCC_H263 VLC_FOURCC('H','2','6','3') +#define FOURCC_h263 VLC_FOURCC('h','2','6','3') +#define FOURCC_U263 VLC_FOURCC('U','2','6','3') +#define FOURCC_I263 VLC_FOURCC('I','2','6','3') +#define FOURCC_i263 VLC_FOURCC('i','2','6','3') + +/* Sound formats */ +#define WAVE_FORMAT_UNKNOWN 0x0000 +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_MPEG 0x0050 +#define WAVE_FORMAT_MPEGLAYER3 0x0055 +#define WAVE_FORMAT_A52 0x2000 + +typedef struct bitmapinfoheader_s +{ + u32 i_size; /* size of header */ + u32 i_width; + u32 i_height; + u16 i_planes; + u16 i_bitcount; + u32 i_compression; + u32 i_sizeimage; + u32 i_xpelspermeter; + u32 i_ypelspermeter; + u32 i_clrused; + u32 i_clrimportant; +} bitmapinfoheader_t; + +typedef struct waveformatex_s +{ + u16 i_formattag; + u16 i_channels; + u32 i_samplespersec; + u32 i_avgbytespersec; + u16 i_blockalign; + u16 i_bitspersample; + u16 i_size; /* the extra size in bytes */ +} waveformatex_t; + + +typedef struct MainAVIHeader_s +{ + u32 i_microsecperframe; + u32 i_maxbytespersec; + u32 i_reserved1; /* dwPaddingGranularity; pad to multiples of this + size; normally 2K */ + u32 i_flags; + u32 i_totalframes; + u32 i_initialframes; + u32 i_streams; + u32 i_suggestedbuffersize; + u32 i_width; + u32 i_height; + u32 i_scale; + u32 i_rate; + u32 i_start; + u32 i_length; + +} MainAVIHeader_t; + +typedef struct AVIStreamHeader_s +{ + u32 i_type; + u32 i_handler; + u32 i_flags; + u32 i_reserved1; /* wPriority wLanguage */ + u32 i_initialframes; + u32 i_scale; + u32 i_rate; + u32 i_start; + u32 i_length; /* In units above... */ + u32 i_suggestedbuffersize; + u32 i_quality; + u32 i_samplesize; + +} AVIStreamHeader_t; + +typedef struct AVIIndexEntry_s +{ + u32 i_id; + u32 i_flags; + u32 i_pos; + u32 i_length; + u32 i_lengthtotal; +} AVIIndexEntry_t; + +typedef struct AVIESBuffer_s +{ + struct AVIESBuffer_s *p_next; + + pes_packet_t *p_pes; + int i_posc; + int i_posb; +} AVIESBuffer_t; + + +typedef struct AVIStreamInfo_s +{ + + riffchunk_t *p_strl; + riffchunk_t *p_strh; + riffchunk_t *p_strf; + riffchunk_t *p_strd; /* not used */ + + AVIStreamHeader_t header; + + u8 i_cat; /* AUDIO_ES, VIDEO_ES */ + bitmapinfoheader_t video_format; + waveformatex_t audio_format; + es_descriptor_t *p_es; + int b_selected; /* newly selected */ + AVIIndexEntry_t *p_index; + int i_idxnb; + int i_idxmax; + + int i_idxposc; /* numero of chunk */ + int i_idxposb; /* byte in the current chunk */ + + /* add some buffering */ + AVIESBuffer_t *p_pes_first; + AVIESBuffer_t *p_pes_last; + int i_pes_count; + int i_pes_totalsize; +} AVIStreamInfo_t; + +typedef struct demux_data_avi_file_s +{ + mtime_t i_pcr; + int i_rate; + riffchunk_t *p_riff; + riffchunk_t *p_hdrl; + riffchunk_t *p_movi; + riffchunk_t *p_idx1; + + int b_seekable; + + /* Info extrated from avih */ + MainAVIHeader_t avih; + + /* number of stream and informations*/ + int i_streams; + AVIStreamInfo_t **pp_info; + + /* current audio and video es */ + AVIStreamInfo_t *p_info_video; + AVIStreamInfo_t *p_info_audio; + +} demux_data_avi_file_t; + diff --git a/modules/demux/avi/libioRIFF.c b/modules/demux/avi/libioRIFF.c new file mode 100644 index 0000000000..bc23680c78 --- /dev/null +++ b/modules/demux/avi/libioRIFF.c @@ -0,0 +1,442 @@ +/***************************************************************************** + * libioRIFF.c : AVI file Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: libioRIFF.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ + +#include +#include + +#include "video.h" + +#include "libioRIFF.h" + +static inline u16 __GetWLE( byte_t *p_buff ) +{ + return( (*p_buff) + ( *(p_buff+1) <<8 ) ); +} + +static inline u32 __GetDWLE( byte_t *p_buff ) +{ + return( *(p_buff) + ( *(p_buff+1) <<8 ) + + ( *(p_buff+2) <<16 ) + ( *(p_buff+3) <<24 ) ); +} + +static inline u32 __EVEN( u32 i ) +{ + return( (i & 1) ? ++i : i ); +} + +int __RIFF_TellPos( input_thread_t *p_input, u32 *pos ) +{ + vlc_mutex_lock( &p_input->stream.stream_lock ); + *pos= p_input->stream.p_selected_area->i_tell - + ( p_input->p_last_data - p_input->p_current_data ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + return 0; +} + +int __RIFF_SkipBytes(input_thread_t * p_input,int nb) +{ + data_packet_t *p_pack; + int i; + int i_rest; + if( ( p_input->stream.b_seekable )&&( p_input->stream.i_method == INPUT_METHOD_FILE ) ) + { + u32 i_pos; + __RIFF_TellPos( p_input, &i_pos); + p_input->pf_seek( p_input, (off_t)(i_pos + nb) ); + input_AccessReinit( p_input ); + } + else + { + msg_Warn( p_input, "cannot seek, it will take times" ); + if( nb < 0 ) { return( -1 ); } + i_rest = nb; + while (i_rest != 0 ) + { + if ( i_rest >= 4096 ) + { + i = input_SplitBuffer( p_input, &p_pack, 4096); + } + else + { + i = input_SplitBuffer( p_input, &p_pack, i_rest); + } + + if ( i < 0 ) { return ( -1 ); } + i_rest-=i; + input_DeletePacket( p_input->p_method_data, p_pack); + if( ( i == 0 )&&( i_rest != 0 )) { return( -1 ); } + } + } + return ( 0 ); +} + + +void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk ) +{ + if( p_chunk != NULL) + { + if( p_chunk->p_data != NULL ) + { + input_DeletePacket( p_input->p_method_data, p_chunk->p_data ); + } + free( p_chunk ); + } +} + +riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input) +{ + riffchunk_t * p_riff; + int count; + byte_t * p_peek; + + if( !(p_riff = malloc( sizeof(riffchunk_t))) ) + { + return( NULL ); + } + + p_riff->p_data = NULL; + /* peek to have the begining, 8+8 get i_8bytes */ + + if( ( count = input_Peek( p_input, &p_peek, 16 ) ) < 8 ) + { + msg_Err( p_input, "cannot peek()" ); + free(p_riff); + return( NULL ); + } + + p_riff->i_id = __GetDWLE( p_peek ); + p_riff->i_size =__GetDWLE( p_peek + 4 ); + p_riff->i_type = ( count >= 12 ) ? __GetDWLE( p_peek + 8 ) : 0 ; + memset( &p_riff->i_8bytes, 0, 8 ); + if( count >= 12 ) + { + memcpy( &p_riff->i_8bytes, p_peek + 8, count - 8 ); + } + __RIFF_TellPos(p_input, &(p_riff->i_pos) ); + + return( p_riff ); +} + +/************************************************** + * Va au chunk juste d'apres si il en a encore * + * -1 si erreur , 1 si y'en a plus * + **************************************************/ +int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather) +{ + int i_len; + int i_lenfather; + riffchunk_t *p_riff; + + if( ( p_riff = RIFF_ReadChunk( p_input ) ) == NULL ) + { + msg_Err( p_input, "cannot read chunk" ); + return( -1 ); + } + i_len = __EVEN( p_riff->i_size ); + + if ( p_rifffather != NULL ) + { + i_lenfather = __EVEN( p_rifffather->i_size ); + if ( p_rifffather->i_pos + i_lenfather <= p_riff->i_pos + i_len + 8 ) + { + msg_Err( p_input, "next chunk out of bounds" ); + free( p_riff ); + return( 1 ); /* pas dans nos frontiere */ + } + } + if ( __RIFF_SkipBytes( p_input,i_len + 8 ) != 0 ) + { + free( p_riff ); + msg_Err( p_input, "cannot go to the next chunk" ); + return( -1 ); + } + free( p_riff ); + return( 0 ); +} + +/**************************************************************** + * Permet de rentrer dans un ck RIFF ou LIST * + ****************************************************************/ +int RIFF_DescendChunk(input_thread_t * p_input) +{ + return( __RIFF_SkipBytes(p_input,12) != 0 ? -1 : 0 ); +} + +/*************************************************************** + * Permet de sortir d'un sous chunk et d'aller sur le suivant * + * chunk * + ***************************************************************/ + +int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_riff) +{ + int i_skip; + u32 i_posactu; + + __RIFF_TellPos(p_input, &i_posactu); + i_skip = __EVEN( p_riff->i_pos + p_riff->i_size + 8 ) - i_posactu; + return( (( __RIFF_SkipBytes(p_input,i_skip)) != 0) ? -1 : 0 ); +} + +/*************************************************************** + * Permet de se deplacer jusqu'au premier chunk avec le bon id * + * *************************************************************/ +int RIFF_FindChunk(input_thread_t * p_input ,u32 i_id,riffchunk_t *p_rifffather) +{ + riffchunk_t *p_riff = NULL; + do + { + if ( p_riff ) + { + free(p_riff); + if ( RIFF_NextChunk(p_input ,p_rifffather) != 0 ) + { + return( -1 ); + } + } + p_riff=RIFF_ReadChunk(p_input); + } while ( ( p_riff )&&( p_riff->i_id != i_id ) ); + + if ( ( !p_riff )||( p_riff->i_id != i_id ) ) + { + return( -1 ); + } + free( p_riff ); + return( 0 ); +} + +/***************************************************************** + * Permet de pointer sur la zone de donné du chunk courant * + *****************************************************************/ +int RIFF_GoToChunkData(input_thread_t * p_input) +{ + return( ( __RIFF_SkipBytes(p_input,8) != 0 ) ? -1 : 0 ); +} + +int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff ) +{ + off_t i_read = __EVEN( p_riff->i_size ); + + RIFF_GoToChunkData(p_input); + if ( input_SplitBuffer( p_input, + &p_riff->p_data, + i_read ) != i_read ) + { + msg_Err( p_input, "cannot read enough data " ); + return ( -1 ); + } + + if( p_riff->i_size&1 ) + { + p_riff->p_data->p_payload_end--; + } + return( 0 ); +} + +int RIFF_LoadChunkDataInPES(input_thread_t * p_input, + pes_packet_t **pp_pes, + int i_size_index) +{ + u32 i_read; + data_packet_t *p_data; + riffchunk_t *p_riff; + int i_size; + int b_pad = 0; + + if( (p_riff = RIFF_ReadChunk( p_input )) == NULL ) + { + *pp_pes = NULL; + return( -1 ); + } + RIFF_GoToChunkData(p_input); + *pp_pes = input_NewPES( p_input->p_method_data ); + + if( *pp_pes == NULL ) + { + return( -1 ); + } + + if( (!p_riff->i_size) || (!i_size_index ) ) + { + i_size = __MAX( i_size_index, p_riff->i_size ); + } + else + { + i_size = __MIN( p_riff->i_size, i_size_index ); + } + + if( !p_riff->i_size ) + { + p_data = input_NewPacket( p_input->p_method_data, 0 ); + (*pp_pes)->p_first = p_data; + (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data = 1; + (*pp_pes)->i_pes_size = 0; + return( 0 ); + } + if( i_size&1 ) + { + i_size++; + b_pad = 1; + } + + do + { + i_read = input_SplitBuffer(p_input, &p_data, i_size - + (*pp_pes)->i_pes_size ); + if( i_read < 0 ) + { + /* FIXME free on all packets */ + return( -1 ); + } + if( (*pp_pes)->p_first == NULL ) + { + (*pp_pes)->p_first = p_data; + (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data = 1; + (*pp_pes)->i_pes_size = ( p_data->p_payload_end - + p_data->p_payload_start ); + } + else + { + (*pp_pes)->p_last->p_next = p_data; + (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data++; + (*pp_pes)->i_pes_size += ( p_data->p_payload_end - + p_data->p_payload_start ); + } + } while( ((*pp_pes)->i_pes_size < i_size)&&(i_read != 0) ); + + if( b_pad ) + { + (*pp_pes)->i_pes_size--; + (*pp_pes)->p_last->p_payload_end--; + } + return( 0 ); +} + +int RIFF_GoToChunk(input_thread_t * p_input, riffchunk_t *p_riff) +{ + if( p_input->stream.b_seekable ) + { + p_input->pf_seek( p_input, (off_t)p_riff->i_pos ); + input_AccessReinit( p_input ); + return( 0 ); + } + return( -1 ); +} + +int RIFF_TestFileHeader( input_thread_t * p_input, riffchunk_t ** pp_riff, u32 i_type ) +{ + if( !( *pp_riff = RIFF_ReadChunk( p_input ) ) ) + { + return( -1 ); + } + if( (*pp_riff)->i_id != VLC_FOURCC('R','I','F','F') + || (*pp_riff)->i_type != i_type ) + { + free( *pp_riff ); + return( -1 ); + } + return( 0 ); +} + + +int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type ) +{ + *pp_fmt = NULL; + if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0) + { + return( -1 ); + } + if ( ( (*pp_fmt = RIFF_ReadChunk( p_input )) == NULL) + || ( RIFF_LoadChunkData( p_input, *pp_fmt ) != 0 ) ) + { + if( *pp_fmt != NULL ) + { + RIFF_DeleteChunk( p_input, *pp_fmt ); + } + return( -1 ); + } + return( 0 ); +} + +int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type ) +{ + *pp_data = NULL; + if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0) + { + return( -1 ); + } + if ( ( *pp_data = RIFF_ReadChunk( p_input ) ) == NULL ) + { + return( -1 ); + } + if ( RIFF_GoToChunkData( p_input ) != 0 ) + { + RIFF_DeleteChunk( p_input, *pp_data ); + return( -1 ); + } + return( 0 ); +} + +int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type ) +{ + int i_ok; + + *pp_riff = NULL; + i_ok = 0; + while( i_ok == 0 ) + { + if( *pp_riff != NULL ) + { + free( *pp_riff ); + } + if( RIFF_FindChunk( p_input, + VLC_FOURCC('L','I','S','T'), p_rifffather ) != 0 ) + { + return( -1 ); + } + *pp_riff = RIFF_ReadChunk( p_input ); + + if( *pp_riff == NULL ) + { + return( -1 ); + } + if( (*pp_riff)->i_type != i_type ) + { + if( RIFF_NextChunk( p_input, p_rifffather ) != 0 ) + { + return( -1 ); + } + } + else + { + i_ok = 1; + } + } + return( 0 ); +} diff --git a/modules/demux/avi/libioRIFF.h b/modules/demux/avi/libioRIFF.h new file mode 100644 index 0000000000..6f096679be --- /dev/null +++ b/modules/demux/avi/libioRIFF.h @@ -0,0 +1,67 @@ +/***************************************************************************** + * libioRIFF.h : AVI file Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: libioRIFF.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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. + *****************************************************************************/ + +typedef struct riffchunk_s +{ + u32 i_id; + u32 i_size; + u32 i_type; + u32 i_pos; + data_packet_t *p_data; + u64 i_8bytes; /* it's the first 8 bytes after header + used for key frame generation */ +} riffchunk_t; + +int __RIFF_TellPos( input_thread_t *p_input, u32 *pos ); +int __RIFF_SkipBytes(input_thread_t * p_input,int nb); +void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk ); +riffchunk_t *RIFF_ReadChunk(input_thread_t * p_input); +int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather); +int RIFF_DescendChunk(input_thread_t * p_input); +int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_riff); +int RIFF_FindChunk(input_thread_t * p_input, + u32 i_id,riffchunk_t *p_rifffather); +int RIFF_GoToChunkData(input_thread_t * p_input); +int RIFF_LoadChunkData(input_thread_t * p_input, + riffchunk_t *p_riff ); +int RIFF_LoadChunkDataInPES(input_thread_t * p_input, + pes_packet_t **pp_pes, + int i_size_index); + +int RIFF_GoToChunk(input_thread_t * p_input, + riffchunk_t *p_riff); +int RIFF_TestFileHeader( input_thread_t * p_input, + riffchunk_t ** pp_riff, + u32 i_type ); +int RIFF_FindAndLoadChunk( input_thread_t * p_input, + riffchunk_t *p_riff, + riffchunk_t **pp_fmt, + u32 i_type ); +int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, + riffchunk_t *p_riff, + riffchunk_t **pp_data, + u32 i_type ); +int RIFF_FindListChunk( input_thread_t *p_input, + riffchunk_t **pp_riff, + riffchunk_t *p_rifffather, + u32 i_type ); + diff --git a/modules/demux/mp4/.cvsignore b/modules/demux/mp4/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/demux/mp4/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/demux/mp4/Makefile b/modules/demux/mp4/Makefile new file mode 100644 index 0000000000..ed545ed66b --- /dev/null +++ b/modules/demux/mp4/Makefile @@ -0,0 +1 @@ +mp4_SOURCES = mp4.c libmp4.c diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c new file mode 100644 index 0000000000..c77b0a6a09 --- /dev/null +++ b/modules/demux/mp4/libmp4.c @@ -0,0 +1,2307 @@ +/***************************************************************************** + * libmp4.c : LibMP4 library for mp4 module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: libmp4.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include +#include + +#include +#include + +#include /* for compressed moov */ +#include "libmp4.h" + +/***************************************************************************** + * Here are defined some macro to make life simpler but before using it + * *look* at the code. + * + * XXX: All macro are written in capital letters + * + *****************************************************************************/ +#define MP4_BOX_HEADERSIZE( p_box ) \ + ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \ + + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) ) + +#define MP4_BOX_DESCEND( p_box ) \ + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) ); + +#define MP4_GET1BYTE( dst ) \ + dst = *p_peek; p_peek++; i_read-- + +#define MP4_GET2BYTES( dst ) \ + dst = GetWBE( p_peek ); p_peek += 2; i_read -= 2 + +#define MP4_GET3BYTES( dst ) \ + dst = Get24bBE( p_peek ); p_peek += 3; i_read -= 3 + +#define MP4_GET4BYTES( dst ) \ + dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4 + +#define MP4_GETFOURCC( dst ) \ + dst = GetDWLE( p_peek ); p_peek += 4; i_read -= 4 + +#define MP4_GET8BYTES( dst ) \ + dst = GetQWBE( p_peek ); p_peek += 8; i_read -= 8 + +#define MP4_GETVERSIONFLAGS( p_void ) \ + MP4_GET1BYTE( p_void->i_version ); \ + MP4_GET3BYTES( p_void->i_flags ) + +#define MP4_GETSTRINGZ( p_str ) \ + if( ( i_read > 0 )&&(p_peek[0] ) ) \ + { \ + p_str = calloc( sizeof( char ), __MIN( strlen( p_peek ), i_read )+1);\ + memcpy( p_str, p_peek, __MIN( strlen( p_peek ), i_read ) ); \ + p_str[__MIN( strlen( p_peek ), i_read )] = 0; \ + p_peek += strlen( p_str ) + 1; \ + i_read -= strlen( p_str ) + 1; \ + } \ + else \ + { \ + p_str = NULL; \ + } + + +#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \ + s64 i_read = p_box->i_size; \ + u8 *p_peek, *p_buff; \ + i_read = p_box->i_size; \ + if( !( p_peek = p_buff = malloc( i_read ) ) ) \ + { \ + return( 0 ); \ + } \ + if( !MP4_ReadStream( p_stream, p_peek, i_read ) )\ + { \ + free( p_buff ); \ + return( 0 ); \ + } \ + p_peek += MP4_BOX_HEADERSIZE( p_box ); \ + i_read -= MP4_BOX_HEADERSIZE( p_box ); \ + if( !( p_box->data.p_data = malloc( sizeof( MP4_Box_data_TYPE_t ) ) ) ) \ + { \ + free( p_buff ); \ + return( 0 ); \ + } + + +#define MP4_READBOX_EXIT( i_code ) \ + if( !i_code ) \ + free( p_buff ); \ + if( i_read < 0 ) \ + { \ + msg_Warn( p_stream->p_input, "Not enougth data" ); \ + } \ + return( i_code ) + +#define FREE( p ) \ + if( p ) {free( p ); p = NULL; } + + + +/* Some assumptions: + * The input method HAVE to be seekable + +*/ + +/* Some functions to manipulate memory */ +static u16 GetWLE( u8 *p_buff ) +{ + return( (p_buff[0]) + ( p_buff[1] <<8 ) ); +} + +static u32 GetDWLE( u8 *p_buff ) +{ + return( p_buff[0] + ( p_buff[1] <<8 ) + + ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) ); +} + +static u16 GetWBE( u8 *p_buff ) +{ + return( (p_buff[0]<<8) + p_buff[1] ); +} + +static u32 Get24bBE( u8 *p_buff ) +{ + return( ( p_buff[0] <<16 ) + ( p_buff[1] <<8 ) + p_buff[2] ); +} + + +static u32 GetDWBE( u8 *p_buff ) +{ + return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) + + ( p_buff[2] <<8 ) + p_buff[3] ); +} + +static u64 GetQWBE( u8 *p_buff ) +{ + return( ( (u64)GetDWBE( p_buff ) << 32 )|( (u64)GetDWBE( p_buff + 4 ) ) ); +} + + +static void GetUUID( UUID_t *p_uuid, u8 *p_buff ) +{ + memcpy( p_uuid, + p_buff, + 16 ); +} + +static void CreateUUID( UUID_t *p_uuid, u32 i_fourcc ) +{ + /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71 + where XXXXXXXX is the fourcc */ + /* FIXME implement this */ +} + +/* some functions for mp4 encoding of variables */ + +void MP4_ConvertDate2Str( char *psz, u64 i_date ) +{ + int i_day; + int i_hour; + int i_min; + int i_sec; + + i_day = i_date / ( 60*60*24); + i_hour = ( i_date /( 60*60 ) ) % 60; + i_min = ( i_date / 60 ) % 60; + i_sec = i_date % 60; + /* FIXME do it correctly, date begin at 1 jan 1904 */ + sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", + i_day, i_hour, i_min, i_sec ); +} + + + +/***************************************************************************** + * Some basic functions to manipulate stream more easily in vlc + * + * MP4_TellAbsolute get file position + * + * MP4_SeekAbsolute seek in the file + * + * MP4_ReadData read data from the file in a buffer + * + *****************************************************************************/ +off_t MP4_TellAbsolute( input_thread_t *p_input ) +{ + off_t i_pos; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + i_pos= p_input->stream.p_selected_area->i_tell - + ( p_input->p_last_data - p_input->p_current_data ); + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( i_pos ); +} + +int MP4_SeekAbsolute( input_thread_t *p_input, + off_t i_pos) +{ + off_t i_filepos; + + if( i_pos >= p_input->stream.p_selected_area->i_size ) + { + return( 0 ); + } + + i_filepos = MP4_TellAbsolute( p_input ); + if( i_pos != i_filepos ) + { + p_input->pf_seek( p_input, i_pos ); + input_AccessReinit( p_input ); + } + return( 1 ); +} + +/* return 1 if success, 0 if fail */ +int MP4_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size ) +{ + data_packet_t *p_data; + + int i_read; + + + if( !i_size ) + { + return( 1 ); + } + + do + { + i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) ); + if( i_read <= 0 ) + { + return( 0 ); + } + memcpy( p_buff, p_data->p_payload_start, i_read ); + input_DeletePacket( p_input->p_method_data, p_data ); + + p_buff += i_read; + i_size -= i_read; + + } while( i_size ); + + return( 1 ); +} + +/***************************************************************************** + * Some basic functions to manipulate MP4_Stream_t, an abstraction o p_input + * in the way that you can read from a memory buffer or from an input + * + *****************************************************************************/ + +/**** ------- First some function to make abstract from input -------- */ + +/**************************************************************************** + * MP4_InputStream create an stram with an input + * + ****************************************************************************/ +MP4_Stream_t *MP4_InputStream( input_thread_t *p_input ) +{ + MP4_Stream_t *p_stream; + + if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) ) + { + return( NULL ); + } + p_stream->b_memory = 0; + p_stream->p_input = p_input; + p_stream->i_start = 0; + p_stream->i_stop = 0; + p_stream->p_buffer = NULL; + return( p_stream ); +} + + +/**************************************************************************** + * MP4_MemoryStream create a memory stream + * if p_buffer == NULL, will allocate a buffer of i_size, else + * it uses p_buffer XXX you have to unallocate it yourself ! + * + ****************************************************************************/ +MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input, + int i_size, u8 *p_buffer ) +{ + MP4_Stream_t *p_stream; + + if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) ) + { + return( NULL ); + } + p_stream->b_memory = 1; + p_stream->p_input = p_input; + p_stream->i_start = 0; + p_stream->i_stop = i_size; + if( !p_stream->p_buffer ) + { + if( !( p_stream->p_buffer = malloc( i_size ) ) ) + { + free( p_stream ); + return( NULL ); + } + } + else + { + p_stream->p_buffer = p_buffer; + } + + return( p_stream ); +} +/**************************************************************************** + * MP4_ReadStream read from a MP4_Stream_t + * + ****************************************************************************/ +int MP4_ReadStream( MP4_Stream_t *p_stream, u8 *p_buff, int i_size ) +{ + if( p_stream->b_memory ) + { + if( i_size > p_stream->i_stop - p_stream->i_start ) + { + return( 0 ); + } + memcpy( p_buff, + p_stream->p_buffer + p_stream->i_start, + i_size ); + p_stream->i_start += i_size; + return( 1 ); + } + else + { + return( MP4_ReadData( p_stream->p_input, p_buff, i_size ) ); + } +} + +/**************************************************************************** + * MP4_PeekStream peek from a MP4_Stream_t + * + ****************************************************************************/ +int MP4_PeekStream( MP4_Stream_t *p_stream, u8 **pp_peek, int i_size ) +{ + if( p_stream->b_memory ) + { + *pp_peek = p_stream->p_buffer + p_stream->i_start; + + return( __MIN(i_size,p_stream->i_stop - p_stream->i_start )); + } + else + { + return( input_Peek( p_stream->p_input, pp_peek, i_size ) ); + } +} + +/**************************************************************************** + * MP4_TellStream give absolute position in the stream + * XXX for a memory stream give position from begining of the buffer + ****************************************************************************/ +off_t MP4_TellStream( MP4_Stream_t *p_stream ) +{ + if( p_stream->b_memory ) + { + return( p_stream->i_start ); + } + else + { + return( MP4_TellAbsolute( p_stream->p_input ) ); + } +} + +/**************************************************************************** + * MP4_SeekStream seek in a MP4_Stream_t + * + ****************************************************************************/ +int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos) +{ + if( p_stream->b_memory ) + { + if( i_pos < p_stream->i_stop ) + { + p_stream->i_start = i_pos; + return( 1 ); + } + else + { + return( 0 ); + } + } + else + { + return( MP4_SeekAbsolute( p_stream->p_input, i_pos ) ); + } +} + + + +/***************************************************************************** + * MP4_ReadBoxCommon : Load only common parameters for all boxes + ***************************************************************************** + * p_box need to be an already allocated MP4_Box_t, and all data + * will only be peek not read + * + * RETURN : 0 if it fail, 1 otherwise + *****************************************************************************/ +int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i_read; + u8 *p_peek; + + if( ( ( i_read = MP4_PeekStream( p_stream, &p_peek, 32 ) ) < 8 ) ) + { + return( 0 ); + } + p_box->i_pos = MP4_TellStream( p_stream ); + + p_box->data.p_data = NULL; + p_box->p_father = NULL; + p_box->p_first = NULL; + p_box->p_last = NULL; + p_box->p_next = NULL; + + MP4_GET4BYTES( p_box->i_shortsize ); + MP4_GETFOURCC( p_box->i_type ); + + /* Now special case */ + + if( p_box->i_shortsize == 1 ) + { + /* get the true size on 64 bits */ + MP4_GET8BYTES( p_box->i_size ); + } + else + { + p_box->i_size = p_box->i_shortsize; + /* XXX size of 0 means that the box extends to end of file */ + } + + if( p_box->i_type == FOURCC_uuid ) + { + /* get extented type on 16 bytes */ + GetUUID( &p_box->i_uuid, p_peek ); + p_peek += 16; i_read -= 16; + } + else + { + CreateUUID( &p_box->i_uuid, p_box->i_type ); + } +#ifdef MP4_VERBOSE + /* FIXME how to write u64 ??? */ + if( p_box->i_size ) + { + msg_Dbg( p_stream->p_input, "Found Box: %c%c%c%c size %d", + (p_box->i_type)&0xff, (p_box->i_type>>8)&0xff, + (p_box->i_type>>16)&0xff, (p_box->i_type>>24)&0xff, + (u32)p_box->i_size ); + } +#endif + + return( 1 ); +} + + +/***************************************************************************** + * MP4_MP4_NextBox : Go to the next box + ***************************************************************************** + * if p_box == NULL, go to the next box in witch we are( at the begining ). + *****************************************************************************/ +int MP4_NextBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_Box_t box; + + if( !p_box ) + { + MP4_ReadBoxCommon( p_stream, &box ); + p_box = &box; + } + + if( !p_box->i_size ) + { + return( 2 ); /* Box with infinite size */ + } + + if( p_box->p_father ) + { + /* check if it's within p-father */ + if( p_box->i_size + p_box->i_pos >= + p_box->p_father->i_size + p_box->p_father->i_pos ) + { + return( 0 ); /* out of bound */ + } + } + return( MP4_SeekStream( p_stream, p_box->i_size + p_box->i_pos ) ); +} +/***************************************************************************** + * MP4_MP4_GotoBox : Go to this particular box + ***************************************************************************** + * RETURN : 0 if it fail, 1 otherwise + *****************************************************************************/ +int MP4_GotoBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + return( MP4_SeekStream( p_stream, p_box->i_pos ) ); +} + + +/***************************************************************************** + * For all known box a loader is given, + * XXX: all common struct have to be already read by MP4_ReadBoxCommon + * after called one of theses functions, file position is unknown + * you need to call MP4_GotoBox to go where you want + *****************************************************************************/ +int MP4_ReadBoxContainerRaw( MP4_Stream_t *p_stream, MP4_Box_t *p_container ) +{ + MP4_Box_t *p_box; + + if( MP4_TellStream( p_stream ) + 8 > + p_container->i_pos + p_container->i_size ) + { + /* there is no box to load */ + return( 0 ); + } + + do + { + p_box = malloc( sizeof( MP4_Box_t ) ); + + if( MP4_ReadBox( p_stream, p_box , p_container ) ) + { + /* chain this box with the father and the other at same level */ + if( !p_container->p_first ) + { + p_container->p_first = p_box; + } + else + { + p_container->p_last->p_next = p_box; + } + p_container->p_last = p_box; + } + else + { + /* free memory */ + free( p_box ); + break; + } + + }while( MP4_NextBox( p_stream, p_box ) == 1 ); + + return( 1 ); +} + + +int MP4_ReadBoxContainer( MP4_Stream_t *p_stream, MP4_Box_t *p_container ) +{ + + if( p_container->i_size <= MP4_BOX_HEADERSIZE(p_container ) + 8 ) + { + /* container is empty, 8 stand for the first header in this box */ + return( 1 ); + } + + /* enter box */ + MP4_BOX_DESCEND( p_container ); + + return( MP4_ReadBoxContainerRaw( p_stream, p_container ) ); +} + +void MP4_FreeBox_Common( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + /* Up to now do nothing */ +} + +int MP4_ReadBoxSkip( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + /* Nothing to do */ +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Skip box: \"%c%c%c%c\"", + (p_box->i_type)&0xff, + (p_box->i_type>>8)&0xff, + (p_box->i_type>>16)&0xff, + (p_box->i_type>>24)&0xff ); +#endif + return( 1 ); +} + +int MP4_ReadBox_ftyp( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_ftyp_t ); + + MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand ); + MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version ); + + if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) ) + { + int i; + p_box->data.p_ftyp->i_compatible_brands = + calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(u32)); + + for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ ) + { + MP4_GETFOURCC( p_box->data.p_ftyp->i_compatible_brands[i] ); + } + } + else + { + p_box->data.p_ftyp->i_compatible_brands = NULL; + } + + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_ftyp( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_ftyp->i_compatible_brands ); +} + + +int MP4_ReadBox_mvhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; +#ifdef MP4_VERBOSE + char s_creation_time[128]; + char s_modification_time[128]; + char s_duration[128]; +#endif + MP4_READBOX_ENTER( MP4_Box_data_mvhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_mvhd ); + + if( p_box->data.p_mvhd->i_version ) + { + MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time ); + MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale ); + MP4_GET8BYTES( p_box->data.p_mvhd->i_duration ); + } + else + { + MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time ); + MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale ); + MP4_GET4BYTES( p_box->data.p_mvhd->i_duration ); + } + MP4_GET4BYTES( p_box->data.p_mvhd->i_rate ); + MP4_GET2BYTES( p_box->data.p_mvhd->i_volume ); + MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 ); + + + for( i = 0; i < 2; i++ ) + { + MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] ); + } + for( i = 0; i < 9; i++ ) + { + MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] ); + } + for( i = 0; i < 6; i++ ) + { + MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] ); + } + + MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id ); + + +#ifdef MP4_VERBOSE + MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time ); + MP4_ConvertDate2Str( s_modification_time, + p_box->data.p_mvhd->i_modification_time ); + if( p_box->data.p_mvhd->i_rate ) + { + MP4_ConvertDate2Str( s_duration, + p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate ); + } + else + { + s_duration[0] = 0; + } + msg_Dbg( p_stream->p_input, "Read Box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d", + s_creation_time, + s_modification_time, + (u32)p_box->data.p_mvhd->i_timescale, + s_duration, + (float)p_box->data.p_mvhd->i_rate / (1<<16 ), + (float)p_box->data.p_mvhd->i_volume / 256 , + (u32)p_box->data.p_mvhd->i_next_track_id ); +#endif + MP4_READBOX_EXIT( 1 ); +} + +int MP4_ReadBox_tkhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; +#ifdef MP4_VERBOSE + char s_creation_time[128]; + char s_modification_time[128]; + char s_duration[128]; +#endif + MP4_READBOX_ENTER( MP4_Box_data_tkhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_tkhd ); + + if( p_box->data.p_tkhd->i_version ) + { + MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time ); + MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved ); + MP4_GET8BYTES( p_box->data.p_tkhd->i_duration ); + } + else + { + MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_duration ); + } + + for( i = 0; i < 2; i++ ) + { + MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] ); + } + MP4_GET2BYTES( p_box->data.p_tkhd->i_layer ); + MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined ); + MP4_GET2BYTES( p_box->data.p_tkhd->i_volume ); + MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 ); + + for( i = 0; i < 9; i++ ) + { + MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] ); + } + MP4_GET4BYTES( p_box->data.p_tkhd->i_width ); + MP4_GET4BYTES( p_box->data.p_tkhd->i_height ); + +#ifdef MP4_VERBOSE + MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time ); + MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time ); + MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration ); + + msg_Dbg( p_stream->p_input, "Read Box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f", + s_creation_time, + s_modification_time, + s_duration, + p_box->data.p_tkhd->i_track_ID, + p_box->data.p_tkhd->i_layer, + (float)p_box->data.p_tkhd->i_volume / 256 , + (float)p_box->data.p_tkhd->i_width / 65536, + (float)p_box->data.p_tkhd->i_height / 65536 ); +#endif + MP4_READBOX_EXIT( 1 ); +} + +int MP4_ReadBox_tref( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + + if( p_box->i_size < MP4_BOX_HEADERSIZE(p_box ) + 8 ) + { + /* container is empty, 8 stand for the first header in this box */ + return( 1 ); + } + + if( !MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) ) ) + { + return( 0 ); + } + + MP4_ReadBoxContainerRaw( p_stream, p_box ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"tref\" " ); + +#endif + return( 1 ); +} + + + +int MP4_ReadBox_mdhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + u16 i_language; +#ifdef MP4_VERBOSE + char s_creation_time[128]; + char s_modification_time[128]; + char s_duration[128]; +#endif + MP4_READBOX_ENTER( MP4_Box_data_mdhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_mdhd ); + + if( p_box->data.p_mdhd->i_version ) + { + MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time ); + MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale ); + MP4_GET8BYTES( p_box->data.p_mdhd->i_duration ); + } + else + { + MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time ); + MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time ); + MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale ); + MP4_GET4BYTES( p_box->data.p_mdhd->i_duration ); + } + i_language = GetWBE( p_peek ); + for( i = 0; i < 3; i++ ) + { + p_box->data.p_mdhd->i_language[i] = + ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60; + } + + MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined ); + +#ifdef MP4_VERBOSE + MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time ); + MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time ); + MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration ); + msg_Dbg( p_stream->p_input, "Read Box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c", + s_creation_time, + s_modification_time, + (u32)p_box->data.p_mdhd->i_timescale, + s_duration, + p_box->data.p_mdhd->i_language[0], + p_box->data.p_mdhd->i_language[1], + p_box->data.p_mdhd->i_language[2] ); +#endif + MP4_READBOX_EXIT( 1 ); +} + + +int MP4_ReadBox_hdlr( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_hdlr_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_hdlr ); + + MP4_GET4BYTES( p_box->data.p_hdlr->i_predefined ); + MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type ); + + p_box->data.p_hdlr->psz_name = calloc( sizeof( char ), i_read + 1 ); + memcpy( p_box->data.p_hdlr->psz_name, p_peek, i_read ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"hdlr\" hanler type %c%c%c%c name %s", + ( p_box->data.p_hdlr->i_handler_type )&0xff, + ( p_box->data.p_hdlr->i_handler_type >> 8 )&0xff, + ( p_box->data.p_hdlr->i_handler_type >> 16 )&0xff, + ( p_box->data.p_hdlr->i_handler_type >> 24 )&0xff, + p_box->data.p_hdlr->psz_name ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_hdlr( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_hdlr->psz_name ); +} + +int MP4_ReadBox_vmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_vmhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_vmhd ); + + MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode ); + for( i = 0; i < 3; i++ ) + { + MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] ); + } + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)", + p_box->data.p_vmhd->i_graphics_mode, + p_box->data.p_vmhd->i_opcolor[0], + p_box->data.p_vmhd->i_opcolor[1], + p_box->data.p_vmhd->i_opcolor[2] ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +int MP4_ReadBox_smhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_smhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_smhd ); + + + + MP4_GET2BYTES( p_box->data.p_smhd->i_balance ); + + MP4_GET2BYTES( p_box->data.p_smhd->i_reserved ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"smhd\" balance %f", + (float)p_box->data.p_smhd->i_balance / 256 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + + +int MP4_ReadBox_hmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_hmhd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_hmhd ); + + MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size ); + MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size ); + + MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate ); + MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate ); + + MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d", + p_box->data.p_hmhd->i_max_PDU_size, + p_box->data.p_hmhd->i_avg_PDU_size, + p_box->data.p_hmhd->i_max_bitrate, + p_box->data.p_hmhd->i_avg_bitrate ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +int MP4_ReadBox_url( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_url_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_url ); + MP4_GETSTRINGZ( p_box->data.p_url->psz_location ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"url\" url: %s", + p_box->data.p_url->psz_location ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + + +void MP4_FreeBox_url( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_url->psz_location ) +} + +int MP4_ReadBox_urn( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_urn_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_urn ); + + MP4_GETSTRINGZ( p_box->data.p_urn->psz_name ); + MP4_GETSTRINGZ( p_box->data.p_urn->psz_location ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"urn\" name %s location %s", + p_box->data.p_urn->psz_name, + p_box->data.p_urn->psz_location ); +#endif + MP4_READBOX_EXIT( 1 ); +} +void MP4_FreeBox_urn( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_urn->psz_name ); + FREE( p_box->data.p_urn->psz_location ); +} + + +int MP4_ReadBox_dref( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_dref_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_dref ); + + MP4_GET4BYTES( p_box->data.p_dref->i_entry_count ); + + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 ); + MP4_ReadBoxContainerRaw( p_stream, p_box ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"dref\" entry-count %d", + p_box->data.p_dref->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + + +int MP4_ReadBox_stts( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + MP4_READBOX_ENTER( MP4_Box_data_stts_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stts ); + MP4_GET4BYTES( p_box->data.p_stts->i_entry_count ); + + p_box->data.p_stts->i_sample_count = + calloc( sizeof( u32 ), p_box->data.p_stts->i_entry_count ); + p_box->data.p_stts->i_sample_delta = + calloc( sizeof( u32 ), p_box->data.p_stts->i_entry_count ); + + for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ ) + { + MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] ); + MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stts\" entry-count %d", + p_box->data.p_stts->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stts( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stts->i_sample_count ); + FREE( p_box->data.p_stts->i_sample_delta ); + +} + +int MP4_ReadBox_ctts( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + MP4_READBOX_ENTER( MP4_Box_data_ctts_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_ctts ); + + MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count ); + + p_box->data.p_ctts->i_sample_count = + calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count ); + p_box->data.p_ctts->i_sample_offset = + calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count ); + + for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ ) + { + MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] ); + MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"ctts\" entry-count %d", + p_box->data.p_ctts->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_ctts( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_ctts->i_sample_count ); + FREE( p_box->data.p_ctts->i_sample_offset ); +} + +static int MP4_ReadLengthDescriptor( u8 **pp_peek, s64 *i_read ) +{ + int i_b; + int i_len = 0; + do + { + i_b = **pp_peek; + + (*pp_peek)++; + (*i_read)--; + i_len = ( i_len << 7 ) + ( i_b&0x7f ); + } while( i_b&0x80 ); + return( i_len ); +} + +int MP4_ReadBox_esds( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ +#define es_descriptor p_box->data.p_esds->es_descriptor + int i_len; + int i_flags; + int i_type; + + MP4_READBOX_ENTER( MP4_Box_data_esds_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_esds ); + + + MP4_GET1BYTE( i_type ); + if( i_type == 0x03 ) /* MP4ESDescrTag */ + { + i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read ); + + MP4_GET2BYTES( es_descriptor.i_ES_ID ); + MP4_GET1BYTE( i_flags ); + es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0); + es_descriptor.b_url = ( (i_flags&0x40) != 0); + es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0); + + es_descriptor.i_stream_priority = i_flags&0x1f; + if( es_descriptor.b_stream_dependence ) + { + MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID ); + } + if( es_descriptor.b_url ) + { + int i_len; + + MP4_GET1BYTE( i_len ); + es_descriptor.psz_URL = calloc( sizeof(char), i_len + 1 ); + memcpy( es_descriptor.psz_URL, p_peek, i_len ); + es_descriptor.psz_URL[i_len] = 0; + p_peek += i_len; + i_read -= i_len; + } + else + { + es_descriptor.psz_URL = NULL; + } + if( es_descriptor.b_OCRstream ) + { + MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID ); + } + MP4_GET1BYTE( i_type ); /* get next type */ + } + + if( i_type != 0x04)/* MP4DecConfigDescrTag */ + { + MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */ + } + + i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read ); + es_descriptor.p_decConfigDescr = + malloc( sizeof( MP4_descriptor_decoder_config_t )); + + MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication ); + MP4_GET1BYTE( i_flags ); + es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2; + es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01; + MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB ); + MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate ); + MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate ); + MP4_GET1BYTE( i_type ); + if( i_type != 0x05 )/* MP4DecSpecificDescrTag */ + { + MP4_READBOX_EXIT( 1 ); + } + + i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read ); + es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len; + es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len ); + memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info, + p_peek, i_len ); + + MP4_READBOX_EXIT( 1 ); + +#undef es_descriptor +} + +void MP4_FreeBox_esds( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_esds->es_descriptor.psz_URL ); + FREE( p_box->data.p_esds->es_descriptor.p_decConfigDescr ); +} + +int MP4_ReadBox_sample_soun( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t ); + + for( i = 0; i < 6 ; i++ ) + { + MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index ); + + for( i = 0; i < 2 ; i++ ) + { + MP4_GET4BYTES( p_box->data.p_sample_soun->i_reserved2[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount ); + MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize ); + MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined ); + MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 ); + MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi ); + MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo ); + + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 ); + MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */ + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"soun\" in stsd channel %d sample size %d sampl rate %f", + p_box->data.p_sample_soun->i_channelcount, + p_box->data.p_sample_soun->i_samplesize, + (float)p_box->data.p_sample_soun->i_sampleratehi + + (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +#if 0 +int MP4_ReadBox_sample_mp4a( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_sample_mp4a_t ); + + for( i = 0; i < 6 ; i++ ) + { + MP4_GET1BYTE( p_box->data.p_sample_mp4a->i_reserved1[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_data_reference_index ); + + for( i = 0; i < 2 ; i++ ) + { + MP4_GET4BYTES( p_box->data.p_sample_mp4a->i_reserved2[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_channelcount ); + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_samplesize ); + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_predefined ); + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_reserved3 ); + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratehi ); + MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratelo ); + + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 ); + MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */ + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"mp4a\" in stsd channel %d sample size %d sampl rate %f", + p_box->data.p_sample_mp4a->i_channelcount, + p_box->data.p_sample_mp4a->i_samplesize, + (float)p_box->data.p_sample_mp4a->i_sampleratehi + + (float)p_box->data.p_sample_mp4a->i_sampleratelo / 65536 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} +#endif + +int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t ); + + for( i = 0; i < 6 ; i++ ) + { + MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index ); + + MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined1 ); + MP4_GET2BYTES( p_box->data.p_sample_vide->i_reserved2 ); + + for( i = 0; i < 3 ; i++ ) + { + MP4_GET4BYTES( p_box->data.p_sample_vide->i_predefined2[i] ); + } + + MP4_GET2BYTES( p_box->data.p_sample_vide->i_width ); + MP4_GET2BYTES( p_box->data.p_sample_vide->i_height ); + + MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution ); + MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution ); + + MP4_GET4BYTES( p_box->data.p_sample_vide->i_reserved3 ); + MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined3 ); + + memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 ); + p_peek += 32; i_read -= 32; + + MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth ); + MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined4 ); + + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78); + MP4_ReadBoxContainerRaw( p_stream, p_box ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"vide\" in stsd %dx%d depth %d", + p_box->data.p_sample_vide->i_width, + p_box->data.p_sample_vide->i_height, + p_box->data.p_sample_vide->i_depth ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + + +int MP4_ReadBox_stsd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + + MP4_READBOX_ENTER( MP4_Box_data_stsd_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stsd ); + + MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count ); + + MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 ); + + MP4_ReadBoxContainerRaw( p_stream, p_box ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stsd\" entry-count %d", + p_box->data.p_stsd->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + + +int MP4_ReadBox_stsz( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_stsz_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stsz ); + + MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size ); + + MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count ); + + p_box->data.p_stsz->i_entry_size = + calloc( sizeof( u32 ), p_box->data.p_stsz->i_sample_count ); + + if( !p_box->data.p_stsz->i_sample_size ) + { + for( i=0; (idata.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ ) + { + MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] ); + } + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stsz\" sample-size %d sample-count %d", + p_box->data.p_stsz->i_sample_size, + p_box->data.p_stsz->i_sample_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stsz( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stsz->i_entry_size ); +} + +int MP4_ReadBox_stsc( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_stsc_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stsc ); + + MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count ); + + p_box->data.p_stsc->i_first_chunk = + calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count ); + p_box->data.p_stsc->i_samples_per_chunk = + calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count ); + p_box->data.p_stsc->i_sample_description_index = + calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count ); + + for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ ) + { + MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] ); + MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] ); + MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stsc\" entry-count %d", + p_box->data.p_stsc->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stsc( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stsc->i_first_chunk ); + FREE( p_box->data.p_stsc->i_samples_per_chunk ); + FREE( p_box->data.p_stsc->i_sample_description_index ); +} + +int MP4_ReadBox_stco_co64( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_co64_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_co64 ); + + MP4_GET4BYTES( p_box->data.p_co64->i_entry_count ); + + p_box->data.p_co64->i_chunk_offset = + calloc( sizeof( u64 ), p_box->data.p_co64->i_entry_count ); + + for( i = 0; (i < p_box->data.p_co64->i_entry_count )&&( i_read >= 8 ); i++ ) + { + if( p_box->i_type == FOURCC_stco ) + { + MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] ); + } + else + { + MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] ); + } + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"co64\" entry-count %d", + p_box->data.p_co64->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stco_co64( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_co64->i_chunk_offset ); +} + +int MP4_ReadBox_stss( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_stss_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stss ); + + MP4_GET4BYTES( p_box->data.p_stss->i_entry_count ); + + p_box->data.p_stss->i_sample_number = + calloc( sizeof( u32 ), p_box->data.p_stss->i_entry_count ); + + for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ ) + { + + MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stss\" entry-count %d", + p_box->data.p_stss->i_entry_count ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stss( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stss->i_sample_number ) +} + +int MP4_ReadBox_stsh( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_stsh_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stsh ); + + + MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count ); + + p_box->data.p_stsh->i_shadowed_sample_number = + calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count ); + + p_box->data.p_stsh->i_sync_sample_number = + calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count ); + + + for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ ) + { + + MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] ); + MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stsh\" entry-count %d", + p_box->data.p_stsh->i_entry_count ); +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stsh( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stsh->i_shadowed_sample_number ) + FREE( p_box->data.p_stsh->i_sync_sample_number ) +} + + +int MP4_ReadBox_stdp( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_stdp_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_stdp ); + + p_box->data.p_stdp->i_priority = + calloc( sizeof( u16 ), i_read / 2 ); + + for( i = 0; i < i_read / 2 ; i++ ) + { + + MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d", + i_read / 2 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_stdp( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_stdp->i_priority ) +} + +int MP4_ReadBox_padb( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_padb_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_padb ); + + + MP4_GET4BYTES( p_box->data.p_padb->i_sample_count ); + + p_box->data.p_padb->i_reserved1 = + calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 ); + p_box->data.p_padb->i_pad2 = + calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 ); + p_box->data.p_padb->i_reserved2 = + calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 ); + p_box->data.p_padb->i_pad1 = + calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 ); + + + for( i = 0; i < i_read / 2 ; i++ ) + { + p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01; + p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07; + p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01; + p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07; + + p_peek += 1; i_read -= 1; + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d", + i_read / 2 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_padb( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_padb->i_reserved1 ); + FREE( p_box->data.p_padb->i_pad2 ); + FREE( p_box->data.p_padb->i_reserved2 ); + FREE( p_box->data.p_padb->i_pad1 ); +} + +int MP4_ReadBox_elst( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i; + + MP4_READBOX_ENTER( MP4_Box_data_padb_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_elst ); + + + MP4_GET4BYTES( p_box->data.p_elst->i_entry_count ); + + p_box->data.p_elst->i_segment_duration = + calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count ); + p_box->data.p_elst->i_media_time = + calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count ); + p_box->data.p_elst->i_media_rate_integer = + calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count ); + p_box->data.p_elst->i_media_rate_fraction= + calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count ); + + + for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ ) + { + if( p_box->data.p_elst->i_version == 1 ) + { + + MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] ); + + MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] ); + } + else + { + + MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] ); + + MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] ); + } + + MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] ); + MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] ); + } + + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"elst\" entry-count %d", + i_read / 2 ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_elst( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_elst->i_segment_duration ); + FREE( p_box->data.p_elst->i_media_time ); + FREE( p_box->data.p_elst->i_media_rate_integer ); + FREE( p_box->data.p_elst->i_media_rate_fraction ); +} + +int MP4_ReadBox_cprt( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + int i_language; + int i; + + MP4_READBOX_ENTER( MP4_Box_data_cprt_t ); + + MP4_GETVERSIONFLAGS( p_box->data.p_cprt ); + + i_language = GetWBE( p_peek ); + for( i = 0; i < 3; i++ ) + { + p_box->data.p_cprt->i_language[i] = + ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60; + } + p_peek += 2; i_read -= 2; + MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"cprt\" language %c%c%c notice %s", + p_box->data.p_cprt->i_language[0], + p_box->data.p_cprt->i_language[1], + p_box->data.p_cprt->i_language[2], + p_box->data.p_cprt->psz_notice ); + +#endif + MP4_READBOX_EXIT( 1 ); +} + +void MP4_FreeBox_cprt( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_cprt->psz_notice ); +} + + +int MP4_ReadBox_dcom( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_dcom_t ); + + MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm ); +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, + "Read Box: \"dcom\" compression algorithm : %c%c%c%c", + ( p_box->data.p_dcom->i_algorithm )&0xff, + ( p_box->data.p_dcom->i_algorithm >> 8 )&0xff, + ( p_box->data.p_dcom->i_algorithm >> 16 )&0xff, + ( p_box->data.p_dcom->i_algorithm >> 24 )&0xff ); +#endif + + MP4_READBOX_EXIT( 1 ); +} + +int MP4_ReadBox_cmvd( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_READBOX_ENTER( MP4_Box_data_cmvd_t ); + + + MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size ); + + p_box->data.p_cmvd->i_compressed_size = i_read; + + if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) ) + { + msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" not enough memory to load data" ); + return( 1 ); + } + + /* now copy compressed data */ + memcpy( p_box->data.p_cmvd->p_data, + p_peek, + i_read); + + p_box->data.p_cmvd->b_compressed = 1; + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" compressed data size %d", + p_box->data.p_cmvd->i_compressed_size ); +#endif + + MP4_READBOX_EXIT( 1 ); +} +void MP4_FreeBox_cmvd( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + FREE( p_box->data.p_cmvd->p_data ); +} + +int MP4_ReadBox_cmov( MP4_Stream_t *p_stream, MP4_Box_t *p_box ) +{ + MP4_Stream_t *p_stream_memory; + MP4_Box_t *p_umov; + + MP4_Box_t *p_dcom; + MP4_Box_t *p_cmvd; + z_stream z_data; + u8 *p_data; + + int i_result; + + if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) ) + { + msg_Err( p_stream->p_input, "out of memory" ); + return( 0 ); + } + memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) ); + + if( !( p_box->p_father )|| + ( p_box->p_father->i_type != FOURCC_moov ) ) + { + msg_Warn( p_stream->p_input, "Read box: \"cmov\" box alone" ); + return( 1 ); + } + + if( !(i_result = MP4_ReadBoxContainer( p_stream, p_box ) ) ) + { + return( 0 ); + } + + if( !( p_dcom = MP4_FindBox( p_box, FOURCC_dcom ) )|| + !( p_cmvd = MP4_FindBox( p_box, FOURCC_cmvd ) )|| + !( p_cmvd->data.p_cmvd->p_data ) ) + { + msg_Warn( p_stream->p_input, "Read Box: \"cmov\" incomplete" ); + return( 1 ); + } + + if( p_dcom->data.p_dcom->i_algorithm != FOURCC_zlib ) + { + msg_Dbg( p_stream->p_input, "Read Box: \"cmov\" compression algorithm : %c%c%c%c not supported", + ( p_dcom->data.p_dcom->i_algorithm )&0xff, + ( p_dcom->data.p_dcom->i_algorithm >> 8 )&0xff, + ( p_dcom->data.p_dcom->i_algorithm >> 16 )&0xff, + ( p_dcom->data.p_dcom->i_algorithm >> 24 )&0xff ); + return( 1 ); + } + + /* decompress data */ + /* allocate a new buffer */ + if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) ) + { + msg_Err( p_stream->p_input, + "Read Box: \"cmov\" not enough memory to uncompress data" ); + return( 1 ); + } + /* init default structures */ + z_data.next_in = p_cmvd->data.p_cmvd->p_data; + z_data.avail_in = p_cmvd->data.p_cmvd->i_compressed_size; + z_data.next_out = p_data; + z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size; + z_data.zalloc = (alloc_func)Z_NULL; + z_data.zfree = (free_func)Z_NULL; + z_data.opaque = (voidpf)Z_NULL; + + /* init zlib */ + if( ( i_result = inflateInit( &z_data ) ) != Z_OK ) + { + msg_Err( p_stream->p_input, + "Read Box: \"cmov\" error while uncompressing data" ); + free( p_data ); + return( 1 ); + } + + /* uncompress */ + i_result = inflate( &z_data, Z_NO_FLUSH ); + if( ( i_result != Z_OK )&&( i_result != Z_STREAM_END ) ) + { + msg_Err( p_stream->p_input, + "Read Box: \"cmov\" error while uncompressing data" ); + free( p_data ); + return( 1 ); + } + + if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out ) + { + msg_Warn( p_stream->p_input, + "Read Box: \"cmov\" uncompressing data size mismatch" ); + } + p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out; + + /* close zlib */ + i_result = inflateEnd( &z_data ); + if( i_result != Z_OK ) + { + msg_Warn( p_stream->p_input, + "Read Box: \"cmov\" error while uncompressing data (ignored)" ); + } + + + free( p_cmvd->data.p_cmvd->p_data ); + p_cmvd->data.p_cmvd->p_data = p_data; + p_cmvd->data.p_cmvd->b_compressed = 0; + + msg_Dbg( p_stream->p_input, + "Read Box: \"cmov\" box succesfully uncompressed" ); + + /* now create a memory stream */ + p_stream_memory = MP4_MemoryStream( p_stream->p_input, + p_cmvd->data.p_cmvd->i_uncompressed_size, + p_cmvd->data.p_cmvd->p_data ); + + /* and read uncompressd moov */ + p_umov = malloc( sizeof( MP4_Box_t ) ); + + i_result = MP4_ReadBox( p_stream_memory, p_umov, NULL ); + + p_box->data.p_cmov->p_moov = p_umov; + free( p_stream_memory ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream->p_input, + "Read Box: \"cmov\" compressed movie header completed" ); +#endif + return( i_result ); +} + + +/**** ------------------------------------------------------------------- ****/ +/**** "Higher level" Functions ****/ +/**** ------------------------------------------------------------------- ****/ + +static struct +{ + u32 i_type; + int (*MP4_ReadBox_function )( MP4_Stream_t *p_stream, MP4_Box_t *p_box ); + void (*MP4_FreeBox_function )( input_thread_t *p_input, MP4_Box_t *p_box ); +} MP4_Box_Function [] = +{ + /* Containers */ + { FOURCC_moov, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_trak, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_mdia, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_moof, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_minf, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_stbl, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_dinf, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_edts, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_udta, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_nmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_hnti, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + + /* specific box */ + { FOURCC_ftyp, MP4_ReadBox_ftyp, MP4_FreeBox_ftyp }, + { FOURCC_cmov, MP4_ReadBox_cmov, MP4_FreeBox_Common }, + { FOURCC_mvhd, MP4_ReadBox_mvhd, MP4_FreeBox_Common }, + { FOURCC_tkhd, MP4_ReadBox_tkhd, MP4_FreeBox_Common }, + { FOURCC_tref, MP4_ReadBox_tref, MP4_FreeBox_Common }, + { FOURCC_mdhd, MP4_ReadBox_mdhd, MP4_FreeBox_Common }, + { FOURCC_hdlr, MP4_ReadBox_hdlr, MP4_FreeBox_hdlr }, + { FOURCC_vmhd, MP4_ReadBox_vmhd, MP4_FreeBox_Common }, + { FOURCC_smhd, MP4_ReadBox_smhd, MP4_FreeBox_Common }, + { FOURCC_hmhd, MP4_ReadBox_hmhd, MP4_FreeBox_Common }, + { FOURCC_url, MP4_ReadBox_url, MP4_FreeBox_url }, + { FOURCC_urn, MP4_ReadBox_urn, MP4_FreeBox_urn }, + { FOURCC_dref, MP4_ReadBox_dref, MP4_FreeBox_Common }, + { FOURCC_stts, MP4_ReadBox_stts, MP4_FreeBox_stts }, + { FOURCC_ctts, MP4_ReadBox_ctts, MP4_FreeBox_ctts }, + { FOURCC_stsd, MP4_ReadBox_stsd, MP4_FreeBox_Common }, + { FOURCC_stsz, MP4_ReadBox_stsz, MP4_FreeBox_stsz }, + { FOURCC_stsc, MP4_ReadBox_stsc, MP4_FreeBox_stsc }, + { FOURCC_stco, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 }, + { FOURCC_co64, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 }, + { FOURCC_stss, MP4_ReadBox_stss, MP4_FreeBox_stss }, + { FOURCC_stsh, MP4_ReadBox_stsh, MP4_FreeBox_stsh }, + { FOURCC_stdp, MP4_ReadBox_stdp, MP4_FreeBox_stdp }, + { FOURCC_padb, MP4_ReadBox_padb, MP4_FreeBox_padb }, + { FOURCC_elst, MP4_ReadBox_elst, MP4_FreeBox_elst }, + { FOURCC_cprt, MP4_ReadBox_cprt, MP4_FreeBox_cprt }, + { FOURCC_esds, MP4_ReadBox_esds, MP4_FreeBox_esds }, + { FOURCC_dcom, MP4_ReadBox_dcom, MP4_FreeBox_Common }, + { FOURCC_cmvd, MP4_ReadBox_cmvd, MP4_FreeBox_cmvd }, + + /* Nothing to do with this box */ + { FOURCC_mdat, MP4_ReadBoxSkip, MP4_FreeBox_Common }, + { FOURCC_skip, MP4_ReadBoxSkip, MP4_FreeBox_Common }, + { FOURCC_free, MP4_ReadBoxSkip, MP4_FreeBox_Common }, + { FOURCC_wide, MP4_ReadBoxSkip, MP4_FreeBox_Common }, + + /* for codecs */ + { FOURCC_soun, MP4_ReadBox_sample_soun, MP4_FreeBox_Common }, + { FOURCC__mp3, MP4_ReadBox_sample_soun, MP4_FreeBox_Common }, + { FOURCC_ms55, MP4_ReadBox_sample_soun, MP4_FreeBox_Common }, + { FOURCC_mp4a, MP4_ReadBox_sample_soun, MP4_FreeBox_Common }, + + { FOURCC_vide, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_mp4v, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_SVQ1, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_DIVX, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_h263, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_cvid, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_3IV1, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_3IV2, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_mjpa, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_mjpb, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + { FOURCC_mjqt, NULL, NULL }, /* found in mjpa/b */ + { FOURCC_mjht, NULL, NULL }, + + { FOURCC_jpeg, MP4_ReadBox_sample_vide, MP4_FreeBox_Common }, + + { FOURCC_mp4s, NULL, MP4_FreeBox_Common }, + + /* XXX there is 2 box where we could find this entry stbl and tref*/ + { FOURCC_hint, NULL, MP4_FreeBox_Common }, + + /* found in tref box */ + { FOURCC_dpnd, NULL, NULL }, + { FOURCC_ipir, NULL, NULL }, + { FOURCC_mpod, NULL, NULL }, + + /* found in hnti */ + { FOURCC_rtp, NULL, NULL }, + + /* Last entry */ + + { 0, NULL, NULL } +}; + + + +/***************************************************************************** + * MP4_ReadBox : parse the actual box and the children + * XXX : Do not go to the next box + *****************************************************************************/ +int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father ) +{ + int i_result; + int i_index; + + if( !MP4_ReadBoxCommon( p_stream, p_box ) ) + { + msg_Warn( p_stream->p_input, "Cannot read one box" ); + return( 0 ); + } + if( !p_box->i_size ) + { + msg_Dbg( p_stream->p_input, "Found an empty box (null size)" ); + return( 0 ); + } + p_box->p_father = p_father; + + /* Now search function to call */ + for( i_index = 0; ; i_index++ ) + { + if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )|| + ( MP4_Box_Function[i_index].i_type == 0 ) ) + { + break; + } + } + if( MP4_Box_Function[i_index].MP4_ReadBox_function == NULL ) + { + msg_Warn( p_stream->p_input, + "Unknown box type %c%c%c%c (uncompletetly loaded)", + (p_box->i_type)&0xff, + (p_box->i_type>>8)&0xff, + (p_box->i_type>>16)&0xff, + (p_box->i_type>>24)&0xff ); + return( 1 ); + } + else + { + i_result = + (MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ); + } + + if( !MP4_GotoBox( p_stream, p_box ) ) + { + return( 0 ); + } + return( i_result ); +} + +/***************************************************************************** + * MP4_FreeBox : free memory after read with MP4_ReadBox and all + * the children + *****************************************************************************/ +void MP4_FreeBox( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + int i_index; + + MP4_Box_t *p_child; + MP4_Box_t *p_next; + + if( !p_box ) + { + return; /* hehe */ + } + p_child = p_box->p_first; + while( p_child ) + { + p_next = p_child->p_next; + MP4_FreeBox( p_input, p_child ); + /* MP4_FreeBoxChildren have free all data expect p_child itself */ + free( p_child ); + p_child = p_next; + } + + /* Now search function to call */ + if( p_box->data.p_data ) + { + for( i_index = 0; ; i_index++ ) + { + if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )|| + ( MP4_Box_Function[i_index].i_type == 0 ) ) + { + break; + } + } + if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL ) + { + /* Should not happen */ + msg_Warn( p_input, + "cannot free box %c%c%c%c, type unknown", + (p_box->i_type)&0xff, + (p_box->i_type >> 8)&0xff, + (p_box->i_type >> 16)&0xff, + (p_box->i_type >> 24)&0xff ); + } + else + { + MP4_Box_Function[i_index].MP4_FreeBox_function( p_input, p_box ); + } + + free( p_box->data.p_data ); + p_box->data.p_data = NULL; + } + + p_box->p_first = NULL; + p_box->p_last = NULL; + +} + +/***************************************************************************** + * MP4_ReadRoot : Parse the entire file, and create all boxes in memory + ***************************************************************************** + * The first box is a virtual box "root" and is the father for all first + * level boxes for the file, a sort of virtual contener + *****************************************************************************/ +int MP4_ReadBoxRoot( input_thread_t *p_input, MP4_Box_t *p_root ) +{ + + MP4_Stream_t *p_stream; + int i_result; + + MP4_SeekAbsolute( p_input, 0 ); /* Go to the begining */ + p_root->i_pos = 0; + p_root->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' ); + p_root->i_shortsize = 1; + p_root->i_size = p_input->stream.p_selected_area->i_size; + CreateUUID( &p_root->i_uuid, p_root->i_type ); + + p_root->data.p_data = NULL; + p_root->p_father = NULL; + p_root->p_first = NULL; + p_root->p_last = NULL; + p_root->p_next = NULL; + + p_stream = MP4_InputStream( p_input ); + + i_result = MP4_ReadBoxContainerRaw( p_stream, p_root ); + + free( p_stream ); + + if( i_result ) + { + MP4_Box_t *p_child; + MP4_Box_t *p_moov; + MP4_Box_t *p_cmov; + + /* check if there is a cmov, if so replace + compressed moov by uncompressed one */ + if( ( p_moov = MP4_FindBox( p_root, FOURCC_moov ) )&& + ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) ) + { + /* rename the compressed moov as a box to skip */ + p_moov->i_type = FOURCC_skip; + + /* get uncompressed p_moov */ + p_moov = p_cmov->data.p_cmov->p_moov; + p_cmov->data.p_cmov->p_moov = NULL; + + /* make p_root father of this new moov */ + p_moov->p_father = p_root; + + /* insert this new moov box as first child of p_root */ + p_moov->p_next = p_child = p_root->p_first; + p_root->p_first = p_moov; + } + } + return( i_result ); +} + + +static void __MP4_DumpBoxStructure( input_thread_t *p_input, + MP4_Box_t *p_box, int i_level ) +{ + MP4_Box_t *p_child; + + if( !i_level ) + { + msg_Dbg( p_input, "Dumping root Box \"%c%c%c%c \"", + (p_box->i_type ) &0xff, + (p_box->i_type >>8 ) &0xff, + (p_box->i_type >>16 ) &0xff, + (p_box->i_type >>24) &0xff ); + } + else + { + char str[512]; + int i; + memset( str, (u8)' ', 512 ); + for( i = 0; i < i_level; i++ ) + { + str[i*5] = '|'; + } + sprintf( str + i_level * 5, "+ %c%c%c%c size %d", + (p_box->i_type ) &0xff, + (p_box->i_type>>8 ) &0xff, + (p_box->i_type>>16 ) &0xff, + (p_box->i_type>>24 ) &0xff, + (u32)p_box->i_size ); + + msg_Dbg( p_input, "%s", str ); + } + p_child = p_box->p_first; + while( p_child ) + { + __MP4_DumpBoxStructure( p_input, p_child, i_level + 1 ); + p_child = p_child->p_next; + } + +} + +void MP4_DumpBoxStructure( input_thread_t *p_input, MP4_Box_t *p_box ) +{ + __MP4_DumpBoxStructure( p_input, p_box, 0 ); +} + + +/***************************************************************************** + * MP4_CountBox: given a box, count how many child have the requested type + * FIXME : support GUUID + *****************************************************************************/ +int MP4_CountBox( MP4_Box_t *p_box, u32 i_type ) +{ + int i_count; + MP4_Box_t *p_child; + + if( !p_box ) + { + return( 0 ); + } + + i_count = 0; + p_child = p_box->p_first; + while( p_child ) + { + if( p_child->i_type == i_type ) + { + i_count++; + } + p_child = p_child->p_next; + } + + return( i_count ); +} + + +/***************************************************************************** + * MP4_FindBox: find first box with i_type child of p_box + * return NULL if not found + *****************************************************************************/ + +MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, u32 i_type ) +{ + MP4_Box_t *p_child; + + if( !p_box ) + { + return( NULL ); + } + + p_child = p_box->p_first; + while( p_child ) + { + if( p_child->i_type == i_type ) + { + return( p_child ); + } + p_child = p_child->p_next; + } + + return( NULL ); +} + + +/***************************************************************************** + * MP4_FindNextBox: find next box with thesame type and at the same level + * than p_box + *****************************************************************************/ +MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box ) +{ + MP4_Box_t *p_next; + + if( !p_box ) + { + return( NULL ); + } + + p_next = p_box->p_next; + while( p_next ) + { + if( p_next->i_type == p_box->i_type ) + { + return( p_next ); + } + p_next = p_next->p_next; + } + return( NULL ); +} + +/***************************************************************************** + * MP4_FindNbBox: find the box i_number + *****************************************************************************/ +MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, u32 i_number ) +{ + MP4_Box_t *p_child = p_box->p_first; + + if( !p_child ) + { + return( NULL ); + } + + while( i_number ) + { + if( !( p_child = p_child->p_next ) ) + { + return( NULL ); + } + i_number--; + } + return( p_child ); +} + diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h new file mode 100644 index 0000000000..e3e3f281ee --- /dev/null +++ b/modules/demux/mp4/libmp4.h @@ -0,0 +1,804 @@ +/***************************************************************************** + * libmp4.h : LibMP4 library for mp4 module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: libmp4.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define FOURCC_uuid VLC_FOURCC( 'u', 'u', 'i', 'd' ) + +#define FOURCC_ftyp VLC_FOURCC( 'f', 't', 'y', 'p' ) +#define FOURCC_moov VLC_FOURCC( 'm', 'o', 'o', 'v' ) +#define FOURCC_cmov VLC_FOURCC( 'c', 'm', 'o', 'v' ) +#define FOURCC_dcom VLC_FOURCC( 'd', 'c', 'o', 'm' ) +#define FOURCC_cmvd VLC_FOURCC( 'c', 'm', 'v', 'd' ) + +#define FOURCC_moof VLC_FOURCC( 'm', 'o', 'o', 'f' ) +#define FOURCC_mdat VLC_FOURCC( 'm', 'd', 'a', 't' ) +#define FOURCC_skip VLC_FOURCC( 's', 'k', 'i', 'p' ) +#define FOURCC_free VLC_FOURCC( 'f', 'r', 'e', 'e' ) +#define FOURCC_udta VLC_FOURCC( 'u', 'd', 't', 'a' ) +#define FOURCC_wide VLC_FOURCC( 'w', 'i', 'd', 'e' ) + +#define FOURCC_trak VLC_FOURCC( 't', 'r', 'a', 'k' ) +#define FOURCC_mvhd VLC_FOURCC( 'm', 'v', 'h', 'd' ) +#define FOURCC_tkhd VLC_FOURCC( 't', 'k', 'h', 'd' ) +#define FOURCC_tref VLC_FOURCC( 't', 'r', 'e', 'f' ) +#define FOURCC_mdia VLC_FOURCC( 'm', 'd', 'i', 'a' ) +#define FOURCC_mdhd VLC_FOURCC( 'm', 'd', 'h', 'd' ) +#define FOURCC_hdlr VLC_FOURCC( 'h', 'd', 'l', 'r' ) +#define FOURCC_minf VLC_FOURCC( 'm', 'i', 'n', 'f' ) +#define FOURCC_vmhd VLC_FOURCC( 'v', 'm', 'h', 'd' ) +#define FOURCC_smhd VLC_FOURCC( 's', 'm', 'h', 'd' ) +#define FOURCC_hmhd VLC_FOURCC( 'h', 'm', 'h', 'd' ) +#define FOURCC_dinf VLC_FOURCC( 'd', 'i', 'n', 'f' ) +#define FOURCC_url VLC_FOURCC( 'u', 'r', 'l', ' ' ) +#define FOURCC_urn VLC_FOURCC( 'u', 'r', 'n', ' ' ) +#define FOURCC_dref VLC_FOURCC( 'd', 'r', 'e', 'f' ) +#define FOURCC_stbl VLC_FOURCC( 's', 't', 'b', 'l' ) +#define FOURCC_stts VLC_FOURCC( 's', 't', 't', 's' ) +#define FOURCC_ctts VLC_FOURCC( 'c', 't', 't', 's' ) +#define FOURCC_stsd VLC_FOURCC( 's', 't', 's', 'd' ) +#define FOURCC_stsz VLC_FOURCC( 's', 't', 's', 'z' ) +#define FOURCC_stz2 VLC_FOURCC( 's', 't', 'z', '2' ) +#define FOURCC_stsc VLC_FOURCC( 's', 't', 's', 'c' ) +#define FOURCC_stco VLC_FOURCC( 's', 't', 'c', 'o' ) +#define FOURCC_co64 VLC_FOURCC( 'c', 'o', '6', '4' ) +#define FOURCC_stss VLC_FOURCC( 's', 't', 's', 's' ) +#define FOURCC_stsh VLC_FOURCC( 's', 't', 's', 'h' ) +#define FOURCC_stdp VLC_FOURCC( 's', 't', 'd', 'p' ) +#define FOURCC_padb VLC_FOURCC( 'p', 'a', 'd', 'b' ) +#define FOURCC_edts VLC_FOURCC( 'e', 'd', 't', 's' ) +#define FOURCC_elst VLC_FOURCC( 'e', 'l', 's', 't' ) +#define FOURCC_udta VLC_FOURCC( 'u', 'd', 't', 'a' ) +#define FOURCC_mvex VLC_FOURCC( 'm', 'v', 'e', 'x' ) +#define FOURCC_trex VLC_FOURCC( 't', 'r', 'e', 'x' ) +#define FOURCC_mfhd VLC_FOURCC( 'm', 'f', 'h', 'd' ) +#define FOURCC_traf VLC_FOURCC( 't', 'r', 'a', 'f' ) +#define FOURCC_tfhd VLC_FOURCC( 't', 'f', 'h', 'd' ) +#define FOURCC_trun VLC_FOURCC( 't', 'r', 'u', 'n' ) +#define FOURCC_cprt VLC_FOURCC( 'c', 'p', 'r', 't' ) +#define FOURCC_iods VLC_FOURCC( 'i', 'o', 'd', 's' ) + +#define FOURCC_nmhd VLC_FOURCC( 'n', 'm', 'h', 'd' ) +#define FOURCC_mp4v VLC_FOURCC( 'm', 'p', '4', 'v' ) +#define FOURCC_mp4a VLC_FOURCC( 'm', 'p', '4', 'a' ) +#define FOURCC_mp4s VLC_FOURCC( 'm', 'p', '4', 's' ) +#define FOURCC_vide VLC_FOURCC( 'v', 'i', 'd', 'e' ) +#define FOURCC_soun VLC_FOURCC( 's', 'o', 'u', 'n' ) +#define FOURCC_hint VLC_FOURCC( 'h', 'i', 'n', 't' ) + +#define FOURCC_dpnd VLC_FOURCC( 'd', 'p', 'n', 'd' ) +#define FOURCC_ipir VLC_FOURCC( 'i', 'p', 'i', 'r' ) +#define FOURCC_mpod VLC_FOURCC( 'm', 'p', 'o', 'd' ) +#define FOURCC_hnti VLC_FOURCC( 'h', 'n', 't', 'i' ) +#define FOURCC_rtp VLC_FOURCC( 'r', 't', 'p', ' ' ) + +#define FOURCC_isom VLC_FOURCC( 'i', 's', 'o', 'm' ) +#define FOURCC_esds VLC_FOURCC( 'e', 's', 'd', 's' ) + +#define FOURCC_zlib VLC_FOURCC( 'z', 'l', 'i', 'b' ) +#define FOURCC_SVQ1 VLC_FOURCC( 'S', 'V', 'Q', '1' ) +#define FOURCC__mp3 VLC_FOURCC( '.', 'm', 'p', '3' ) +#define FOURCC_ms55 VLC_FOURCC( 'm', 's', 0x0, 0x55 ) +#define FOURCC_3IV1 VLC_FOURCC( '3', 'I', 'V', '1' ) +#define FOURCC_3IV2 VLC_FOURCC( '3', 'I', 'V', '2' ) +#define FOURCC_h263 VLC_FOURCC( 'h', '2', '6', '3' ) +#define FOURCC_DIVX VLC_FOURCC( 'D', 'I', 'V', 'X' ) +#define FOURCC_cvid VLC_FOURCC( 'c', 'v', 'i', 'd' ) +#define FOURCC_mjpa VLC_FOURCC( 'm', 'j', 'p', 'a' ) +#define FOURCC_mjpb VLC_FOURCC( 'm', 'j', 'q', 't' ) +#define FOURCC_mjqt VLC_FOURCC( 'm', 'j', 'h', 't' ) +#define FOURCC_mjht VLC_FOURCC( 'm', 'j', 'p', 'b' ) + +#define FOURCC_jpeg VLC_FOURCC( 'j', 'p', 'e', 'g' ) + +/* Do you want some debug information on all read boxes ? */ +#define MP4_VERBOSE 1 + +/* memory stream and file stream object */ + +typedef struct MP4_Stream_s +{ + int b_memory; /* do we uses a memory buffer */ + + input_thread_t *p_input; + + off_t i_start; /* in the buffer position for memory stream */ + off_t i_stop; + u8 *p_buffer; + +} MP4_Stream_t; + +struct MP4_Box_s; + + +/* uuid Universal Unique IDentifiers */ +typedef struct UUID_s +{ + u8 b[16]; +} UUID_t; + +/* specific structure for all boxes */ + +typedef struct MP4_Box_data_ftyp_s +{ + u32 i_major_brand; + u32 i_minor_version; + + u32 i_compatible_brands_count; + u32 *i_compatible_brands; + +} MP4_Box_data_ftyp_t; + +typedef struct MP4_Box_data_mvhd_s +{ + u8 i_version; + u32 i_flags; + + u64 i_creation_time; + u64 i_modification_time; + u32 i_timescale; + u64 i_duration; + + s32 i_rate; + s16 i_volume; + s16 i_reserved1; + u32 i_reserved2[2]; + s32 i_matrix[9]; + u32 i_predefined[6]; + u32 i_next_track_id; + +} MP4_Box_data_mvhd_t; + +#define MP4_TRACK_ENABLED 0x000001 +#define MP4_TRACK_IN_MOVIE 0x000002 +#define MP4_TRACK_IN_PREVIEW 0x000004 +typedef struct MP4_Box_data_tkhd_s +{ + u8 i_version; + u32 i_flags; + + u64 i_creation_time; + u64 i_modification_time; + u32 i_track_ID; + u32 i_reserved; + u64 i_duration; + + u32 i_reserved2[2]; + s16 i_layer; + s16 i_predefined; + + s16 i_volume; + u16 i_reserved3; + s32 i_matrix[9]; + s32 i_width; + s32 i_height; + +} MP4_Box_data_tkhd_t; + +typedef struct MP4_Box_data_mdhd_s +{ + u8 i_version; + u32 i_flags; + + u64 i_creation_time; + u64 i_modification_time; + u32 i_timescale; + u64 i_duration; + + /* one bit for pad */ + /* unsigned int(5)[3] language difference with 0x60*/ + unsigned char i_language[3]; + u16 i_predefined; + +} MP4_Box_data_mdhd_t; + +typedef struct MP4_Box_data_hdlr_s +{ + u8 i_version; + u32 i_flags; + + u32 i_predefined; + u32 i_handler_type; /* "vide" "soun" "hint" "odsm" + "crsm" "sdsm" "m7sm" "ocsm" + "ipsm" "mjsm" */ + + unsigned char *psz_name; /* in UTF-8 */ + +} MP4_Box_data_hdlr_t; + +typedef struct MP4_Box_data_vmhd_s +{ + u8 i_version; + u32 i_flags; + + s16 i_graphics_mode; + s16 i_opcolor[3]; + +} MP4_Box_data_vmhd_t; + +typedef struct MP4_Box_data_smhd_s +{ + u8 i_version; + u32 i_flags; + + s16 i_balance; + s16 i_reserved; + +} MP4_Box_data_smhd_t; + +typedef struct MP4_Box_data_hmhd_s +{ + u8 i_version; + u32 i_flags; + + u16 i_max_PDU_size; + u16 i_avg_PDU_size; + u32 i_max_bitrate; + u32 i_avg_bitrate; + u32 i_reserved; + +} MP4_Box_data_hmhd_t; + +typedef struct MP4_Box_data_url_s +{ + u8 i_version; + u32 i_flags; + + unsigned char *psz_location; + +} MP4_Box_data_url_t; + +typedef struct MP4_Box_data_urn_s +{ + u8 i_version; + u32 i_flags; + + unsigned char *psz_name; + unsigned char *psz_location; + +} MP4_Box_data_urn_t; + +typedef struct MP4_Box_data_dref_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; +/* XXX it's also a container with i_entry_count entry */ +} MP4_Box_data_dref_t; + +typedef struct MP4_Box_data_stts_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + u32 *i_sample_count; /* these are array */ + s32 *i_sample_delta; + +} MP4_Box_data_stts_t; + +typedef struct MP4_Box_data_ctts_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u32 *i_sample_count; /* these are array */ + s32 *i_sample_offset; + +} MP4_Box_data_ctts_t; + + +typedef struct MP4_Box_data_sample_soun_s +{ + u8 i_reserved1[6]; + u16 i_data_reference_index; + + u32 i_reserved2[2]; + u16 i_channelcount; + u16 i_samplesize; + u16 i_predefined; + u16 i_reserved3; + u16 i_sampleratehi; /* timescale of track */ + u16 i_sampleratelo; + +} MP4_Box_data_sample_soun_t; + +typedef struct MP4_Box_data_sample_vide_s +{ + u8 i_reserved1[6]; + u16 i_data_reference_index; + + u16 i_predefined1; + u16 i_reserved2; + u32 i_predefined2[3]; + + s16 i_width; + s16 i_height; + + u32 i_horizresolution; + u32 i_vertresolution; + + u32 i_reserved3; + u16 i_predefined3; + + u8 i_compressorname[32]; + s16 i_depth; + + s16 i_predefined4; + +} MP4_Box_data_sample_vide_t; + +typedef struct MP4_Box_data_sample_hint_s +{ + u8 i_reserved1[6]; + u16 i_data_reference_index; + + u8 *p_data; + +} MP4_Box_data_sample_hint_t; + +typedef struct MP4_Box_data_moviehintinformation_rtp_s +{ + u32 i_description_format; + unsigned char *psz_text; + +} MP4_Box_data_moviehintinformation_rtp_t; + + + +typedef struct MP4_Box_data_stsd_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + /* it contains SampleEntry handled as if it was Box */ + +} MP4_Box_data_stsd_t; + + +typedef struct MP4_Box_data_stsz_s +{ + u8 i_version; + u32 i_flags; + + u32 i_sample_size; + u32 i_sample_count; + + u32 *i_entry_size; /* array , empty if i_sample_size != 0 */ + +} MP4_Box_data_stsz_t; + +typedef struct MP4_Box_data_stz2_s +{ + u8 i_version; + u32 i_flags; + + u32 i_sample_size; /* 24 bits */ + u8 i_field_size; + u32 i_sample_count; + + u32 *i_entry_size; /* array: unsigned int(i_field_size) entry_size */ + +} MP4_Box_data_stz2_t; + +typedef struct MP4_Box_data_stsc_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u32 *i_first_chunk; /* theses are arrays */ + u32 *i_samples_per_chunk; + u32 *i_sample_description_index; + +} MP4_Box_data_stsc_t; + + +typedef struct MP4_Box_data_co64_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u64 *i_chunk_offset; + +} MP4_Box_data_co64_t; + + +typedef struct MP4_Box_data_stss_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u32 *i_sample_number; + +} MP4_Box_data_stss_t; + +typedef struct MP4_Box_data_stsh_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u32 *i_shadowed_sample_number; + u32 *i_sync_sample_number; + +} MP4_Box_data_stsh_t; + +typedef struct MP4_Box_data_stdp_s +{ + u8 i_version; + u32 i_flags; + + u16 *i_priority; + +} MP4_Box_data_stdp_t; + +typedef struct MP4_Box_data_padb_s +{ + u8 i_version; + u32 i_flags; + + u32 i_sample_count; + + u16 *i_reserved1; /* 1bit */ + u16 *i_pad2; /* 3bits */ + u16 *i_reserved2; /* 1bit */ + u16 *i_pad1; /* 3bits */ + + +} MP4_Box_data_padb_t; + + +typedef struct MP4_Box_data_elst_s +{ + u8 i_version; + u32 i_flags; + + u32 i_entry_count; + + u64 *i_segment_duration; + s64 *i_media_time; + u16 *i_media_rate_integer; + u16 *i_media_rate_fraction; + + +} MP4_Box_data_elst_t; + +typedef struct MP4_Box_data_cprt_s +{ + u8 i_version; + u32 i_flags; + /* 1 pad bit */ + unsigned char i_language[3]; + + unsigned char *psz_notice; +} MP4_Box_data_cprt_t; + + +/* DecoderConfigDescriptor */ +typedef struct MP4_descriptor_decoder_config_s +{ + u8 i_objectTypeIndication; + u8 i_streamType; + int b_upStream; + int i_buffer_sizeDB; + int i_max_bitrate; + int i_avg_bitrate; + + int i_decoder_specific_info_len; + u8 *p_decoder_specific_info; + /* some other stuff */ + +} MP4_descriptor_decoder_config_t; + +typedef struct MP4_descriptor_SL_config_s +{ + +} MP4_descriptor_SL_config_t; + + +typedef struct MP4_descriptor_ES_s +{ + u16 i_ES_ID; + int b_stream_dependence; + int b_url; + int b_OCRstream; + int i_stream_priority; + + int i_depend_on_ES_ID; /* if b_stream_dependence set */ + + unsigned char *psz_URL; + + u16 i_OCR_ES_ID; /* if b_OCRstream */ + MP4_descriptor_decoder_config_t *p_decConfigDescr; + + MP4_descriptor_SL_config_t *p_slConfigDescr; + + /* some other stuff ... */ + +} MP4_descriptor_ES_t; + +/* ES descriptor */ +typedef struct MP4_Box_data_esds_s +{ + u8 i_version; + u32 i_flags; + + MP4_descriptor_ES_t es_descriptor; + +} MP4_Box_data_esds_t; + + +typedef struct MP4_Box_data_dcom_s +{ + u32 i_algorithm; /* fourcc */ + +} MP4_Box_data_dcom_t; + +typedef struct MP4_Box_data_cmvd_s +{ + u32 i_uncompressed_size; + u32 i_compressed_size; + + int b_compressed; /* Set to 1 if compressed data, 0 if uncompressed */ + u8 *p_data; + +} MP4_Box_data_cmvd_t; + +typedef struct MP4_Box_data_cmov_s +{ + struct MP4_Box_s *p_moov; /* uncompressed moov */ + +} MP4_Box_data_cmov_t; + +/* +typedef struct MP4_Box_data_cmov_s +{ + u8 i_version; + u32 i_flags; + +} MP4_Box_data__t; + +*/ + +typedef union MP4_Box_data_s +{ + MP4_Box_data_ftyp_t *p_ftyp; + MP4_Box_data_mvhd_t *p_mvhd; + MP4_Box_data_tkhd_t *p_tkhd; + MP4_Box_data_mdhd_t *p_mdhd; + MP4_Box_data_hdlr_t *p_hdlr; + MP4_Box_data_vmhd_t *p_vmhd; + MP4_Box_data_smhd_t *p_smhd; + MP4_Box_data_hmhd_t *p_hmhd; + MP4_Box_data_url_t *p_url; + MP4_Box_data_urn_t *p_urn; + MP4_Box_data_dref_t *p_dref; + MP4_Box_data_stts_t *p_stts; + MP4_Box_data_ctts_t *p_ctts; + MP4_Box_data_stsd_t *p_stsd; + MP4_Box_data_sample_vide_t *p_sample_vide; + MP4_Box_data_sample_soun_t *p_sample_soun; + MP4_Box_data_sample_hint_t *p_sample_hint; + + MP4_Box_data_esds_t *p_esds; + + MP4_Box_data_stsz_t *p_stsz; + MP4_Box_data_stz2_t *p_stz2; + MP4_Box_data_stsc_t *p_stsc; + MP4_Box_data_co64_t *p_co64; + MP4_Box_data_stss_t *p_stss; + MP4_Box_data_stsh_t *p_stsh; + MP4_Box_data_stdp_t *p_stdp; + MP4_Box_data_padb_t *p_padb; + MP4_Box_data_elst_t *p_elst; + MP4_Box_data_cprt_t *p_cprt; + + MP4_Box_data_dcom_t *p_dcom; + MP4_Box_data_cmvd_t *p_cmvd; + MP4_Box_data_cmov_t *p_cmov; + + MP4_Box_data_moviehintinformation_rtp_t p_moviehintinformation_rtp; + + void *p_data; /* for unknow type */ +} MP4_Box_data_t; + + + +/* the most basic structure */ +typedef struct MP4_Box_s +{ + off_t i_pos; /* absolute position */ + + u32 i_type; + u32 i_shortsize; + + UUID_t i_uuid; /* Set if i_type == "uuid" */ + + u64 i_size; /* always set so use it */ + + MP4_Box_data_t data; /* union of pointers on extended data depending on i_type (or i_usertype) */ + + struct MP4_Box_s *p_father; /* pointer on the father Box */ + + struct MP4_Box_s *p_first; /* pointer on the first child Box */ + struct MP4_Box_s *p_last; + + struct MP4_Box_s *p_next; /* pointer on the next boxes at the same level */ + +} MP4_Box_t; + +/*---------------------------------------------------------------------------*/ +/****----------------------- High level functions ------------------------****/ +/*---------------------------------------------------------------------------*/ + +/***************************************************************************** + * Function for manipulate stream easily + *****************************************************************************/ + +off_t MP4_TellAbsolute( input_thread_t *p_input ); +int MP4_SeekAbsolute( input_thread_t *p_input, off_t i_pos); +int MP4_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size ); + +/***************************************************************************** + * MP4_ReadRoot : Parse the entire file, and create all boxes in memory + ***************************************************************************** + * The first box is a virtual box "root" and is the father for all first + * level boxes + * + * RETURN : 1 if succes and 0 if it failed + *****************************************************************************/ +int MP4_ReadBoxRoot( input_thread_t *p_input, MP4_Box_t *p_root ); + +/***************************************************************************** + * MP4_FreeBox : free memory allocated after read with MP4_ReadBox + * this, means also children boxes + * XXX : all children have to be allocated by a malloc !! and + * p_box isn't freeing + *****************************************************************************/ +void MP4_FreeBox( input_thread_t *p_input, MP4_Box_t *p_box ); + +/***************************************************************************** + * MP4_DumpBoxStructure: print the structure of the p_box + *****************************************************************************/ +void MP4_DumpBoxStructure( input_thread_t *p_input, MP4_Box_t *p_box ); + +/***************************************************************************** + * MP4_CountBox: given a box, count how many child have the requested type + * FIXME : support GUUID + *****************************************************************************/ +int MP4_CountBox( MP4_Box_t *p_box, u32 i_type ); + +/***************************************************************************** + * MP4_FindBox: find first box with i_type child of p_box + * return NULL if not found + *****************************************************************************/ +MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, u32 i_type ); + +/***************************************************************************** + * MP4_FindNextBox: find next box with thesame type and at the same level + * than p_box + *****************************************************************************/ +MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box ); + +/***************************************************************************** + * MP4_FindNbBox: find the box i_number + *****************************************************************************/ +MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, u32 i_number ); + + +/*---------------------------------------------------------------------------*/ +/****----------------------- Lower level functions -----------------------****/ +/**** ****/ +/****------Use them only when you known what they really do and need------****/ +/**** ****/ +/****---------------------------------------------------------------------****/ +/*---------------------------------------------------------------------------*/ + + +/**** ------- First some function to make abstract from input -------- */ + +/**************************************************************************** + * MP4_InputStream create an stram with an input + * + ****************************************************************************/ +MP4_Stream_t *MP4_InputStream( input_thread_t *p_input ); + +/**************************************************************************** + * MP4_MemoryStream create a memory stream + * if p_buffer == NULL, will allocate a buffer of i_size, else + * it uses p_buffer XXX you have to unallocate yourself ! + * + ****************************************************************************/ +MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input, + int i_size, u8 *p_buffer ); + +/**************************************************************************** + * MP4_ReadStream read from a MP4_Stream_t + * + ****************************************************************************/ +int MP4_ReadStream( MP4_Stream_t *p_stream, u8 *p_buff, int i_size ); + +/**************************************************************************** + * MP4_PeekStream guess it ;) + * + ****************************************************************************/ +int MP4_PeekStream( MP4_Stream_t *p_stream, u8 **pp_peek, int i_size ); + +/**************************************************************************** + * MP4_TellStream give absolute position in the stream + * XXX for a memory stream give position from begining of the buffer + ****************************************************************************/ +off_t MP4_TellStream( MP4_Stream_t *p_stream ); + +/**************************************************************************** + * MP4_SeekStream seek in a MP4_Stream_t + * + ****************************************************************************/ +int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos); + + + +/***************************************************************************** + * MP4_ReadBox : parse the actual box and the children if they exist + * + * RETURN : 1 if succes and 0 if it failed + *****************************************************************************/ +int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father ); + + +/***************************************************************************** + * MP4_ReadBoxCommon : Load only common parameters for all boxes + ***************************************************************************** + * p_box need to be an already allocated MP4_Box_t, and all data + * will only be peek not read + * + * RETURN : 0 if it fail, 1 otherwise + *****************************************************************************/ +int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box ); + + +/***************************************************************************** + * MP4_MP4_GotoBox : Go to this particular box + ***************************************************************************** + * RETURN : 0 if it fail, 1 otherwise + *****************************************************************************/ +int MP4_GotoBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box ); + + +/***************************************************************************** + * MP4_MP4_NextBox : Go to the next box wiithin p_box->p_father + ***************************************************************************** + * if p_box == NULL, go to the next box in witch we are( at the begining ). + *****************************************************************************/ +int MP4_NextBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box ); + + diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c new file mode 100644 index 0000000000..b3fecc44ee --- /dev/null +++ b/modules/demux/mp4/mp4.c @@ -0,0 +1,1084 @@ +/***************************************************************************** + * mp4.c : MP4 file input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: mp4.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include +#include + +#include +#include + +#include "libmp4.h" +#include "mp4.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int MP4Init ( vlc_object_t * ); +static void __MP4End ( vlc_object_t * ); +static int MP4Demux ( input_thread_t * ); + +#define MP4End(a) __MP4End(VLC_OBJECT(a)) + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( "MP4 demuxer" ); + set_capability( "demux", 242 ); + set_callbacks( MP4Init, __MP4End ); +vlc_module_end(); + +/***************************************************************************** + * Declaration of local function + *****************************************************************************/ +static void MP4_ParseTrack(); + +static int MP4_CreateChunksIndex(); +static int MP4_CreateSamplesIndex(); + +static void MP4_StartDecoder(); +static void MP4_StopDecoder(); + +static int MP4_ReadSample(); +static int MP4_DecodeSample(); + +#define MP4_Set4BytesLE( p, dw ) \ + *((u8*)p) = ( (dw)&0xff ); \ + *((u8*)p+1) = ( ((dw)>> 8)&0xff ); \ + *((u8*)p+2) = ( ((dw)>>16)&0xff ); \ + *((u8*)p+3) = ( ((dw)>>24)&0xff ) + +#define MP4_Set2BytesLE( p, dw ) \ + *((u8*)p) = ( (dw)&0xff ); \ + *((u8*)p+1) = ( ((dw)>> 8)&0xff ) + + +/***************************************************************************** + * MP4Init: check file and initializes MP4 structures + *****************************************************************************/ +static int MP4Init( vlc_object_t * p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + u8 *p_peek; + u32 i_type; + + demux_data_mp4_t *p_demux; + + MP4_Box_t *p_moov; + MP4_Box_t *p_ftyp; + + + MP4_Box_t *p_mvhd; + MP4_Box_t *p_trak; + + int i; + /* I need to seek */ + if( !p_input->stream.b_seekable ) + { + msg_Warn( p_input, "MP4 plugin discarded (unseekable)" ); + return( -1 ); + + } + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ; + } + + p_input->pf_demux = MP4Demux; + + /* a little test to see if it could be a mp4 */ + if( input_Peek( p_input, &p_peek, 8 ) < 8 ) + { + msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" ); + return( -1 ); + } + i_type = ( p_peek[4] ) + ( p_peek[5] << 8 ) + + ( p_peek[6] << 16 ) + ( p_peek[7] << 24); + switch( i_type ) + { + case( FOURCC_ftyp ): + case( FOURCC_moov ): + case( FOURCC_moof ): + case( FOURCC_mdat ): + case( FOURCC_udta ): /* should never match but ... */ + case( FOURCC_free ): + case( FOURCC_skip ): + case( FOURCC_wide ): /* not mp4 compliant but ... */ + break; + default: + msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" ); + return( -1 ); + } + + /* create our structure that will contains all data */ + if( !( p_input->p_demux_data = + p_demux = malloc( sizeof( demux_data_mp4_t ) ) ) ) + { + msg_Err( p_input, "out of memory" ); + return( -1 ); + } + memset( p_demux, 0, sizeof( demux_data_mp4_t ) ); + p_input->p_demux_data = p_demux; + + + /* Now load all boxes ( except raw data ) */ + if( !MP4_ReadBoxRoot( p_input, &p_demux->box_root ) ) + { + msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" ); + return( -1 ); + } + + MP4_DumpBoxStructure( p_input, &p_demux->box_root ); + + if( ( p_ftyp = MP4_FindBox( &p_demux->box_root, FOURCC_ftyp ) ) ) + { + switch( p_ftyp->data.p_ftyp->i_major_brand ) + { + case( FOURCC_isom ): + msg_Info( p_input, + "ISO Media file (isom) version %d.", + p_ftyp->data.p_ftyp->i_minor_version ); + break; + default: + msg_Info( p_input, + "Unrecognize major file specification (%c%c%c%c).", + p_ftyp->data.p_ftyp->i_major_brand&0xff, + ( p_ftyp->data.p_ftyp->i_major_brand >> 8)&0xff, + ( p_ftyp->data.p_ftyp->i_major_brand >> 16 )&0xff, + ( p_ftyp->data.p_ftyp->i_major_brand >> 24 )&0xff ); + break; + } + } + else + { + msg_Info( p_input, "File Type box missing(assume ISO Media file)" ); + } + + /* the file need to have one moov box */ + if( !( p_moov = MP4_FindBox( &p_demux->box_root, FOURCC_moov ) ) ) + { + msg_Warn( p_input, "MP4 plugin discarded (missing moov box)" ); + MP4End( p_input ); + return( -1 ); + } + + if( MP4_CountBox( &p_demux->box_root, FOURCC_moov ) != 1 ) + { + msg_Warn( p_input, "more than one \"moov\" box (continuying anyway)" ); + } + + if( !(p_mvhd = MP4_FindBox( p_moov, FOURCC_mvhd ) ) ) + { + msg_Err( p_input, "cannot find \"mvhd\" box" ); + MP4End( p_input ); + return( -1 ); + } + else + { + p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale; + } + + p_demux->i_tracks = MP4_CountBox( p_moov, FOURCC_trak ); + msg_Dbg( p_input, "find %d track%c", + p_demux->i_tracks, + p_demux->i_tracks ? 's':' ' ); + + if( !( p_trak = MP4_FindBox( p_moov, FOURCC_trak ) ) ) + { + msg_Err( p_input, "cannot find /moov/trak !" ); + MP4End( p_input ); + return( -1 ); + } + + /* allocate memory */ + p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) ); + + /* now process each track and extract all usefull informations */ + for( i = 0; i < p_demux->i_tracks; i++ ) + { + MP4_ParseTrack( p_input, &p_demux->track[i], p_trak ); + + if( p_demux->track[i].b_ok ) + { + char *psz_cat; + switch( p_demux->track[i].i_cat ) + { + case( VIDEO_ES ): + psz_cat = "video"; + break; + case( AUDIO_ES ): + psz_cat = "audio"; + break; + default: + psz_cat = ""; + break; + } + + msg_Dbg( p_input, "adding track(%d) %s (%s) language %c%c%c", + i, + psz_cat, + p_demux->track[i].b_enable ? "enable":"disable", + p_demux->track[i].i_language[0], + p_demux->track[i].i_language[1], + p_demux->track[i].i_language[2] ); + } + else + { + msg_Dbg( p_input, "ignoring track(%d)", i ); + } + + p_trak = MP4_FindNextBox( p_trak ); + } + + /* create one program */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( input_InitStream( p_input, 0 ) == -1) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "cannot init stream" ); + MP4End( p_input ); + return( -1 ); + } + if( input_AddProgram( p_input, 0, 0) == NULL ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "cannot add program" ); + MP4End( p_input ); + return( -1 ); + } + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + p_input->stream.i_mux_rate = 0 ; /* FIXME */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + + for( i = 0; i < p_demux->i_tracks; i++ ) + { + /* start decoder for this track if enable by default*/ + if( p_demux->track[i].b_enable ) + { + MP4_StartDecoder( p_input, &p_demux->track[i] ); + } + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); + +} + +/***************************************************************************** + * MP4Demux: read packet and send them to decoders + *****************************************************************************/ +static int MP4Demux( input_thread_t *p_input ) +{ + demux_data_mp4_t *p_demux = p_input->p_demux_data; + int i_track; + + /* first wait for the good time to read a packet */ + + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_demux->i_pcr ); + + + /* update pcr XXX in mpeg scale so in 90000 unit/s */ + p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100; + + + /* we will read 100ms for each stream so ...*/ + p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 ); + + + for( i_track = 0; i_track < p_demux->i_tracks; i_track++ ) + { + if( ( !p_demux->track[i_track].b_ok )|| + ( !p_demux->track[i_track].p_es )|| + ( !p_demux->track[i_track].p_es->p_decoder_fifo )|| + ( MP4_GetTrackPTS( &p_demux->track[i_track] ) >= + MP4_GetMoviePTS( p_demux ) ) ) + { + continue; /* no need to read something */ + } + + while( MP4_GetTrackPTS( &p_demux->track[i_track] ) < + MP4_GetMoviePTS( p_demux ) ) + { + + pes_packet_t *p_pes; + + /* read a sample */ + if( !MP4_ReadSample( p_input , + &p_demux->track[i_track], + &p_pes ) ) + { + break; + } + + /* send it to decoder and update time of this track + it also launch a new decoder if needed */ + MP4_DecodeSample( p_input , + &p_demux->track[i_track], + p_pes ); + } + + } + + /* now check if all tracks are finished or unhandled*/ + + for( i_track = 0; i_track < p_demux->i_tracks; i_track++ ) + { + if( ( p_demux->track[i_track].b_ok )&& + ( p_demux->track[i_track].i_sample < p_demux->track[i_track].i_sample_count )&& + ( p_demux->track[i_track].p_es )&& + ( p_demux->track[i_track].p_es->p_decoder_fifo ) ) + { + return( 1 ); + } + } + + return( 0 ); /* EOF */ +} + +/***************************************************************************** + * MP4End: frees unused data + *****************************************************************************/ +static void __MP4End ( vlc_object_t * p_this ) +{ +#define FREE( p ) \ + if( p ) { free( p ); } + int i_track; + input_thread_t * p_input = (input_thread_t *)p_this; + demux_data_mp4_t *p_demux = p_input->p_demux_data; + + msg_Dbg( p_input, "Freeing all memory" ); + MP4_FreeBox( p_input, &p_demux->box_root ); + for( i_track = 0; i_track < p_demux->i_tracks; i_track++ ) + { + int i_chunk; + for( i_chunk = 0; + i_chunk < p_demux->track[i_track].i_chunk_count; i_chunk++ ) + { + if( p_demux->track[i_track].chunk ) + { + FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_count_dts); + FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_delta_dts ); + } + } + + if( !p_demux->track[i_track].i_sample_size ) + { + FREE( p_demux->track[i_track].p_sample_size ); + } + } + FREE( p_demux->track ); +#undef FREE +} + + +/**************************************************************************** + * Local functions, specific to vlc + ****************************************************************************/ + +/**************************************************************************** + * Parse track information and create all needed data to run a track + * If it succeed b_ok is set to 1 else to 0 + ****************************************************************************/ +static void MP4_ParseTrack( input_thread_t *p_input, + track_data_mp4_t *p_demux_track, + MP4_Box_t * p_trak ) +{ + int i; + + MP4_Box_t *p_tkhd = MP4_FindBox( p_trak, FOURCC_tkhd ); + MP4_Box_t *p_tref = MP4_FindBox( p_trak, FOURCC_tref ); + MP4_Box_t *p_edts = MP4_FindBox( p_trak, FOURCC_edts ); + MP4_Box_t *p_mdia = MP4_FindBox( p_trak, FOURCC_mdia ); + + MP4_Box_t *p_mdhd; + MP4_Box_t *p_hdlr; + MP4_Box_t *p_minf; + + MP4_Box_t *p_vmhd; + MP4_Box_t *p_smhd; + + /* hint track unsuported */ + + /* by default, track isn't usable */ + p_demux_track->b_ok = 0; + + /* by default, we don't known the categorie */ + p_demux_track->i_cat = UNKNOWN_ES; + + if( ( !p_tkhd )||( !p_mdia ) ) + { + return; + } + + /* do we launch this track by default ? */ + p_demux_track->b_enable = ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 ); + + p_demux_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID; + p_demux_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536; + p_demux_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536; + + if( !p_edts ) + { +// msg_Warn( p_input, "Unhandled box: edts --> FIXME" ); + } + + if( !p_tref ) + { +// msg_Warn( p_input, "Unhandled box: tref --> FIXME" ); + } + + p_mdhd = MP4_FindBox( p_mdia, FOURCC_mdhd ); + p_hdlr = MP4_FindBox( p_mdia, FOURCC_hdlr ); + p_minf = MP4_FindBox( p_mdia, FOURCC_minf ); + + if( ( !p_mdhd )||( !p_hdlr )||( !p_minf ) ) + { + return; + } + + p_demux_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale; + + for( i = 0; i < 3; i++ ) + { + p_demux_track->i_language[i] = p_mdhd->data.p_mdhd->i_language[i]; + } + + switch( p_hdlr->data.p_hdlr->i_handler_type ) + { + case( FOURCC_soun ): + if( !( p_smhd = MP4_FindBox( p_minf, FOURCC_smhd ) ) ) + { + return; + } + p_demux_track->i_cat = AUDIO_ES; + break; + + case( FOURCC_vide ): + if( !( p_vmhd = MP4_FindBox( p_minf, FOURCC_vmhd ) ) ) + { + return; + } + p_demux_track->i_cat = VIDEO_ES; + break; + + default: + return; + } +/* FIXME + add support to: + p_dinf = MP4_FindBox( p_minf, FOURCC_dinf ); +*/ + if( !( p_demux_track->p_stbl = MP4_FindBox( p_minf, FOURCC_stbl ) ) ) + { + return; + } + + if( !( p_demux_track->p_stsd = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsd ) ) ) + { + return; + } + + /* Create chunk index table */ + if( !MP4_CreateChunksIndex( p_input,p_demux_track ) ) + { + return; /* cannot create chunks index */ + } + + /* create sample index table needed for reading and seeking */ + if( !MP4_CreateSamplesIndex( p_input, p_demux_track ) ) + { + return; /* cannot create samples index */ + } + + p_demux_track->b_ok = 1; +} + + + +/* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */ +static int MP4_CreateChunksIndex( input_thread_t *p_input, + track_data_mp4_t *p_demux_track ) +{ + MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */ + MP4_Box_t *p_stsc; + + int i_chunk; + int i_index, i_last; + + + if( ( !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stco ) )&& + !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_co64 ) ) )|| + ( !(p_stsc = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsc ) ) )) + { + return( 0 ); + } + + p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count; + if( !p_demux_track->i_chunk_count ) + { + msg_Warn( p_input, "No chunk defined" ); + return( 0 ); + } + p_demux_track->chunk = calloc( p_demux_track->i_chunk_count, + sizeof( chunk_data_mp4_t ) ); + + /* first we read chunk offset */ + for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) + { + p_demux_track->chunk[i_chunk].i_offset = + p_co64->data.p_co64->i_chunk_offset[i_chunk]; + } + + /* now we read index for SampleEntry( soun vide mp4a mp4v ...) + to be used for the sample XXX begin to 1 + We construct it begining at the end */ + i_last = p_demux_track->i_chunk_count; /* last chunk proceded */ + i_index = p_stsc->data.p_stsc->i_entry_count; + if( !i_index ) + { + msg_Warn( p_input, "cannot read chunk table or table empty" ); + return( 0 ); + } + + while( i_index ) + { + i_index--; + for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1; + i_chunk < i_last; i_chunk++ ) + { + p_demux_track->chunk[i_chunk].i_sample_description_index = + p_stsc->data.p_stsc->i_sample_description_index[i_index]; + p_demux_track->chunk[i_chunk].i_sample_count = + p_stsc->data.p_stsc->i_samples_per_chunk[i_index]; + } + i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1; + } + + p_demux_track->chunk[i_chunk].i_sample_first = 0; + for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) + { + p_demux_track->chunk[i_chunk].i_sample_first = + p_demux_track->chunk[i_chunk-1].i_sample_first + + p_demux_track->chunk[i_chunk-1].i_sample_count; + + } + + msg_Dbg( p_input, "read %d chunk", p_demux_track->i_chunk_count ); + return( 1 ); + +} + + + +static int MP4_CreateSamplesIndex( input_thread_t *p_input, + track_data_mp4_t *p_demux_track ) +{ + MP4_Box_t *p_stts; /* makes mapping between sample and decoding time, + ctts make same mapping but for composition time, + not yet used and probably not usefull */ + MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2 + that uses a compressed form FIXME make them in libmp4 + as a unique type */ + /* TODO use also stss and stsh table for seeking */ + /* FIXME use edit table */ + int i_sample; + int i_chunk; + + int i_index; + int i_index_sample_used; + + u64 i_last_dts; + + p_stts = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stts ); + p_stsz = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsz ); /* FIXME and stz2 */ + + + if( ( !p_stts )||( !p_stsz ) ) + { + msg_Warn( p_input, "cannot read sample table" ); + return( 0 ); + } + + p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count; + + + /* for sample size, there are 2 case */ + if( p_stsz->data.p_stsz->i_sample_size ) + { + /* 1: all sample have the same size, so no need to construct a table */ + p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size; + p_demux_track->p_sample_size = NULL; + } + else + { + /* 2: each sample can have a different size */ + p_demux_track->i_sample_size = 0; + p_demux_track->p_sample_size = + calloc( p_demux_track->i_sample_count, sizeof( u32 ) ); + + for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ ) + { + p_demux_track->p_sample_size[i_sample] = + p_stsz->data.p_stsz->i_entry_size[i_sample]; + } + } + /* we have extract all information from stsz, + now use stts */ + + /* if we don't want to waste too much memory, we can't expand + the box !, so each chunk will contain an "extract" of this table + for fast research */ + + i_last_dts = 0; + i_index = 0; i_index_sample_used =0; + /* create and init last data for each chunk */ + for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) + { + + int i_entry, i_sample_count, i; + /* save last dts */ + p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts; + /* count how many entries needed for this chunk + for p_sample_delta_dts and p_sample_count_dts */ + + i_entry = 0; + i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count; + while( i_sample_count > 0 ) + { + i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry]; + if( i_entry == 0 ) + { + i_sample_count += i_index_sample_used; /* don't count already used sample + int this entry */ + } + i_entry++; + } + /* allocate them */ + p_demux_track->chunk[i_chunk].p_sample_count_dts = + calloc( i_entry, sizeof( u32 ) ); + p_demux_track->chunk[i_chunk].p_sample_delta_dts = + calloc( i_entry, sizeof( u32 ) ); + + /* now copy */ + i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count; + for( i = 0; i < i_entry; i++ ) + { + int i_used; + int i_rest; + + i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used; + + i_used = __MIN( i_rest, i_sample_count ); + + i_index_sample_used += i_used; + + p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used; + + p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] = + p_stts->data.p_stts->i_sample_delta[i_index]; + + i_last_dts += i_used * + p_demux_track->chunk[i_chunk].p_sample_delta_dts[i]; + + if( i_index_sample_used >= + p_stts->data.p_stts->i_sample_count[i_index] ) + { + i_index++; + i_index_sample_used = 0; + } + } + + } + + msg_Dbg( p_input, "read %d samples", p_demux_track->i_sample_count ); + + return( 1 ); +} + +static void MP4_StartDecoder( input_thread_t *p_input, + track_data_mp4_t *p_demux_track ) +{ + MP4_Box_t *p_sample; + int i; + int i_chunk; + + int i_decoder_specific_info_len; + u8 *p_decoder_specific_info; + + u8 *p_init; + + MP4_Box_t *p_esds; + + + if( (!p_demux_track->b_ok )||( p_demux_track->i_cat == UNKNOWN_ES ) ) + { + return; + } + + msg_Dbg( p_input, "Starting decoder (track ID 0x%x)", + p_demux_track->i_track_ID ); + + /* launch decoder according in chunk we are */ + i_chunk = p_demux_track->i_chunk; + + if( !p_demux_track->chunk[i_chunk].i_sample_description_index ) + { + msg_Warn( p_input, + "invalid SampleEntry index (track ID 0x%x)", + p_demux_track->i_track_ID ); + return; + } + + p_sample = MP4_FindNbBox( p_demux_track->p_stsd, + p_demux_track->chunk[i_chunk].i_sample_description_index - 1); + + if( ( !p_sample )||( !p_sample->data.p_data ) ) + { + msg_Warn( p_input, + "cannot find SampleEntry (track ID 0x%x)", + p_demux_track->i_track_ID ); + return; + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_demux_track->p_es = input_AddES( p_input, + p_input->stream.p_selected_program, + p_demux_track->i_track_ID, + 0 ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + /* Initialise ES, first language as description */ + for( i = 0; i < 3; i++ ) + { + p_demux_track->p_es->psz_desc[i] = p_demux_track->i_language[i]; + } + p_demux_track->p_es->psz_desc[4] = 0; + + p_demux_track->p_es->i_stream_id = p_demux_track->i_track_ID; + + /* It's a little ugly but .. there are special cases */ + switch( p_sample->i_type ) + { + case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): + case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' ); + break; + default: + p_demux_track->p_es->i_fourcc = p_sample->i_type; + break; + } + + p_demux_track->p_es->i_cat = p_demux_track->i_cat; + + i_decoder_specific_info_len = 0; + p_decoder_specific_info = NULL; + + /* now see if esds is present and if so create a data packet + with decoder_specific_info */ +#define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr + if( ( p_esds = MP4_FindBox( p_sample, FOURCC_esds ) )&& + ( p_esds->data.p_esds )&& + ( p_decconfig ) ) + { + /* First update information based on i_objectTypeIndication */ + switch( p_decconfig->i_objectTypeIndication ) + { + case( 0x20 ): /* MPEG4 VIDEO */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' ); + break; + case( 0x40): + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' ); + break; + case( 0x60): + case( 0x61): + case( 0x62): + case( 0x63): + case( 0x64): + case( 0x65): /* MPEG2 video */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' ); + break; + /* Theses are MPEG2-AAC (what is this codec ?) */ + case( 0x66): /* main profile */ + case( 0x67): /* Low complexity profile */ + case( 0x68): /* Scaleable Sampling rate profile */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' ); + break; + /* true MPEG 2 audio */ + case( 0x69): + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' ); + break; + case( 0x6a): /* MPEG1 video */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' ); + break; + case( 0x6b): /* MPEG1 audio */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' ); + break; + case( 0x6c ): /* jpeg */ + p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' ); + break; + default: + /* Unknown entry, but don't touch i_fourcc */ + msg_Warn( p_input, + "objectTypeIndication(0x%x) unknow (Track ID 0x%x)", + p_decconfig->i_objectTypeIndication, + p_demux_track->i_track_ID ); + break; + } + i_decoder_specific_info_len = + p_decconfig->i_decoder_specific_info_len; + p_decoder_specific_info = + p_decconfig->p_decoder_specific_info; + } + +#undef p_decconfig + + /* some last initialisation */ + /* XXX I create a bitmapinfoheader_t or + waveformatex_t for each stream, up to now it's the best thing + I've found but it could exist a better solution :) as something + like adding some new fields in p_es ... + + XXX I don't set all values, only thoses that are interesting or known + --> bitmapinfoheader_t : width and height + --> waveformatex_t : channels, samplerate, bitspersample + and at the end I add p_decoder_specific_info + + TODO set more values + + */ + + switch( p_demux_track->i_cat ) + { + case( VIDEO_ES ): + /* now create a bitmapinfoheader_t for decoder and + add information found in p_esds */ + p_init = malloc( 40 + i_decoder_specific_info_len); + memset( p_init, 0, 40 + i_decoder_specific_info_len); + MP4_Set4BytesLE( p_init, 40 + i_decoder_specific_info_len ); + if( p_sample->data.p_sample_vide->i_width ) + { + MP4_Set4BytesLE( p_init + 4, + p_sample->data.p_sample_vide->i_width ); + } + else + { + /* use display size */ + MP4_Set4BytesLE( p_init + 4, p_demux_track->i_width ); + } + if( p_sample->data.p_sample_vide->i_height ) + { + MP4_Set4BytesLE( p_init + 8, + p_sample->data.p_sample_vide->i_height ); + } + else + { + MP4_Set4BytesLE( p_init + 8, p_demux_track->i_height ); + } + if( i_decoder_specific_info_len ) + { + memcpy( p_init + 40, + p_decoder_specific_info, + i_decoder_specific_info_len); + } + break; + + case( AUDIO_ES ): + p_init = malloc( 18 + i_decoder_specific_info_len); + memset( p_init, 0, 18 + i_decoder_specific_info_len); + MP4_Set2BytesLE( p_init + 2, /* i_channel */ + p_sample->data.p_sample_soun->i_channelcount ); + MP4_Set4BytesLE( p_init + 4, /* samplepersec */ + p_sample->data.p_sample_soun->i_sampleratehi ); + MP4_Set4BytesLE( p_init + 8, /* avgbytespersec */ + p_sample->data.p_sample_soun->i_channelcount * + p_sample->data.p_sample_soun->i_sampleratehi * + (p_sample->data.p_sample_soun->i_samplesize/8) ); + MP4_Set2BytesLE( p_init + 14, /* bits/sample */ + p_sample->data.p_sample_soun->i_samplesize ); + + MP4_Set2BytesLE( p_init + 16, /* i_size, specific info len*/ + i_decoder_specific_info_len ); + if( i_decoder_specific_info_len ) + { + memcpy( p_init + 18, + p_decoder_specific_info, + i_decoder_specific_info_len); + } + break; + + default: + p_init = NULL; + break; + } + + p_demux_track->p_es->p_demux_data = p_init; + vlc_mutex_lock( &p_input->stream.stream_lock ); + input_SelectES( p_input, p_demux_track->p_es ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + p_demux_track->b_ok = 1; +} + +static void MP4_StopDecoder( input_thread_t *p_input, + track_data_mp4_t *p_demux_track ) +{ + msg_Dbg( p_input, "Stopping decoder (track ID 0x%x)", + p_demux_track->i_track_ID ); + + input_UnselectES( p_input, p_demux_track->p_es ); + p_demux_track->p_es = NULL; +} + +static int MP4_ReadSample( input_thread_t *p_input, + track_data_mp4_t *p_demux_track, + pes_packet_t **pp_pes ) +{ + int i_size; + off_t i_pos; + + data_packet_t *p_data; + + + /* this track have already reach the end */ + if( p_demux_track->i_sample >= p_demux_track->i_sample_count ) + { + *pp_pes = NULL; + return( 0 ); + } + /* caculate size and position for this sample */ + i_size = p_demux_track->i_sample_size ? + p_demux_track->i_sample_size : + p_demux_track->p_sample_size[p_demux_track->i_sample]; + /* TODO */ + i_pos = MP4_GetTrackPos( p_demux_track ); + + /* go,go go ! */ + if( ! MP4_SeekAbsolute( p_input, i_pos ) ) + { + return( 0 ); + } + + /* now create a pes */ + if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) ) + { + return( 0 ); + } + /* and a data packet for the data */ + if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) ) + { + input_DeletePES( p_input->p_method_data, *pp_pes ); + *pp_pes = NULL; + return( 0 ); + } + + /* initialisation of all the field */ + (*pp_pes)->i_dts = + (*pp_pes)->i_pts = MP4_GetTrackPTS( p_demux_track ); + (*pp_pes)->p_first = (*pp_pes)->p_last = p_data; + (*pp_pes)->i_nb_data = 1; + (*pp_pes)->i_pes_size = i_size; + + if( !i_size ) + { + return( 1 ); + } + +// msg_Dbg( p_input, "will read %d bytes", i_size ); + if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) ) + { + input_DeletePES( p_input->p_method_data, *pp_pes ); + input_DeletePacket( p_input->p_method_data, p_data ); + return( 0 ); + } + + return( 1 ); +} + + +static int MP4_DecodeSample( input_thread_t *p_input, + track_data_mp4_t *p_demux_track, + pes_packet_t *p_pes ) +{ + + if( !p_pes ) + { + return( 0 ); + } + + /* don't forget to convert in mpeg clock */ + /* FIXME correct ffmpeg to use dts instead of pts that it incorrect + and, set it here ( and correct avi demux ) */ + p_pes->i_dts = + p_pes->i_pts = input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + p_pes->i_pts * 9/100); + + + input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes ); + + /* now update sample position */ + p_demux_track->i_sample++; /* easy ;) */ + if( p_demux_track->i_sample >= p_demux_track->i_sample_count ) + { + /* we have reach end of the track so free decoder stuff */ + MP4_StopDecoder( p_input, p_demux_track ); + return( 1 ); + } + /* Have we changed chunk ? */ + if( p_demux_track->i_sample >= + p_demux_track->chunk[p_demux_track->i_chunk].i_sample_first + + p_demux_track->chunk[p_demux_track->i_chunk].i_sample_count ) + { + /* we haven't reached the end of the track, so see if we + have to change the decoder for the next frame because + i_sample_description_index have changed */ + + p_demux_track->i_chunk++; + if( p_demux_track->chunk[p_demux_track->i_chunk-1].i_sample_description_index + != p_demux_track->chunk[p_demux_track->i_chunk].i_sample_description_index ) + { + /* FIXME */ + msg_Warn( p_input, + "SampleEntry have changed, starting a new decoder" ); + MP4_StopDecoder( p_input, p_demux_track ); + MP4_StartDecoder( p_input, p_demux_track ); + } + } + + + return( 1 ); +} + + + diff --git a/modules/demux/mp4/mp4.h b/modules/demux/mp4/mp4.h new file mode 100644 index 0000000000..93cc8d7c45 --- /dev/null +++ b/modules/demux/mp4/mp4.h @@ -0,0 +1,208 @@ +/***************************************************************************** + * mp4.h : MP4 file input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: mp4.h,v 1.1 2002/08/04 17:23:42 sam Exp $ + * Authors: Laurent Aimar + * + * 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. + *****************************************************************************/ + + + +/***************************************************************************** + * Structure needed for decoder + *****************************************************************************/ +typedef struct bitmapinfoheader_s +{ + u32 i_size; /* size of header 40 + size of data follwoing this header */ + u32 i_width; + u32 i_height; + u16 i_planes; + u16 i_bitcount; + u32 i_compression; + u32 i_sizeimage; + u32 i_xpelspermeter; + u32 i_ypelspermeter; + u32 i_clrused; + u32 i_clrimportant; +} bitmapinfoheader_t; + +typedef struct waveformatex_s +{ + u16 i_format; + u16 i_channels; + u32 i_samplepersec; + u32 i_avgbytespersec; + u16 i_blockalign; + u16 i_bitspersample; + u16 i_size; /* This give size of data + imediatly following this header. */ +} waveformatex_t; + +/***************************************************************************** + * Contain all information about a chunk + *****************************************************************************/ +typedef struct chunk_data_mp4_s +{ + u64 i_offset; /* absolute position of this chunk in the file */ + u32 i_sample_description_index; /* index for SampleEntry to use */ + u32 i_sample_count; /* how many samples in this chunk */ + u32 i_sample_first; /* index of the first sample in this chunk */ + + /* now provide way to calculate pts, dts, and offset without to + much memory and with fast acces */ + + /* with this we can calculate dts/pts without waste memory */ + u64 i_first_dts; + u32 *p_sample_count_dts; + u32 *p_sample_delta_dts; /* dts delta */ + + /* TODO if needed add pts + but quickly *add* support for edts and seeking */ + +} chunk_data_mp4_t; + + +/***************************************************************************** + * Contain all needed information for read all track with vlc + *****************************************************************************/ +typedef struct track_data_mp4_s +{ + int b_ok; /* The track is usable */ + int i_track_ID; /* this should be unique */ + int b_enable; /* is the trak enable by default */ + + int i_cat; /* Type of the track, VIDEO_ES, AUDIO_ES, UNKNOWN_ES ... */ + char i_language[3]; + + /* display size only ! */ + int i_width; + int i_height; + + /* more internal data */ + u64 i_timescale; /* time scale for this track only */ + + /* give the next sample to read, i_chunk is to find quickly where + the sample is located */ + u32 i_sample; /* next sample to read */ + u32 i_chunk; /* chunk where next sample is stored */ + /* total count of chunk and sample */ + u32 i_chunk_count; + u32 i_sample_count; + + chunk_data_mp4_t *chunk; /* always defined for each chunk */ + + /* sample size, p_sample_size defined only if i_sample_size == 0 + else i_sample_size is size for all sample */ + u32 i_sample_size; + u32 *p_sample_size; /* XXX perhaps add file offset if take + too much time to do sumations each time*/ + + es_descriptor_t *p_es; /* vlc es for this track */ + + MP4_Box_t *p_stbl; /* will contain all timing information */ + MP4_Box_t *p_stsd; /* will contain all data to initialize decoder */ + + MP4_Box_t *p_sample; /* actual SampleEntry to make life simpler */ +} track_data_mp4_t; + + +/***************************************************************************** + * + *****************************************************************************/ +typedef struct demux_data_mp4_s +{ + + MP4_Box_t box_root; /* container for the hole file */ + + mtime_t i_pcr; + + u64 i_time; /* time position of the presentation in movie timescale */ + u64 i_timescale; /* movie time scale */ + + int i_tracks; /* number of track */ + track_data_mp4_t *track; /* array of track */ + + +} demux_data_mp4_t; + +static inline u64 MP4_GetTrackPos( track_data_mp4_t *p_track ) +{ + int i_sample; + u64 i_pos; + + + i_pos = p_track->chunk[p_track->i_chunk].i_offset; + + if( p_track->i_sample_size ) + { + i_pos += ( p_track->i_sample - + p_track->chunk[p_track->i_chunk].i_sample_first ) * + p_track->i_sample_size; + } + else + { + for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first; + i_sample < p_track->i_sample; i_sample++ ) + { + i_pos += p_track->p_sample_size[i_sample]; + } + + } + return( i_pos ); +} + +/* Return time in µs of a track */ +static inline mtime_t MP4_GetTrackPTS( track_data_mp4_t *p_track ) +{ + int i_sample; + int i_index; + u64 i_dts; + + i_sample = p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first; + i_dts = p_track->chunk[p_track->i_chunk].i_first_dts; + i_index = 0; + while( i_sample > 0 ) + { + if( i_sample > p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] ) + { + i_dts += p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] * + p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index]; + i_sample -= p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index]; + i_index++; + } + else + { + i_dts += i_sample * + p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index]; + i_sample = 0; + break; + } + } + return( (mtime_t)( + (mtime_t)1000000 * + (mtime_t)i_dts / + (mtime_t)p_track->i_timescale ) ); +} + +static inline mtime_t MP4_GetMoviePTS(demux_data_mp4_t *p_demux ) +{ + return( (mtime_t)( + (mtime_t)1000000 * + (mtime_t)p_demux->i_time / + (mtime_t)p_demux->i_timescale ) + ); +} diff --git a/modules/demux/mpeg/.cvsignore b/modules/demux/mpeg/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/demux/mpeg/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/demux/mpeg/Makefile b/modules/demux/mpeg/Makefile new file mode 100644 index 0000000000..1f968d8324 --- /dev/null +++ b/modules/demux/mpeg/Makefile @@ -0,0 +1,5 @@ +es_SOURCES = es.c +ps_SOURCES = ps.c +ts_SOURCES = ts.c +ts_dvbpsi_SOURCES = ts.c +audio_SOURCES = audio.c diff --git a/modules/demux/mpeg/audio.c b/modules/demux/mpeg/audio.c new file mode 100644 index 0000000000..444a1e74dd --- /dev/null +++ b/modules/demux/mpeg/audio.c @@ -0,0 +1,662 @@ +/***************************************************************************** + * mpeg_audio.c : mpeg_audio Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: audio.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Laurent Aimar + * + * 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 /* malloc(), free() */ +#include + +#include +#include + +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static int Demux ( input_thread_t * ); + +/* TODO: support MPEG-2.5, not difficult */ + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ISO 13818-3 MPEG I/II audio stream demux" ) ); + set_capability( "demux", 100 ); + set_callbacks( Activate, NULL ); + add_shortcut( "mpegaudio" ); +vlc_module_end(); + +/***************************************************************************** + * Definitions of structures and functions used by this plugins + *****************************************************************************/ + +/* XXX set this to 0 to avoid problem with PS XXX */ +/* but with some file or web radio will failed to detect */ +/* it's you to choose */ +#define MPEGAUDIO_MAXTESTPOS 0 + +#define MPEGAUDIO_MAXFRAMESIZE 1500 /* no exactly */ + +typedef struct mpegaudio_format_s +{ + u32 i_header; + int i_version; + int i_layer; + int i_crc; + int i_bitrate; + int i_samplingfreq; + int i_padding; + int i_extension; + int i_mode; + int i_modeext; + int i_copyright; + int i_original; + int i_emphasis; + +} mpegaudio_format_t; + +/* Xing Header if present */ +#define FRAMES_FLAG 0x0001 /* these flags is for i_flags */ +#define BYTES_FLAG 0x0002 /* because all is optionnal */ +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 +typedef struct mpegaudio_xing_header_s +{ + int i_flags; /* from Xing header data */ + int i_frames; /* total bit stream frames from Xing header data */ + int i_bytes; /* total bit stream bytes from Xing header data */ + int i_vbr_scale; /* encoded vbr scale from Xing header data */ + u8 i_toc[100]; /* for seek */ + int i_avgbitrate; /* calculated, XXX: bits/sec not Kb */ +} mpegaudio_xing_header_t; + +typedef struct demux_data_mpegaudio_s +{ + mtime_t i_pts; + + int i_framecount; + + es_descriptor_t *p_es; + mpegaudio_format_t mpeg; + mpegaudio_xing_header_t xingheader; + +} demux_data_mpegaudio_t; + + +static int mpegaudio_bitrate[2][3][16] = +{ + { + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, /* v1 l1 */ + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, /* v1 l2 */ + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } /* v1 l3 */ + }, + + { + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, /* v2 l1 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, /* v2 l2 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } /* v2 l3 */ + } + +}; + +static int mpegaudio_samplingfreq[2][4] = /* version 1 then 2 */ +{ + { 44100, 48000, 32000, 0 }, + { 22050, 24000, 16000, 0 } +}; + +static char* mpegaudio_mode[4] = +{ + "stereo", "joint stereo", "dual channel", "mono" +}; + +static inline u32 __GetDWBE( byte_t *p_buff ) +{ + return( ( (*(p_buff)) << 24 ) + ( (*(p_buff+1)) << 16 ) + + ( (*(p_buff+2)) << 8 ) + ( (*(p_buff+3)) ) ); +} + +static int __CheckPS( input_thread_t *p_input ) +{ + byte_t *p_buff; + int i_size = input_Peek( p_input, &p_buff, 8196 ); + + while( i_size > 0 ) + { + if( !(*p_buff) && !(*(p_buff + 1)) + && (*(p_buff + 2) == 1 ) && (*(p_buff + 3) >= 0xB9 ) ) + { + return( 1 ); /* it could be ps so ...*/ + } + p_buff++; + i_size--; + } + return( 0 ); +} + +/* +#define __GetDWBE( p_buff ) \ + ( ( (*(p_buff)) << 24 ) + ( (*(p_buff+1)) << 16 ) + \ + ( (*(p_buff+2)) << 8 ) + ( (*(p_buff+3)) ) ) +*/ +/***************************************************************************** + * MPEGAudio_CheckHeader : Test the validity of the header + *****************************************************************************/ +static int MPEGAudio_CheckHeader( u32 i_header ) +{ + if( ((( i_header >> 20 )&0x0FFF) != 0x0FFF ) /* header sync */ + || (((i_header >> 17)&0x03) == 0 ) /* valid layer ?*/ + || (((i_header >> 12)&0x0F) == 0x0F ) + || (((i_header >> 12)&0x0F) == 0x00 ) /* valid bitrate ? */ + || (((i_header >> 10) & 0x03) == 0x03 ) /* valide sampling freq ? */ + || ((i_header & 0x03) == 0x02 )) /* valid emphasis ? */ + { + return( 0 ); /*invalid */ + } + return( 1 ); /* valid */ +} + +/***************************************************************************** + * MPEGAudio_ParseHeader : Parse a header ;) + *****************************************************************************/ +static void MPEGAudio_ParseHeader( u32 i_header, mpegaudio_format_t *p_mpeg ) +{ + p_mpeg->i_header = i_header; + p_mpeg->i_version = 1 - ( ( i_header >> 19 ) & 0x01 ); + p_mpeg->i_layer = 3 - ( ( i_header >> 17 ) & 0x03 ); + p_mpeg->i_crc = 1 - (( i_header >> 16 ) & 0x01); + p_mpeg->i_bitrate = mpegaudio_bitrate[p_mpeg->i_version][p_mpeg->i_layer][(i_header>>12)&0x0F]; + p_mpeg->i_samplingfreq = mpegaudio_samplingfreq[p_mpeg->i_version][(i_header>>10)&0x03]; + p_mpeg->i_padding = (( i_header >> 9 ) & 0x01); + p_mpeg->i_extension = ( i_header >> 7 ) & 0x01; + p_mpeg->i_mode = ( i_header >> 6 ) & 0x03; + p_mpeg->i_modeext = ( i_header >> 4 ) & 0x03; + p_mpeg->i_copyright = ( i_header >> 3 ) & 0x01; + p_mpeg->i_original = ( i_header >> 2 ) & 0x01; + p_mpeg->i_emphasis = ( i_header ) & 0x03; +} + +/***************************************************************************** + * MPEGAudio_FrameSize : give the size of a frame in the mpeg stream + *****************************************************************************/ +static int MPEGAudio_FrameSize( mpegaudio_format_t *p_mpeg ) +{ + /* XXX if crc do i need to add 2 bytes or not? */ + switch( p_mpeg->i_layer ) + { + case( 0 ): + return( ( ( ( !p_mpeg->i_version ? 12000 : 6000 ) * + p_mpeg->i_bitrate ) / + p_mpeg->i_samplingfreq + p_mpeg->i_padding ) * 4); + case( 1 ): + case( 2 ): + return( ( ( !p_mpeg->i_version ? 144000 : 72000 ) * + p_mpeg->i_bitrate ) / + p_mpeg->i_samplingfreq + p_mpeg->i_padding ); + } + return( 1024 ); /* must never happen, 1k to advance in stream*/ +} + +/***************************************************************************** + * MPEGAudio_DecodedFrameSize : give the length of the decoded pcm data + *****************************************************************************/ +static int MPEGAudio_DecodedFrameSize( mpegaudio_format_t *p_mpeg ) +{ + switch( p_mpeg->i_layer ) + { + case( 0 ): /* layer 1 */ + return( 384); + case( 1 ): /* layer 2 */ + return( 1152 ); + case( 2 ): /* layer 3 */ + return( !p_mpeg->i_version ? 1152 : 576 ); + /* XXX: perhaps we have to /2 for all layer but i'm not sure */ + } + return( 0 ); +} + +static int MPEGAudio_SkipID3Tag( input_thread_t *p_input ) +{ + int count; + byte_t *p_peek; + byte_t version, revision; + int b_footer; + int i_size; + + msg_Dbg( p_input, "Checking for ID3 tag" ); + /* get 10 byte id3 header */ + if( ( count = input_Peek( p_input, &p_peek, 10 ) ) < 10 ) + { + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } +/* + msg_Info( p_input, "Three first bytes are: %d %d %d", + p_peek[0], + p_peek[1], + p_peek[2] + ); +*/ + if ( !( (p_peek[0] == 0x49) && (p_peek[1] == 0x44) && (p_peek[2] == 0x33))) + { + return( 0 ); + } + + version = p_peek[3]; /* These may become usfull later, */ + revision = p_peek[4]; /* but we ignore them for now */ + + b_footer = p_peek[5] & 0x10; + i_size = (p_peek[6] << 21) + + (p_peek[7] << 14) + + (p_peek[8] << 7) + + p_peek[9]; //Is this safe? + if ( b_footer ) + { + i_size += 10; + } + i_size += 10; + msg_Dbg( p_input, "ID3 tag found, skiping %d bytes", i_size ); + if ( input_Peek( p_input, &p_peek, i_size ) < i_size ) + { + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } + + p_input->p_current_data += i_size; //seek passed end of ID3 tag + + return (0); +} + +/***************************************************************************** + * MPEGAudio_FindFrame : Find a header that could be valid. + ***************************************************************************** + * The idea is to search for 2 consecutive headers that seem valid + * Perhaps we can search 2 header with same version or samplefreq(...) to be + * more secure but this seems to be enougth + *****************************************************************************/ +static int MPEGAudio_FindFrame( input_thread_t *p_input, + int *pi_pos, + mpegaudio_format_t *p_mpeg, + int i_posmax ) +{ + byte_t *p_buff; + u32 i_header; + int i_framesize; + + int i_pos = 0; + int i_size = input_Peek( p_input, &p_buff, i_posmax+MPEGAUDIO_MAXFRAMESIZE); + + while( i_pos <= __MIN( i_posmax, i_size - 4) ) + { + i_header = __GetDWBE( p_buff ); + if( MPEGAudio_CheckHeader( i_header ) ) + { + MPEGAudio_ParseHeader( i_header, p_mpeg ); + i_framesize = MPEGAudio_FrameSize( p_mpeg ); + if( i_pos + i_framesize + 4 > i_size ) + { + *pi_pos = i_pos; + return( 1 ); + } + else + { + if( MPEGAudio_CheckHeader( __GetDWBE( p_buff + i_framesize ) ) ) + { + *pi_pos = i_pos; + return( 2 ); + } + } + } + p_buff++; + i_pos++; + } + + *pi_pos = 0; + return( 0 ); +} + +/***************************************************************************** + * MPEGAudio_ExtractXingHeader : extract a Xing header if exist + ***************************************************************************** + * It also calcul avgbitrate, using Xing header if present or assume that + * the bitrate of the first frame is the same for the all file + *****************************************************************************/ +static void MPEGAudio_ExtractXingHeader( input_thread_t *p_input, + mpegaudio_xing_header_t *p_xh ) +{ + int i_pos; + int i_size; + mpegaudio_format_t mpeg; + byte_t *p_buff; + + p_xh->i_flags = 0; /* nothing present */ + if( !(MPEGAudio_FindFrame( p_input, &i_pos, &mpeg, 2024 )) ) + { + return; /* failed , can't */ + } + p_xh->i_avgbitrate = mpeg.i_bitrate * 1000; /* default */ + + /* 1024 is enougth */ + if( ( i_size = input_Peek( p_input, &p_buff, 1024 + i_pos ) ) < 8 ) + { + return; + } + p_buff += i_pos; + + /* calculate pos of xing header */ + if( !mpeg.i_version ) + { + p_buff += mpeg.i_mode != 3 ? 36 : 21; + } + else + { + p_buff += mpeg.i_mode != 3 ? 21 : 13; + } + + if( (*p_buff != 'X' )||(*(p_buff+1) != 'i' ) + ||(*(p_buff+2) != 'n' )||(*(p_buff+3) != 'g' ) ) + { + return; + } + p_buff += 4; + + p_xh->i_flags = __GetDWBE( p_buff ); + p_buff += 4; + + if( p_xh->i_flags&FRAMES_FLAG ) + { + p_xh->i_frames = __GetDWBE( p_buff ); + p_buff += 4; + } + if( p_xh->i_flags&BYTES_FLAG ) + { + p_xh->i_bytes = __GetDWBE( p_buff ); + p_buff += 4; + } + if( p_xh->i_flags&TOC_FLAG ) + { + p_input->p_vlc->pf_memcpy( p_xh->i_toc, p_buff, 100 ); + p_buff += 100; + } + if( p_xh->i_flags&VBR_SCALE_FLAG ) + { + p_xh->i_vbr_scale = __GetDWBE( p_buff ); + p_buff += 4; + } + if( ( p_xh->i_flags&FRAMES_FLAG )&&( p_xh->i_flags&BYTES_FLAG ) ) + { + p_xh->i_avgbitrate = + ((u64)p_xh->i_bytes * (u64)8 * (u64)mpeg.i_samplingfreq) / + ((u64)p_xh->i_frames * (u64)MPEGAudio_DecodedFrameSize( &mpeg)); + } +} + + +/***************************************************************************** + * Activate: initializes MPEGaudio structures + *****************************************************************************/ +static int Activate( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + demux_data_mpegaudio_t * p_mpegaudio; + mpegaudio_format_t mpeg; + es_descriptor_t * p_es; + int i_pos; + int b_forced; + input_info_category_t * p_category; + + /* Set the demux function */ + p_input->pf_demux = Demux; + + /* XXX: i don't know what it's supposed to do, copied from ESInit */ + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + if( ( *p_input->psz_demux ) + &&( !strncmp( p_input->psz_demux, "mpegaudio", 10 ) ) ) + { + b_forced = 1; + } + else + { + b_forced = 0; + } + + if ( MPEGAudio_SkipID3Tag( p_input ) ) + { + return -1; + } + + /* check if it can be a ps stream */ + if( __CheckPS( p_input ) && !b_forced ) + { + return( -1 ); + } + + /* must be sure that is mpeg audio stream */ + if( MPEGAudio_FindFrame( p_input, + &i_pos, + &mpeg, + (b_forced ? 2 * MPEGAUDIO_MAXFRAMESIZE : + MPEGAUDIO_MAXTESTPOS) ) + < (b_forced ? 1 : 2) ) + { + msg_Warn( p_input, "MPEGAudio module discarded (no frame found)" ); + return( -1 ); + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( input_InitStream( p_input, 0 ) == -1) + { + msg_Err( p_input, "cannot init stream" ); + return( -1 ); + } + if( input_AddProgram( p_input, 0, 0) == NULL ) + { + msg_Err( p_input, "cannot add program" ); + return( -1 ); + } + p_input->stream.pp_programs[0]->b_is_ok = 0; + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + + /* create our ES */ + p_es = input_AddES( p_input, + p_input->stream.p_selected_program, + 1, /* id */ + 0 ); + if( !p_es ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + msg_Err( p_input, "out of memory" ); + return( -1 ); + } + p_es->i_stream_id = 1; + p_es->i_fourcc = !mpeg.i_layer ? VLC_FOURCC('m','p','g','a') /* layer 1 */ + : VLC_FOURCC('m','p','g','a'); /* layer 2 */ + p_es->i_cat = AUDIO_ES; + input_SelectES( p_input, p_es ); + + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + /* create p_mpegaudio and init it */ + p_input->p_demux_data = + p_mpegaudio = malloc( sizeof( demux_data_mpegaudio_t )); + + if( !p_mpegaudio ) + { + msg_Err( p_input, "out of memory" ); + return( -1 ); + } + + /*input_ClockInit( p_input->stream.p_selected_program ); + done by AddProgram */ + p_mpegaudio->p_es = p_es; + p_mpegaudio->mpeg = mpeg; + p_mpegaudio->i_framecount = 0; + p_mpegaudio->i_pts = 0; + + /* parse Xing Header if present */ + MPEGAudio_ExtractXingHeader( p_input, &p_mpegaudio->xingheader ); + + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.i_mux_rate = p_mpegaudio->xingheader.i_avgbitrate / 50 / 8; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME */ + /* if i don't do that, it don't work correctly but why ??? */ + if( p_input->stream.b_seekable ) + { + p_input->pf_seek( p_input, 0 ); + input_AccessReinit( p_input ); + } + /* FIXME FIXME FIXME FIXME FIXME FIXME FIXME */ + + /* all is ok :)) */ + msg_Dbg( p_input, "audio MPEG-%d layer %d %s %dHz %dKb/s %s", + mpeg.i_version + 1, + mpeg.i_layer + 1, + mpegaudio_mode[mpeg.i_mode], + mpeg.i_samplingfreq, + p_mpegaudio->xingheader.i_avgbitrate / 1000, + p_mpegaudio->xingheader.i_flags ? + "VBR (Xing)" : "" + ); + + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_category = input_InfoCategory( p_input, "mpeg" ); + input_AddInfo( p_category, "input type", "audio MPEG-%d", + mpeg.i_version +1 ); + input_AddInfo( p_category, "layer", "%d", mpeg.i_layer + 1 ); + input_AddInfo( p_category, "mode", mpegaudio_mode[mpeg.i_mode] ); + input_AddInfo( p_category, "sample rate", "%dHz", mpeg.i_samplingfreq ); + input_AddInfo( p_category, "average bitrate", "%dKb/s", + p_mpegaudio->xingheader.i_avgbitrate / 1000 ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Demux( input_thread_t * p_input ) +{ + int i_pos; + int i_toread; + pes_packet_t *p_pes; + mpegaudio_format_t mpeg; + demux_data_mpegaudio_t *p_mpegaudio = + (demux_data_mpegaudio_t*) p_input->p_demux_data; + /* look for a frame */ + if( !MPEGAudio_FindFrame( p_input, &i_pos, &mpeg, 4096 ) ) + { + msg_Warn( p_input, "cannot find next frame" ); + return( 0 ); + } + + /* if stream has changed */ + if( ( mpeg.i_version != p_mpegaudio->mpeg.i_version ) + ||( mpeg.i_layer != p_mpegaudio->mpeg.i_layer ) + ||( mpeg.i_samplingfreq != p_mpegaudio->mpeg.i_samplingfreq ) ) + { + msg_Dbg( p_input, "stream has changed" ); + p_mpegaudio->i_framecount = 0; + p_mpegaudio->i_pts = 0; + } + + input_ClockManageRef( p_input, + p_input->stream.p_selected_program, + p_mpegaudio->i_pts ); + + /* in fact i_pos may be garbage but ... i don't want to skip it + it's borring ;) */ + + i_toread = MPEGAudio_FrameSize( &mpeg ) + i_pos; + /* create one pes */ + if( !(p_pes = input_NewPES( p_input->p_method_data )) ) + { + msg_Err( p_input, "cannot allocate new PES" ); + return( -1 ); + } + + while( i_toread > 0 ) + { + data_packet_t *p_data; + int i_read; + + if( (i_read = input_SplitBuffer( p_input, &p_data, i_toread ) ) <= 0 ) + { + break; + } + if( !p_pes->p_first ) + { + p_pes->p_first = p_data; + p_pes->i_nb_data = 1; + p_pes->i_pes_size = i_read; + } + else + { + p_pes->p_last->p_next = p_data; + p_pes->i_nb_data++; + p_pes->i_pes_size += i_read; + } + p_pes->p_last = p_data; + i_toread -= i_read; + } + p_mpegaudio->i_pts = (mtime_t)90000 * + (mtime_t)p_mpegaudio->i_framecount * + (mtime_t)MPEGAudio_DecodedFrameSize( &mpeg ) / + (mtime_t)mpeg.i_samplingfreq; + p_pes->i_dts = 0; + p_pes->i_pts = input_ClockGetTS( p_input, + p_input->stream.p_selected_program, + p_mpegaudio->i_pts ); + + if( !p_mpegaudio->p_es->p_decoder_fifo ) + { + msg_Err( p_input, "no audio decoder" ); + input_DeletePES( p_input->p_method_data, p_pes ); + return( -1 ); /* perhaps not, it's my choice */ + } + else + { + input_DecodePES( p_mpegaudio->p_es->p_decoder_fifo, p_pes ); + } + + p_mpegaudio->i_framecount++; + p_mpegaudio->mpeg = mpeg; + + return( 1 ); +} + + diff --git a/modules/demux/mpeg/es.c b/modules/demux/mpeg/es.c new file mode 100644 index 0000000000..af13465278 --- /dev/null +++ b/modules/demux/mpeg/es.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * mpeg_es.c : Elementary Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: es.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include + +#include +#include + +#include + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define ES_PACKET_SIZE 65536 +#define MAX_PACKETS_IN_FIFO 3 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static int Demux ( input_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ISO 13818-1 MPEG Elementary Stream input") ); + set_capability( "demux", 150 ); + set_callbacks( Activate, NULL ); + add_shortcut( "es" ); +vlc_module_end(); + +/* + * Data reading functions + */ + +/***************************************************************************** + * Activate: initializes ES structures + *****************************************************************************/ +static int Activate( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + es_descriptor_t * p_es; + byte_t * p_peek; + + /* Set the demux function */ + p_input->pf_demux = Demux; + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + /* Have a peep at the show. */ + if( input_Peek( p_input, &p_peek, 4 ) < 4 ) + { + /* Stream shorter than 4 bytes... */ + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } + + if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "es", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this doesn't look like an MPEG ES stream, continuing" ); + } + else + { + msg_Warn( p_input, "ES module discarded (no startcode)" ); + return( -1 ); + } + } + else if( *(p_peek + 3) > 0xb9 ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "es", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this seems to be a system stream (PS plug-in ?), but continuing" ); + } + else + { + msg_Warn( p_input, "ES module discarded (system startcode)" ); + return( -1 ); + } + } + + if( input_InitStream( p_input, 0 ) == -1 ) + { + return( -1 ); + } + input_AddProgram( p_input, 0, 0 ); + p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xE0, 0 ); + p_es->i_stream_id = 0xE0; + p_es->i_fourcc = VLC_FOURCC('m','p','g','v'); + p_es->i_cat = VIDEO_ES; + input_SelectES( p_input, p_es ); + p_input->stream.p_selected_area->i_tell = 0; + p_input->stream.p_selected_program->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, 1 otherwise + *****************************************************************************/ +static int Demux( input_thread_t * p_input ) +{ + ssize_t i_read; + decoder_fifo_t * p_fifo = + p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo; + pes_packet_t * p_pes; + data_packet_t * p_data; + + if( p_fifo == NULL ) + { + return -1; + } + + i_read = input_SplitBuffer( p_input, &p_data, ES_PACKET_SIZE ); + + if ( i_read <= 0 ) + { + return i_read; + } + + p_pes = input_NewPES( p_input->p_method_data ); + + if( p_pes == NULL ) + { + msg_Err( p_input, "out of memory" ); + input_DeletePacket( p_input->p_method_data, p_data ); + return -1; + } + + p_pes->i_rate = p_input->stream.control.i_rate; + p_pes->p_first = p_pes->p_last = p_data; + p_pes->i_nb_data = 1; + + vlc_mutex_lock( &p_fifo->data_lock ); + + if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO ) + { + /* Wait for the decoder. */ + vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + } + vlc_mutex_unlock( &p_fifo->data_lock ); + + if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT) + | (input_ClockManageControl( p_input, + p_input->stream.p_selected_program, + (mtime_t)0 ) == PAUSE_S) ) + { + msg_Warn( p_input, "synchro reinit" ); + p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY; + p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK; + } + + input_DecodePES( p_fifo, p_pes ); + + return 1; +} + diff --git a/modules/demux/mpeg/ps.c b/modules/demux/mpeg/ps.c new file mode 100644 index 0000000000..9e2d6f6aa1 --- /dev/null +++ b/modules/demux/mpeg/ps.c @@ -0,0 +1,278 @@ +/***************************************************************************** + * mpeg_ps.c : Program Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2000-2001 VideoLAN + * $Id: ps.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include + +#include +#include + +#include + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define PS_READ_ONCE 50 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static int Demux ( input_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ISO 13818-1 MPEG Program Stream input") ); + set_capability( "demux", 100 ); + set_callbacks( Activate, NULL ); + add_shortcut( "ps" ); +vlc_module_end(); + +/***************************************************************************** + * Activate: initializes PS structures + *****************************************************************************/ +static int Activate( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + byte_t * p_peek; + + /* Set the demux function */ + p_input->pf_demux = Demux; + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + /* Have a peep at the show. */ + if( input_Peek( p_input, &p_peek, 4 ) < 4 ) + { + /* Stream shorter than 4 bytes... */ + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } + + if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this does not look like an MPEG PS stream, continuing" ); + } + else + { + msg_Warn( p_input, "this does not look like an MPEG PS stream, " + "but continuing anyway" ); + } + } + else if( *(p_peek + 3) <= 0xb9 ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ps", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this seems to be an elementary stream (ES module?), but continuing" ); + } + else + { + msg_Warn( p_input, "this seems to be an elementary stream (ES module?), but continuing" ); + } + } + + if( input_InitStream( p_input, sizeof( stream_ps_data_t ) ) == -1 ) + { + return( -1 ); + } + input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) ); + + p_input->stream.p_selected_program = + p_input->stream.pp_programs[0] ; + + if( p_input->stream.b_seekable ) + { + stream_ps_data_t * p_demux_data = + (stream_ps_data_t *)p_input->stream.pp_programs[0]->p_demux_data; + + /* Pre-parse the stream to gather stream_descriptor_t. */ + p_input->stream.pp_programs[0]->b_is_ok = 0; + p_demux_data->i_PSM_version = EMPTY_PSM_VERSION; + + while( !p_input->b_die && !p_input->b_error + && !p_demux_data->b_has_PSM ) + { + ssize_t i_result; + data_packet_t * p_data; + + i_result = input_ReadPS( p_input, &p_data ); + + if( i_result == 0 ) + { + /* EOF */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.pp_programs[0]->b_is_ok = 1; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + break; + } + else if( i_result == -1 ) + { + p_input->b_error = 1; + break; + } + + input_ParsePS( p_input, p_data ); + input_DeletePacket( p_input->p_method_data, p_data ); + + /* File too big. */ + if( p_input->stream.p_selected_area->i_tell > + INPUT_PREPARSE_LENGTH ) + { + break; + } + } + input_AccessReinit( p_input ); + p_input->pf_seek( p_input, (off_t)0 ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( p_demux_data->b_has_PSM ) + { + /* (The PSM decoder will care about spawning the decoders) */ + p_input->stream.pp_programs[0]->b_is_ok = 1; + } +#ifdef AUTO_SPAWN + else + { + /* (We have to do it ourselves) */ + int i_es; + + /* FIXME: we should do multiple passes in case an audio type + * is not present */ + for( i_es = 0; + i_es < p_input->stream.pp_programs[0]->i_es_number; + i_es++ ) + { +#define p_es p_input->stream.pp_programs[0]->pp_es[i_es] + switch( p_es->i_fourcc ) + { + case VLC_FOURCC('m','p','g','v'): + input_SelectES( p_input, p_es ); + break; + + case VLC_FOURCC('m','p','g','a'): + if( config_GetInt( p_input, "audio-channel" ) + == (p_es->i_id & 0x1F) || + ( config_GetInt( p_input, "audio-channel" ) < 0 + && !(p_es->i_id & 0x1F) ) ) + switch( config_GetInt( p_input, "audio-type" ) ) + { + case -1: + case REQUESTED_MPEG: + input_SelectES( p_input, p_es ); + } + break; + + case VLC_FOURCC('a','5','2',' '): + if( config_GetInt( p_input, "audio-channel" ) + == ((p_es->i_id & 0xF00) >> 8) || + ( config_GetInt( p_input, "audio-channel" ) < 0 + && !((p_es->i_id & 0xF00) >> 8) ) ) + switch( config_GetInt( p_input, "audio-type" ) ) + { + case -1: + case REQUESTED_A52: + input_SelectES( p_input, p_es ); + } + break; + + case VLC_FOURCC('s','p','u',' '): + if( config_GetInt( p_input, "spu-channel" ) + == ((p_es->i_id & 0x1F00) >> 8) ) + { + input_SelectES( p_input, p_es ); + } + break; + + case VLC_FOURCC('l','p','c','m'): + if( config_GetInt( p_input, "audio-channel" ) + == ((p_es->i_id & 0x1F00) >> 8) || + ( config_GetInt( p_input, "audio-channel" ) < 0 + && !((p_es->i_id & 0x1F00) >> 8) ) ) + switch( config_GetInt( p_input, "audio-type" ) ) + { + case -1: + case REQUESTED_LPCM: + input_SelectES( p_input, p_es ); + } + break; + } +#undef p_es + } + } +#endif + input_DumpStream( p_input ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + else + { + /* The programs will be added when we read them. */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.pp_programs[0]->b_is_ok = 0; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + + return( 0 ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, otherwise the number of + * packets. + *****************************************************************************/ +static int Demux( input_thread_t * p_input ) +{ + int i; + + for( i = 0; i < PS_READ_ONCE; i++ ) + { + data_packet_t * p_data; + ssize_t i_result; + i_result = input_ReadPS( p_input, &p_data ); + + if( i_result <= 0 ) + { + return( i_result ); + } + + input_DemuxPS( p_input, p_data ); + } + + return( i ); +} + diff --git a/modules/demux/mpeg/ts.c b/modules/demux/mpeg/ts.c new file mode 100644 index 0000000000..2ecf45a073 --- /dev/null +++ b/modules/demux/mpeg/ts.c @@ -0,0 +1,912 @@ +/***************************************************************************** + * mpeg_ts.c : Transport Stream input module for vlc + ***************************************************************************** + * Copyright (C) 2000-2001 VideoLAN + * $Id: ts.c,v 1.1 2002/08/04 17:23:42 sam Exp $ + * + * Authors: Henri Fallon + * Johan Bilien + * + * 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 +#include +#include + +#include +#include + +#include "iso_lang.h" + +#if defined MODULE_NAME_IS_ts_dvbpsi +# ifdef HAVE_DVBPSI_DR_H +# include +# include +# include +# include +# include +# else +# include "dvbpsi.h" +# include "descriptor.h" +# include "tables/pat.h" +# include "tables/pmt.h" +# include "descriptors/dr.h" +# endif +#endif + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define TS_READ_ONCE 200 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static int Demux ( input_thread_t * ); + +#if defined MODULE_NAME_IS_ts +static void TSDemuxPSI ( input_thread_t *, data_packet_t *, + es_descriptor_t *, vlc_bool_t ); +static void TSDecodePAT( input_thread_t *, es_descriptor_t *); +static void TSDecodePMT( input_thread_t *, es_descriptor_t *); +#define PSI_CALLBACK TSDemuxPSI +#elif defined MODULE_NAME_IS_ts_dvbpsi +static void TS_DVBPSI_DemuxPSI ( input_thread_t *, data_packet_t *, + es_descriptor_t *, vlc_bool_t ); +static void TS_DVBPSI_HandlePAT ( input_thread_t *, dvbpsi_pat_t * ); +static void TS_DVBPSI_HandlePMT ( input_thread_t *, dvbpsi_pmt_t * ); +#define PSI_CALLBACK TS_DVBPSI_DemuxPSI +#endif + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#if defined MODULE_NAME_IS_ts + set_description( _("ISO 13818-1 MPEG Transport Stream input") ); + set_capability( "demux", 160 ); + add_shortcut( "ts" ); +#elif defined MODULE_NAME_IS_ts_dvbpsi + set_description( _("ISO 13818-1 MPEG Transport Stream input (libdvbpsi)") ); + set_capability( "demux", 170 ); + add_shortcut( "ts_dvbpsi" ); +#endif + set_callbacks( Activate, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Activate: initializes TS structures + *****************************************************************************/ +static int Activate( vlc_object_t * p_this ) +{ + input_thread_t * p_input = (input_thread_t *)p_this; + es_descriptor_t * p_pat_es; + es_ts_data_t * p_demux_data; + stream_ts_data_t * p_stream_data; + byte_t * p_peek; + + /* Set the demux function */ + p_input->pf_demux = Demux; + + /* Initialize access plug-in structures. */ + if( p_input->i_mtu == 0 ) + { + /* Improve speed. */ + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + /* Have a peep at the show. */ + if( input_Peek( p_input, &p_peek, 1 ) < 1 ) + { + msg_Err( p_input, "cannot peek()" ); + return( -1 ); + } + + if( *p_peek != TS_SYNC_CODE ) + { + if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "ts", 3 ) ) + { + /* User forced */ + msg_Err( p_input, "this does not look like a TS stream, continuing" ); + } + else + { + msg_Warn( p_input, "TS module discarded (no sync)" ); + return( -1 ); + } + } + + /* Adapt the bufsize for our only use. */ + if( p_input->i_mtu != 0 ) + { + /* Have minimum granularity to avoid bottlenecks at the input level. */ + p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE; + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 ) + { + return( -1 ); + } + + p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data; + p_stream_data->i_pat_version = PAT_UNINITIALIZED ; + +#ifdef MODULE_NAME_IS_ts_dvbpsi + p_stream_data->p_pat_handle = (dvbpsi_handle *) + dvbpsi_AttachPAT( (dvbpsi_pat_callback) &TS_DVBPSI_HandlePAT, p_input ); + + if( p_stream_data->p_pat_handle == NULL ) + { + msg_Err( p_input, "could not create PAT decoder" ); + return( -1 ); + } +#endif + + /* We'll have to catch the PAT in order to continue + * Then the input will catch the PMT and then the others ES + * The PAT es is indepedent of any program. */ + p_pat_es = input_AddES( p_input, NULL, + 0x00, sizeof( es_ts_data_t ) ); + p_demux_data = (es_ts_data_t *)p_pat_es->p_demux_data; + p_demux_data->b_psi = 1; + p_demux_data->i_psi_type = PSI_IS_PAT; + p_demux_data->p_psi_section = malloc(sizeof(psi_section_t)); + p_demux_data->p_psi_section->b_is_complete = 1; + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( 0 ); +} + +/***************************************************************************** + * Demux: reads and demuxes data packets + ***************************************************************************** + * Returns -1 in case of error, 0 in case of EOF, otherwise the number of + * packets. + *****************************************************************************/ +static int Demux( input_thread_t * p_input ) +{ + int i_read_once = (p_input->i_mtu ? + p_input->i_bufsize / TS_PACKET_SIZE : + TS_READ_ONCE); + int i; + + for( i = 0; i < i_read_once; i++ ) + { + data_packet_t * p_data; + ssize_t i_result; + + i_result = input_ReadTS( p_input, &p_data ); + + if( i_result <= 0 ) + { + return( i_result ); + } + + input_DemuxTS( p_input, p_data, (psi_callback_t) &PSI_CALLBACK ); + } + + return( i_read_once ); +} + + +#if defined MODULE_NAME_IS_ts +/* + * PSI demultiplexing and decoding without libdvbpsi + */ + +/***************************************************************************** + * DemuxPSI : makes up complete PSI data + *****************************************************************************/ +static void TSDemuxPSI( input_thread_t * p_input, data_packet_t * p_data, + es_descriptor_t * p_es, vlc_bool_t b_unit_start ) +{ + es_ts_data_t * p_demux_data; + + p_demux_data = (es_ts_data_t *)p_es->p_demux_data; + +#define p_psi (p_demux_data->p_psi_section) +#define p (p_data->p_payload_start) + + if( b_unit_start ) + { + /* unit_start set to 1 -> presence of a pointer field + * (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */ + if( (u8)p[0] != 0x00 ) + { + msg_Warn( p_input, + "non-zero pointer field found, trying to continue" ); + p+=(u8)p[0]; + } + else + { + p++; + } + + /* This is the begining of a new section */ + + if( ((u8)(p[1]) & 0xc0) != 0x80 ) + { + msg_Warn( p_input, "invalid PSI packet" ); + p_psi->b_trash = 1; + } + else + { + p_psi->i_section_length = ((p[1] & 0xF) << 8) | p[2]; + p_psi->b_section_complete = 0; + p_psi->i_read_in_section = 0; + p_psi->i_section_number = (u8)p[6]; + + if( p_psi->b_is_complete || p_psi->i_section_number == 0 ) + { + /* This is a new PSI packet */ + p_psi->b_is_complete = 0; + p_psi->b_trash = 0; + p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f; + p_psi->i_last_section_number = (u8)p[7]; + + /* We'll write at the begining of the buffer */ + p_psi->p_current = p_psi->buffer; + } + else + { + if( p_psi->b_section_complete ) + { + /* New Section of an already started PSI */ + p_psi->b_section_complete = 0; + + if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) ) + { + msg_Warn( p_input, + "PSI version differs inside same PAT" ); + p_psi->b_trash = 1; + } + if( p_psi->i_section_number + 1 != (u8)p[6] ) + { + msg_Warn( p_input, + "PSI Section discontinuity, packet lost?" ); + p_psi->b_trash = 1; + } + else + p_psi->i_section_number++; + } + else + { + msg_Warn( p_input, "got unexpected new PSI section" ); + p_psi->b_trash = 1; + } + } + } + } /* b_unit_start */ + + if( !p_psi->b_trash ) + { + /* read */ + if( (p_data->p_payload_end - p) >= + ( p_psi->i_section_length - p_psi->i_read_in_section ) ) + { + /* The end of the section is in this TS packet */ + memcpy( p_psi->p_current, p, + (p_psi->i_section_length - p_psi->i_read_in_section) ); + + p_psi->b_section_complete = 1; + p_psi->p_current += + (p_psi->i_section_length - p_psi->i_read_in_section); + + if( p_psi->i_section_number == p_psi->i_last_section_number ) + { + /* This was the last section of PSI */ + p_psi->b_is_complete = 1; + + switch( p_demux_data->i_psi_type) + { + case PSI_IS_PAT: + TSDecodePAT( p_input, p_es ); + break; + case PSI_IS_PMT: + TSDecodePMT( p_input, p_es ); + break; + default: + msg_Warn( p_input, "received unknown PSI in DemuxPSI" ); + } + } + } + else + { + memcpy( p_psi->buffer, p, p_data->p_payload_end - p ); + p_psi->i_read_in_section += p_data->p_payload_end - p; + + p_psi->p_current += p_data->p_payload_end - p; + } + } + +#undef p_psi +#undef p + + input_DeletePacket( p_input->p_method_data, p_data ); + + return ; +} + +/***************************************************************************** + * DecodePAT : Decodes Programm association table and deal with it + *****************************************************************************/ +static void TSDecodePAT( input_thread_t * p_input, es_descriptor_t * p_es ) +{ + stream_ts_data_t * p_stream_data; + es_ts_data_t * p_demux_data; + + pgrm_descriptor_t * p_pgrm; + es_descriptor_t * p_current_es; + byte_t * p_current_data; + + int i_section_length, i_program_id, i_pmt_pid; + int i_loop, i_current_section; + + vlc_bool_t b_changed = 0; + + p_demux_data = (es_ts_data_t *)p_es->p_demux_data; + p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data; + +#define p_psi (p_demux_data->p_psi_section) + + /* Not so fast, Mike ! If the PAT version has changed, we first check + * that its content has really changed before doing anything */ + if( p_stream_data->i_pat_version != p_psi->i_version_number ) + { + int i_programs = p_input->stream.i_pgrm_number; + + p_current_data = p_psi->buffer; + + do + { + i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) | + p_current_data[2]; + i_current_section = (u8)p_current_data[6]; + + for( i_loop = 0; + ( i_loop < (i_section_length - 9) / 4 ) && !b_changed; + i_loop++ ) + { + i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 ) + | *(p_current_data + i_loop * 4 + 9); + i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F) + << 8 ) + | *(p_current_data + i_loop * 4 + 11); + + if( i_program_id ) + { + if( (p_pgrm = input_FindProgram( p_input, i_program_id )) + && (p_current_es = input_FindES( p_input, i_pmt_pid )) + && p_current_es->p_pgrm == p_pgrm + && p_current_es->i_id == i_pmt_pid + && ((es_ts_data_t *)p_current_es->p_demux_data)->b_psi + && ((es_ts_data_t *)p_current_es->p_demux_data) + ->i_psi_type == PSI_IS_PMT ) + { + i_programs--; + } + else + { + b_changed = 1; + } + } + } + + p_current_data += 3 + i_section_length; + + } while( ( i_current_section < p_psi->i_last_section_number ) + && !b_changed ); + + /* If we didn't find the expected amount of programs, the PAT has + * changed. Otherwise, it only changed if b_changed is already != 0 */ + b_changed = b_changed || i_programs; + } + + if( b_changed ) + { + /* PAT has changed. We are going to delete all programs and + * create new ones. We chose not to only change what was needed + * as a PAT change may mean the stream is radically changing and + * this is a secure method to avoid crashes */ + es_ts_data_t * p_es_demux; + pgrm_ts_data_t * p_pgrm_demux; + + p_current_data = p_psi->buffer; + + /* Delete all programs */ + while( p_input->stream.i_pgrm_number ) + { + input_DelProgram( p_input, p_input->stream.pp_programs[0] ); + } + + do + { + i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) | + p_current_data[2]; + i_current_section = (u8)p_current_data[6]; + + for( i_loop = 0; i_loop < (i_section_length - 9) / 4 ; i_loop++ ) + { + i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 ) + | *(p_current_data + i_loop * 4 + 9); + i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F) + << 8 ) + | *(p_current_data + i_loop * 4 + 11); + + /* If program = 0, we're having info about NIT not PMT */ + if( i_program_id ) + { + /* Add this program */ + p_pgrm = input_AddProgram( p_input, i_program_id, + sizeof( pgrm_ts_data_t ) ); + + /* whatis the PID of the PMT of this program */ + p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data; + p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED; + + /* Add the PMT ES to this program */ + p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid, + sizeof( es_ts_data_t) ); + p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data; + p_es_demux->b_psi = 1; + p_es_demux->i_psi_type = PSI_IS_PMT; + + p_es_demux->p_psi_section = + malloc( sizeof( psi_section_t ) ); + p_es_demux->p_psi_section->b_is_complete = 0; + } + } + + p_current_data += 3 + i_section_length; + + } while( i_current_section < p_psi->i_last_section_number ); + + /* Go to the beginning of the next section */ + p_stream_data->i_pat_version = p_psi->i_version_number; + + } +#undef p_psi + +} + +/***************************************************************************** + * DecodePMT : decode a given Program Stream Map + * *************************************************************************** + * When the PMT changes, it may mean a deep change in the stream, and it is + * careful to delete the ES and add them again. If the PMT doesn't change, + * there no need to do anything. + *****************************************************************************/ +static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es ) +{ + + pgrm_ts_data_t * p_pgrm_data; + es_ts_data_t * p_demux_data; + + p_demux_data = (es_ts_data_t *)p_es->p_demux_data; + p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data; + +#define p_psi (p_demux_data->p_psi_section) + + if( p_psi->i_version_number != p_pgrm_data->i_pmt_version ) + { + es_descriptor_t * p_new_es; + es_ts_data_t * p_es_demux; + byte_t * p_current_data, * p_current_section; + int i_section_length,i_current_section; + int i_prog_info_length, i_loop; + int i_es_info_length, i_pid, i_stream_type; + + p_current_section = p_psi->buffer; + p_current_data = p_psi->buffer; + + p_pgrm_data->i_pcr_pid = ( ((u32)*(p_current_section + 8) & 0x1F) << 8 ) | + *(p_current_section + 9); + + + /* Lock stream information */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* Delete all ES in this program except the PSI. We start from the + * end because i_es_number gets decremented after each deletion. */ + for( i_loop = p_es->p_pgrm->i_es_number ; i_loop ; ) + { + i_loop--; + p_es_demux = (es_ts_data_t *) + p_es->p_pgrm->pp_es[i_loop]->p_demux_data; + if ( ! p_es_demux->b_psi ) + { + input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] ); + } + } + + /* Then add what we received in this PMT */ + do + { + i_section_length = ( ((u32)*(p_current_data + 1) & 0xF) << 8 ) | + *(p_current_data + 2); + i_current_section = (u8)p_current_data[6]; + i_prog_info_length = ( ((u32)*(p_current_data + 10) & 0xF) << 8 ) | + *(p_current_data + 11); + + /* For the moment we ignore program descriptors */ + p_current_data += 12 + i_prog_info_length; + + /* The end of the section, before the CRC is at + * p_current_section + i_section_length -1 */ + while( p_current_data < p_current_section + i_section_length -1 ) + { + i_stream_type = (int)p_current_data[0]; + i_pid = ( ((u32)*(p_current_data + 1) & 0x1F) << 8 ) | + *(p_current_data + 2); + i_es_info_length = ( ((u32)*(p_current_data + 3) & 0xF) << 8 ) | + *(p_current_data + 4); + + /* Add this ES to the program */ + p_new_es = input_AddES( p_input, p_es->p_pgrm, + (u16)i_pid, sizeof( es_ts_data_t ) ); + + /* Tell the interface what kind of stream it is and select + * the required ones */ + { + switch( i_stream_type ) + { + case MPEG1_VIDEO_ES: + case MPEG2_VIDEO_ES: + p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v'); + p_new_es->i_cat = VIDEO_ES; + break; + case MPEG1_AUDIO_ES: + case MPEG2_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('m','p','g','a'); + p_new_es->i_cat = AUDIO_ES; + break; + case LPCM_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('l','p','c','m'); + p_new_es->i_stream_id = 0xBD; + p_new_es->i_cat = AUDIO_ES; + break; + case A52_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('a','5','2',' '); + p_new_es->i_stream_id = 0xBD; + p_new_es->i_cat = AUDIO_ES; + break; + /* Not sure this one is fully specification-compliant */ + case DVD_SPU_ES: + p_new_es->i_fourcc = VLC_FOURCC('s','p','u',' '); + p_new_es->i_stream_id = 0xBD; + p_new_es->i_cat = SPU_ES; + break; + default : + p_new_es->i_fourcc = 0; + p_new_es->i_cat = UNKNOWN_ES; + break; + } + } + + p_current_data += 5 + i_es_info_length; + } + + /* Go to the beginning of the next section*/ + p_current_data += 3 + i_section_length; + + p_current_section++; + + } while( i_current_section < p_psi->i_last_section_number ); + + p_pgrm_data->i_pmt_version = p_psi->i_version_number; + + /* if no program is selected :*/ + if( !p_input->stream.p_selected_program ) + { + pgrm_descriptor_t * p_pgrm_to_select; + u16 i_id = (u16)config_GetInt( p_input, "program" ); + + if( i_id != 0 ) /* if user specified a program */ + { + p_pgrm_to_select = input_FindProgram( p_input, i_id ); + + if( p_pgrm_to_select && p_pgrm_to_select == p_es->p_pgrm ) + p_input->pf_set_program( p_input, p_pgrm_to_select ); + } + else + p_input->pf_set_program( p_input, p_es->p_pgrm ); + } + + /* inform interface that stream has changed */ + p_input->stream.b_changed = 1; + /* Remove lock */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + +#undef p_psi +} + +#elif defined MODULE_NAME_IS_ts_dvbpsi +/* + * PSI Decoding using libdvbcss + */ + +/***************************************************************************** + * DemuxPSI : send the PSI to the right libdvbpsi decoder + *****************************************************************************/ +static void TS_DVBPSI_DemuxPSI( input_thread_t * p_input, + data_packet_t * p_data, + es_descriptor_t * p_es, + vlc_bool_t b_unit_start ) +{ + es_ts_data_t * p_es_demux_data; + pgrm_ts_data_t * p_pgrm_demux_data; + stream_ts_data_t * p_stream_demux_data; + + p_es_demux_data = ( es_ts_data_t * ) p_es->p_demux_data; + p_stream_demux_data = ( stream_ts_data_t * ) p_input->stream.p_demux_data; + + switch( p_es_demux_data->i_psi_type) + { + case PSI_IS_PAT: + dvbpsi_PushPacket( + ( dvbpsi_handle ) p_stream_demux_data->p_pat_handle, + p_data->p_demux_start ); + break; + case PSI_IS_PMT: + p_pgrm_demux_data = ( pgrm_ts_data_t * )p_es->p_pgrm->p_demux_data; + dvbpsi_PushPacket( + ( dvbpsi_handle ) p_pgrm_demux_data->p_pmt_handle, + p_data->p_demux_start ); + break; + default: + msg_Warn( p_input, "received unknown PSI in DemuxPSI" ); + } + + input_DeletePacket( p_input->p_method_data, p_data ); +} + +/***************************************************************************** + * HandlePAT: will treat a PAT returned by dvbpsi + *****************************************************************************/ + +void TS_DVBPSI_HandlePAT( input_thread_t * p_input, dvbpsi_pat_t * p_new_pat ) +{ + dvbpsi_pat_program_t * p_pgrm; + pgrm_descriptor_t * p_new_pgrm; + pgrm_ts_data_t * p_pgrm_demux; + es_descriptor_t * p_current_es; + es_ts_data_t * p_es_demux; + stream_ts_data_t * p_stream_data; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data; + + if ( !p_new_pat->b_current_next || + p_stream_data->i_pat_version == PAT_UNINITIALIZED ) + { + /* Delete all programs */ + while( p_input->stream.i_pgrm_number ) + { + input_DelProgram( p_input, p_input->stream.pp_programs[0] ); + } + + /* treat the new programs list */ + p_pgrm = p_new_pat->p_first_program; + + while( p_pgrm ) + { + /* If program = 0, we're having info about NIT not PMT */ + if( p_pgrm->i_number ) + { + /* Add this program */ + p_new_pgrm = input_AddProgram( p_input, p_pgrm->i_number, + sizeof( pgrm_ts_data_t ) ); + + p_pgrm_demux = (pgrm_ts_data_t *)p_new_pgrm->p_demux_data; + p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED; + + /* Add the PMT ES to this program */ + p_current_es = input_AddES( p_input, p_new_pgrm, + (u16) p_pgrm->i_pid, + sizeof( es_ts_data_t) ); + p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data; + p_es_demux->b_psi = 1; + p_es_demux->i_psi_type = PSI_IS_PMT; + + p_es_demux->p_psi_section = malloc( sizeof( psi_section_t ) ); + if ( p_es_demux->p_psi_section == NULL ) + { + msg_Err( p_input, "out of memory" ); + p_input->b_error = 1; + return; + } + + p_es_demux->p_psi_section->b_is_complete = 0; + + /* Create a PMT decoder */ + p_pgrm_demux->p_pmt_handle = (dvbpsi_handle *) + dvbpsi_AttachPMT( p_pgrm->i_number, + (dvbpsi_pmt_callback) &TS_DVBPSI_HandlePMT, + p_input ); + + if( p_pgrm_demux->p_pmt_handle == NULL ) + { + msg_Err( p_input, "could not create PMT decoder" ); + p_input->b_error = 1; + return; + } + + } + p_pgrm = p_pgrm->p_next; + } + + p_stream_data->i_pat_version = p_new_pat->i_version; + } + vlc_mutex_unlock( &p_input->stream.stream_lock ); +} + +/***************************************************************************** + * HandlePMT: will treat a PMT returned by dvbpsi + *****************************************************************************/ +void TS_DVBPSI_HandlePMT( input_thread_t * p_input, dvbpsi_pmt_t * p_new_pmt ) +{ + dvbpsi_pmt_es_t * p_es; + pgrm_descriptor_t * p_pgrm; + es_descriptor_t * p_new_es; + pgrm_ts_data_t * p_pgrm_demux; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_pgrm = input_FindProgram( p_input, p_new_pmt->i_program_number ); + + if( p_pgrm == NULL ) + { + msg_Warn( p_input, "PMT of unreferenced program found" ); + return; + } + + p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data; + p_pgrm_demux->i_pcr_pid = p_new_pmt->i_pcr_pid; + + if( !p_new_pmt->b_current_next || + p_pgrm_demux->i_pmt_version == PMT_UNINITIALIZED ) + { + p_es = p_new_pmt->p_first_es; + while( p_es ) + { + /* Add this ES */ + p_new_es = input_AddES( p_input, p_pgrm, + (u16)p_es->i_pid, sizeof( es_ts_data_t ) ); + if( p_new_es == NULL ) + { + msg_Err( p_input, "could not add ES %d", p_es->i_pid ); + p_input->b_error = 1; + return; + } + + switch( p_es->i_type ) + { + case MPEG1_VIDEO_ES: + case MPEG2_VIDEO_ES: + p_new_es->i_fourcc = VLC_FOURCC('m','p','g','v'); + p_new_es->i_cat = VIDEO_ES; + break; + case MPEG1_AUDIO_ES: + case MPEG2_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('m','p','g','a'); + p_new_es->i_cat = AUDIO_ES; + break; + case LPCM_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('l','p','c','m'); + p_new_es->i_cat = AUDIO_ES; + p_new_es->i_stream_id = 0xBD; + break; + case A52_AUDIO_ES: + p_new_es->i_fourcc = VLC_FOURCC('a','5','2',' '); + p_new_es->i_cat = AUDIO_ES; + p_new_es->i_stream_id = 0xBD; + break; + case DVD_SPU_ES: + p_new_es->i_fourcc = VLC_FOURCC('s','p','u',' '); + p_new_es->i_cat = SPU_ES; + p_new_es->i_stream_id = 0xBD; + break; + default: + p_new_es->i_fourcc = 0; + p_new_es->i_cat = UNKNOWN_ES; + } + + if( ( p_new_es->i_cat == AUDIO_ES ) + || (p_new_es->i_cat == SPU_ES ) ) + { + dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor; + while( p_dr && ( p_dr->i_tag != 0x0a ) ) + p_dr = p_dr->p_next; + if( p_dr ) + { + dvbpsi_iso639_dr_t *p_decoded = + dvbpsi_DecodeISO639Dr( p_dr ); + if( p_decoded->i_code_count > 0 ) + { + const iso639_lang_t * p_iso; + p_iso = GetLang_2T(p_decoded->i_iso_639_code); + if(p_iso) + { + if(p_iso->psz_native_name[0]) + strcpy( p_new_es->psz_desc, + p_iso->psz_native_name ); + else + strcpy( p_new_es->psz_desc, + p_iso->psz_eng_name ); + } + else + { + strncpy( p_new_es->psz_desc, + p_decoded->i_iso_639_code, 3 ); + } + } + } + switch( p_es->i_type ) + { + case MPEG1_AUDIO_ES: + case MPEG2_AUDIO_ES: + strcat( p_new_es->psz_desc, " (mpeg)" ); + break; + case LPCM_AUDIO_ES: + strcat( p_new_es->psz_desc, " (lpcm)" ); + break; + case A52_AUDIO_ES: + strcat( p_new_es->psz_desc, " (A52)" ); + break; + } + } + + p_es = p_es->p_next; + } + + /* if no program is selected :*/ + if( !p_input->stream.p_selected_program ) + { + pgrm_descriptor_t * p_pgrm_to_select; + u16 i_id = (u16)config_GetInt( p_input, "program" ); + + if( i_id != 0 ) /* if user specified a program */ + { + p_pgrm_to_select = input_FindProgram( p_input, i_id ); + + if( p_pgrm_to_select && p_pgrm_to_select == p_pgrm ) + p_input->pf_set_program( p_input, p_pgrm_to_select ); + } + else + p_input->pf_set_program( p_input, p_pgrm ); + } + /* if the pmt belongs to the currently selected program, we + * reselect it to update its ES */ + else if( p_pgrm == p_input->stream.p_selected_program ) + { + p_input->pf_set_program( p_input, p_pgrm ); + } + + p_pgrm_demux->i_pmt_version = p_new_pmt->i_version; + p_input->stream.b_changed = 1; + } + vlc_mutex_unlock( &p_input->stream.stream_lock ); +} +#endif diff --git a/modules/gui/beos/.cvsignore b/modules/gui/beos/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/beos/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/beos/AudioOutput.cpp b/modules/gui/beos/AudioOutput.cpp new file mode 100644 index 0000000000..d897165457 --- /dev/null +++ b/modules/gui/beos/AudioOutput.cpp @@ -0,0 +1,201 @@ +/***************************************************************************** + * aout.cpp: BeOS audio output + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: AudioOutput.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/***************************************************************************** + * aout_sys_t: BeOS audio output method descriptor + ***************************************************************************** + * This structure is part of the audio output thread descriptor. + * It describes some BeOS specific variables. + *****************************************************************************/ +struct aout_sys_t +{ + BPushGameSound * p_sound; + gs_audio_format * p_format; + void * p_buffer; + int i_buffer_size; + int i_buffer_pos; +}; + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int SetFormat ( aout_thread_t * ); +static int GetBufInfo ( aout_thread_t *, int ); +static void Play ( aout_thread_t *, byte_t *, int ); + +/***************************************************************************** + * OpenAudio: opens a BPushGameSound + *****************************************************************************/ +int E_(OpenAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + /* Allocate structure */ + p_aout->p_sys = (aout_sys_t*) malloc( sizeof( aout_sys_t ) ); + if( p_aout->p_sys == NULL ) + { + msg_Err( p_aout, "out of memory" ); + return( 1 ); + } + + /* Allocate gs_audio_format */ + p_aout->p_sys->p_format = (gs_audio_format *) malloc( sizeof( gs_audio_format ) ); + if( p_aout->p_sys->p_format == NULL ) + { + free( p_aout->p_sys ); + msg_Err( p_aout, "out of memory" ); + return( 1 ); + } + + /* Initialize some variables */ + p_aout->p_sys->p_format->frame_rate = 44100.0; + p_aout->p_sys->p_format->channel_count = p_aout->i_channels; + p_aout->p_sys->p_format->format = gs_audio_format::B_GS_S16; + p_aout->p_sys->p_format->byte_order = B_MEDIA_LITTLE_ENDIAN; + p_aout->p_sys->p_format->buffer_size = 4*8192; + p_aout->p_sys->i_buffer_pos = 0; + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = Play; + + /* Allocate BPushGameSound */ + p_aout->p_sys->p_sound = new BPushGameSound( 8192, + p_aout->p_sys->p_format, + 2, NULL ); + if( p_aout->p_sys->p_sound == NULL ) + { + free( p_aout->p_sys->p_format ); + free( p_aout->p_sys ); + msg_Err( p_aout, "cannot allocate BPushGameSound" ); + return( 1 ); + } + + if( p_aout->p_sys->p_sound->InitCheck() != B_OK ) + { + free( p_aout->p_sys->p_format ); + free( p_aout->p_sys ); + msg_Err( p_aout, "cannot initialize BPushGameSound" ); + return( 1 ); + } + + p_aout->p_sys->p_sound->StartPlaying( ); + + p_aout->p_sys->p_sound->LockForCyclic( &p_aout->p_sys->p_buffer, + (size_t *)&p_aout->p_sys->i_buffer_size ); + + return( 0 ); +} + +/***************************************************************************** + * SetFormat: sets the dsp output format + *****************************************************************************/ +static int SetFormat( aout_thread_t *p_aout ) +{ + return( 0 ); +} + +/***************************************************************************** + * GetBufInfo: buffer status query + *****************************************************************************/ +static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +{ + /* Each value is 4 bytes long (stereo signed 16 bits) */ + int i_hard_pos = 4 * p_aout->p_sys->p_sound->CurrentPosition(); + + i_hard_pos = p_aout->p_sys->i_buffer_pos - i_hard_pos; + if( i_hard_pos < 0 ) + { + i_hard_pos += p_aout->p_sys->i_buffer_size; + } + + return( i_hard_pos ); +} + +/***************************************************************************** + * 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_newbuf_pos; + + if( (i_newbuf_pos = p_aout->p_sys->i_buffer_pos + i_size) + > p_aout->p_sys->i_buffer_size ) + { + memcpy( (void *)((int)p_aout->p_sys->p_buffer + + p_aout->p_sys->i_buffer_pos), + buffer, + p_aout->p_sys->i_buffer_size - p_aout->p_sys->i_buffer_pos ); + + memcpy( (void *)((int)p_aout->p_sys->p_buffer), + buffer + p_aout->p_sys->i_buffer_size - p_aout->p_sys->i_buffer_pos, + i_size - ( p_aout->p_sys->i_buffer_size + - p_aout->p_sys->i_buffer_pos ) ); + + p_aout->p_sys->i_buffer_pos = i_newbuf_pos - p_aout->p_sys->i_buffer_size; + + } + else + { + memcpy( (void *)((int)p_aout->p_sys->p_buffer + p_aout->p_sys->i_buffer_pos), + buffer, i_size ); + + p_aout->p_sys->i_buffer_pos = i_newbuf_pos; + } +} + +/***************************************************************************** + * CloseAudio: closes the dsp audio device + *****************************************************************************/ +void E_(CloseAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + p_aout->p_sys->p_sound->UnlockCyclic(); + p_aout->p_sys->p_sound->StopPlaying( ); + delete p_aout->p_sys->p_sound; + free( p_aout->p_sys->p_format ); + free( p_aout->p_sys ); +} + diff --git a/modules/gui/beos/BeOS.cpp b/modules/gui/beos/BeOS.cpp new file mode 100644 index 0000000000..b453351f23 --- /dev/null +++ b/modules/gui/beos/BeOS.cpp @@ -0,0 +1,60 @@ +/***************************************************************************** + * beos.cpp : BeOS plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: BeOS.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t * ); +void E_(CloseIntf) ( vlc_object_t * ); + +int E_(OpenAudio) ( vlc_object_t * ); +void E_(CloseAudio) ( vlc_object_t * ); + +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("BeOS standard API module") ); + add_submodule(); + set_capability( "interface", 100 ); + set_callbacks( E_(OpenIntf), E_(CloseIntf) ); + add_submodule(); + set_capability( "video output", 100 ); + set_callbacks( E_(OpenVideo), E_(CloseVideo) ); + add_submodule(); + set_capability( "audio output", 100 ); + set_callbacks( E_(OpenAudio), E_(CloseAudio) ); +vlc_module_end(); + diff --git a/modules/gui/beos/Bitmaps.h b/modules/gui/beos/Bitmaps.h new file mode 100644 index 0000000000..cbde2434d6 --- /dev/null +++ b/modules/gui/beos/Bitmaps.h @@ -0,0 +1,1749 @@ +/***************************************************************************** + * Bitmaps.h + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: Bitmaps.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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 "Bitmaps.h" + +const unsigned char eject16x11_raw[] = { +0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0x00,0x17,0x18,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x00,0x17,0x17,0x18,0x17,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x00,0x17,0x18,0x17,0x18,0x17,0x17,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x17,0x18,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x17,0x18,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff}; +const unsigned char pause16x10_raw[] = { +0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0x00,0x3f,0x3f,0x3f,0x3f,0xff,0xff,0xff,0xff}; +const unsigned char play16x10_raw[] = { +0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x18,0x17,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x18,0x17,0x18,0x17,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x18,0x17,0x17,0x18,0x17,0x18,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; +const unsigned char skipleft24x8_raw[] = { +0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00, +0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x17,0x3f, +0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x17,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x00,0x00,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0x00,0x00,0x17,0x18,0x17, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x17,0x17,0x18,0x17,0x17,0x3f, +0xff,0x00,0x00,0x17,0x18,0x17,0x18,0x17,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x3f,0x3f,0x17,0x17,0x18,0x17,0x17,0x3f,0xff,0x3f,0x3f,0x17,0x17,0x18,0x17,0x17, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0x17,0x17,0x18,0x3f, +0xff,0xff,0xff,0x3f,0x3f,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0x3f,0x3f,0x17,0x3f,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0x17, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; +const unsigned char skipright24x8_raw[] = { +0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x17,0x00,0x00,0xff,0xff,0xff,0xff, +0xff,0x00,0x18,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x00,0x00,0xff,0xff,0xff,0x00,0x18,0x17,0x17,0x00,0x00,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x17,0x17,0x18,0x17,0x17,0x00,0x00, +0xff,0x00,0x17,0x18,0x17,0x17,0x18,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x3f,0x3f,0xff,0x00,0x17,0x18,0x17,0x18,0x17,0x3f, +0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0x3f,0xff,0xff, +0xff,0x00,0x17,0x18,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x00,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0x00,0x17,0x3f,0x3f,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; +const unsigned char skiptrackleft24x8_raw[] = { +0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0x00, +0x00,0x17,0x3f,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x17,0x3f,0xff,0xff,0xff,0xff, +0x00,0x3f,0xff,0xff,0xff,0x00,0x00,0x17,0x18,0x17,0x3f,0xff,0xff,0xff,0x00,0x00, +0x17,0x18,0x17,0x3f,0xff,0xff,0xff,0xff,0x00,0x3f,0xff,0x00,0x00,0x17,0x18,0x17, +0x18,0x17,0x3f,0xff,0x00,0x00,0x17,0x18,0x17,0x18,0x17,0x3f,0xff,0xff,0xff,0xff, +0x00,0x3f,0xff,0x3f,0x3f,0x17,0x17,0x18,0x17,0x17,0x3f,0xff,0x3f,0x3f,0x17,0x17, +0x18,0x17,0x17,0x3f,0xff,0xff,0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0x3f,0x3f,0x17, +0x17,0x18,0x3f,0xff,0xff,0xff,0x3f,0x3f,0x17,0x17,0x18,0x3f,0xff,0xff,0xff,0xff, +0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0x17,0x3f,0xff,0xff,0xff,0xff,0xff, +0x3f,0x3f,0x17,0x3f,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff}; +const unsigned char skiptrackright24x8_raw[] = { +0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x17,0x00,0x00,0xff,0xff,0xff,0xff, +0xff,0x00,0x18,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x00,0x00,0xff,0xff,0xff,0x00,0x18,0x17,0x17,0x00,0x00,0xff, +0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0xff,0x00,0x17,0x17,0x18,0x17,0x17,0x00,0x00, +0xff,0x00,0x17,0x18,0x17,0x17,0x18,0x00,0x00,0xff,0x00,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x17,0x18,0x17,0x17,0x3f,0x3f,0xff,0x00,0x17,0x18,0x17,0x18,0x17,0x3f, +0x3f,0xff,0x00,0x3f,0xff,0xff,0xff,0xff,0x00,0x17,0x17,0x18,0x3f,0x3f,0xff,0xff, +0xff,0x00,0x17,0x18,0x17,0x3f,0x3f,0xff,0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0xff, +0x00,0x17,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0x00,0x17,0x3f,0x3f,0xff,0xff,0xff, +0xff,0xff,0x00,0x3f,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0xff,0xff,0xff,0xff}; +const unsigned char stop8x8_raw[] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f,0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f,0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f, +0x00,0x17,0x17,0x18,0x17,0x17,0x18,0x3f,0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f}; +const unsigned char LCDLarge96x16_raw[] = { +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x8d,0x21,0x21,0x22,0x21,0x8d,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21,0x21,0x8d,0xff,0xff,0xff,0xff,0x8d,0x22, +0x21,0x8d,0x21,0x21,0x22,0x21,0x8d,0xff,0x22,0x8d,0x21,0x21,0x22,0x21,0x8d,0xff, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21,0x21,0x8d,0x21,0x22,0x21,0x21,0x8d,0x22, +0x21,0x8d,0x21,0x22,0x21,0x21,0x8d,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0xff,0x22,0x8d,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21,0x21,0x8d,0x21,0x22,0x21,0x21,0x8d,0x22, +0x21,0x8d,0x21,0x22,0x21,0x21,0xff,0xff,0x22,0x8d,0x21,0x21,0x22,0x21,0x8d,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0x21,0x21,0x22,0x21,0x8d,0x21, +0x22,0x8d,0x21,0x21,0x22,0x21,0x8d,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0x8d,0xff,0xff,0xff,0xff,0xff,0xff,0x8d, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x8d,0x22,0x21,0x21,0x21,0x22,0x21,0x8d, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0x8d,0x8d,0x21,0x22,0x21,0x21,0x22,0x21,0x8d, +0x8d,0x21,0x22,0x21,0x21,0x22,0x21,0x8d,0x8d,0x21,0x21,0x22,0x21,0x21,0x22,0x8d, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x8d,0x22,0x21,0x21,0x21,0x22,0x21,0x8d, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0x8d,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x8d,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x8d,0x21,0x21,0x22,0x21,0x8d,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0x21,0x21,0x22,0x21,0xff,0xff, +0xff,0xff,0x22,0x21,0x21,0x22,0x8d,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21,0x21,0x8d,0x21,0x22,0x21,0x21,0x8d,0x22, +0xff,0xff,0xff,0xff,0xff,0xff,0x8d,0x22,0x21,0x8d,0x21,0x21,0x22,0x21,0x8d,0x21, +0xff,0x8d,0x22,0x21,0x21,0x22,0x8d,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff, +0xff,0x22,0x21,0x21,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; +const unsigned char LCDMedium64x9_raw[] = { +0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0x34,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x34,0x34,0x34,0xff,0x8d,0xff,0xff,0xff,0x8d,0xff,0xff,0xff,0xff,0x8d,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0x8d,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0x34, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0x34,0x34,0x34,0xff,0xff,0x34,0x34,0x34,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; +const unsigned char LCDsmall64x8_raw[] = { +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0x22,0xff, +0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0x22, +0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0x22,0x21,0x21,0x22,0xff,0xff,0x22,0x21, +0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff, +0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0x22,0x21,0xff, +0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff, +0xff,0x22,0x21,0xff,0xff,0xff,0x22,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff, +0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff,0xff,0x22,0x21,0xff, +0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff, +0xff,0x22,0x21,0xff,0xff,0xff,0x22,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x22,0x21,0x21,0xff,0x8d,0xff,0xff,0xff,0x8d,0xff,0xff,0xff,0xff,0x8d,0xff, +0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0x22, +0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0x8d,0xff,0x22,0x21, +0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21, +0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff, +0xff,0xff,0x22,0x21,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff, +0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff, +0xff,0xff,0x22,0x21,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff, +0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff, +0xff,0xff,0x22,0x21,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0x22,0x21,0xff,0xff, +0xff,0x22,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0x22,0xff, +0x22,0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0x22, +0x21,0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0x22,0x21, +0x21,0xff,0xff,0x22,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff +}; + +const int32 kSpeakerIconBitmapWidth = 16; +const int32 kSpeakerIconBitmapHeight = 9; +const BPoint kSpeakerButtonSize(kSpeakerIconBitmapWidth - 1, kSpeakerIconBitmapHeight - 1); + + +const unsigned char kSpeakerIconBits [] = { + 0xff,0xff,0xff,0xff,0xff,0x10,0x10,0xff,0xff,0xff,0xff,0x10,0xff,0xff,0xff,0xff, + 0x10,0x10,0x10,0xff,0x10,0x1d,0x10,0xff,0xff,0xff,0xff,0xff,0x10,0xff,0xff,0xff, + 0x10,0x1d,0x10,0x10,0x1d,0x1d,0x10,0xff,0xff,0x10,0xff,0xff,0x10,0xff,0xff,0xff, + 0x10,0x1d,0x10,0x1d,0x1d,0x1d,0x10,0xff,0xff,0xff,0x10,0xff,0xff,0x10,0xff,0xff, + 0x10,0x1d,0x10,0x1d,0x1d,0x1d,0x10,0xff,0x10,0xff,0x10,0xff,0xff,0x10,0xff,0xff, + 0x10,0x1d,0x10,0x1d,0x1d,0x1d,0x10,0xff,0xff,0xff,0x10,0xff,0xff,0x10,0xff,0xff, + 0x10,0x1d,0x10,0x10,0x1d,0x1d,0x10,0xff,0xff,0x10,0xff,0xff,0x10,0xff,0xff,0xff, + 0x10,0x10,0x10,0xff,0x10,0x1d,0x10,0xff,0xff,0xff,0xff,0xff,0x10,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x10,0x10,0xff,0xff,0xff,0xff,0x10,0xff,0xff,0xff,0xff, +}; + +const unsigned char kPressedSpeakerIconBits [] = { + 0xff,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff, + 0x34,0x34,0x34,0xff,0x34,0x1d,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff, + 0x34,0x1d,0x34,0x34,0x1d,0x1d,0x34,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff, + 0x34,0x1d,0x34,0x1d,0x1d,0x1d,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff, + 0x34,0x1d,0x34,0x1d,0x1d,0x1d,0x34,0xff,0x34,0xff,0x34,0xff,0xff,0x34,0xff,0xff, + 0x34,0x1d,0x34,0x1d,0x1d,0x1d,0x34,0xff,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff, + 0x34,0x1d,0x34,0x34,0x1d,0x1d,0x34,0xff,0xff,0x34,0xff,0xff,0x34,0xff,0xff,0xff, + 0x34,0x34,0x34,0xff,0x34,0x1d,0x34,0xff,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x34,0x34,0xff,0xff,0xff,0xff,0x34,0xff,0xff,0xff,0xff, +}; + + +// #pragma mark play + +const int32 kPlayPauseBitmapWidth = 48; +const int32 kPlayPauseBitmapHeight = 22; +const BPoint kPlayButtonSize(kPlayPauseBitmapWidth - 1, kPlayPauseBitmapHeight - 1); + +const unsigned char kPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11,0x12,0x19,0xff,0xff,0xff, + 0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x14,0x11,0x16,0x1a,0xff,0xff, + 0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x11,0x1a,0xff,0xff, + 0xff,0x17,0x11,0x18,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x00,0x00,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x00,0x10,0x1a,0x1a,0x00,0x00,0x00,0x10,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff, + 0xff,0x14,0x11,0x1d,0x1d,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff, + 0xff,0x13,0x10,0x1e,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff, + 0xff,0x13,0x10,0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e,0xff, + 0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a,0x1e,0xff, + 0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16,0x1e,0x1c,0xff, + 0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12,0x19,0x3f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12,0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kDisabledPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0x1a,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x1a,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x18, + 0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x19,0x1a,0x1a,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x18,0x1a,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1b,0x19,0x18,0x18,0x1a,0x1a,0xff,0xff,0xff,0xff,0xff,0x1a, + 0x19,0x18,0x19,0x1c,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a, + 0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x19,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a,0x18,0x1a,0x1c, + 0xff,0xff,0xff,0x1a,0x19,0x18,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x18,0x1c,0xff,0xff,0xff,0x1a, + 0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x16, + 0x16,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16, + 0x16,0x1b,0x1b,0x1b,0x16,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1a,0x18,0x1a,0x1c,0xff,0xff,0x19,0x17,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x16,0x16,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b, + 0x16,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18, + 0x19,0x1c,0xff,0xff,0x19,0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x16,0x16,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b,0x16,0x19,0x19,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x17,0x1c,0xff,0xff, + 0x19,0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x16, + 0x19,0x19,0x1c,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff,0x19,0x16,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b, + 0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x18,0x18,0x1c,0xff,0xff,0x19,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x1c,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b,0x16,0x19,0x19, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff, + 0xff,0x19,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16, + 0x19,0x19,0x19,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x16,0x19,0x19,0x1c,0x1b,0x1b,0x16,0x19,0x19,0x1c,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c,0xff,0xff,0x1a,0x18,0x19, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1a,0x17,0x1a,0x1c,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x18,0x1c,0x1c, + 0xff,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1a,0x19,0x17,0x1b,0x1c,0xff,0xff,0xff,0xff,0xff, + 0xff,0x19,0x18,0x19,0x1a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18, + 0x17,0x1a,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1a,0x18, + 0x18,0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x18,0x17,0x18,0x1b,0x1c,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1c,0x1a,0x19,0x17,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x19,0x1a,0x1c,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1d,0x1d, + 0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff, +}; + + +const unsigned char kPressedPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0x19, + 0x12,0x10,0x0d,0x0a,0x0f,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f, + 0x11,0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x16,0x1a, + 0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x00,0x10,0x13,0x13,0x00,0x00,0x00,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e,0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a,0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x10,0x19,0x19,0x19,0x13,0x13,0x10,0x19,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16,0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12,0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +const unsigned char kPlayingPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c, + 0x19,0x16,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0x19, + 0x12,0x10,0x17,0x1c,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14, + 0x11,0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x14,0x11,0x16,0x1a, + 0xff,0xff,0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x11,0x1a,0xff,0xff,0xff,0x17, + 0x11,0x18,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x00, + 0x00,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00, + 0x00,0x10,0x1a,0x1a,0x00,0x00,0x00,0x10,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d,0x1d,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x00,0x00,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a, + 0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x12, + 0x13,0xff,0xff,0xff,0x13,0x10,0x1e,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x00,0x34,0x34,0x34,0x34,0x34,0x00,0x00,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff, + 0x13,0x10,0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34, + 0x34,0x34,0x34,0x34,0x34,0x34,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x00, + 0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13,0x10,0x1d,0x19, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x34,0x34, + 0x34,0x34,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a, + 0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18, + 0x13,0x10,0x3f,0xff,0xff,0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x34,0x34,0x3f,0x3f,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00, + 0x34,0x34,0x34,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x00,0x17,0x17,0x3f,0x1a,0x1a,0x00,0x17,0x17,0x3f,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e,0xff,0xff,0x17,0x11,0x13, + 0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x3f,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x10,0x3f,0x3f,0x3f, + 0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x14,0x10,0x1a,0x1e,0xff,0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16,0x1e,0x1c, + 0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x15,0x10,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff, + 0x18,0x11,0x11,0x14,0x17,0x18,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10, + 0x12,0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11, + 0x12,0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x16,0x13,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d, + 0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff, +}; + + +const unsigned char kPressedPlayingPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0x19, + 0x12,0x10,0x0d,0x0a,0x0f,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f, + 0x11,0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x16,0x1a, + 0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17, + 0x11,0x0d,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x00,0x00,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x00,0x10,0x13, + 0x13,0x00,0x00,0x00,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f, + 0x13,0xff,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x00,0x34,0x34,0x34,0x00,0x00,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x34,0x34,0x34,0x34,0x34,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x34,0x34, + 0x34,0x34,0x34,0x00,0x00,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19, + 0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x19, + 0x19,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10, + 0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x34,0x34,0x34,0x34,0x34,0x19,0x19,0x13,0x13,0x13,0x13,0x13, + 0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e,0xff,0xff,0x17,0x11,0x11, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x34, + 0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10, + 0x19,0x13,0x13,0x00,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13, + 0x12,0x10,0x1a,0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x19,0x19,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x10,0x19,0x19,0x19,0x13,0x13,0x10, + 0x19,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16,0x1e,0x1c, + 0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff, + 0x18,0x11,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10, + 0x12,0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10, + 0x11,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x14,0x13,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d, + 0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff, +}; + +const unsigned char kPausedPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11,0x12,0x19,0xff,0xff,0xff, + 0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x14,0x11,0x16,0x1a,0xff,0xff, + 0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x11,0x1a,0xff,0xff, + 0xff,0x17,0x11,0x18,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x00,0x00,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x00,0x10,0x1a,0x1a,0x00,0x00,0x00,0x10,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff, + 0xff,0x14,0x11,0x1d,0x1d,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff, + 0xff,0x13,0x10,0x1e,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff, + 0xff,0x13,0x10,0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x00,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e,0xff, + 0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a,0x1e,0xff, + 0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16,0x1e,0x1c,0xff, + 0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12,0x19,0x3f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12,0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +const unsigned char kPressedPausedPlayButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff,0x19, + 0x12,0x10,0x0d,0x0a,0x0f,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f, + 0x11,0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x16,0x1a, + 0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17, + 0x11,0x0d,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x00,0x00,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x00,0x10,0x13, + 0x13,0x00,0x00,0x00,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f, + 0x13,0xff,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x00,0x34,0x34, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x34,0x34,0x19,0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x00,0x00,0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x19, + 0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x19, + 0x19,0x13,0x13,0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x00,0x34, + 0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x10,0x10,0x10,0x10,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13, + 0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e,0xff,0xff,0x17,0x11,0x11, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10, + 0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x34, + 0x19,0x13,0x13,0x00,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13, + 0x12,0x10,0x1a,0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x19,0x19,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x10,0x19,0x19,0x19,0x13,0x13,0x10, + 0x19,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16,0x1e,0x1c, + 0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff, + 0x18,0x11,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10, + 0x12,0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10, + 0x11,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x14,0x13,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d, + 0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff, +}; + +// #pragma mark stop + +const int32 kStopBitmapWidth = 32; +const int32 kStopBitmapHeight = 22; +const BPoint kStopButtonSize(kStopBitmapWidth - 1, kStopBitmapHeight - 1); + + +const unsigned char kStopButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a, + 0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16, + 0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x1c,0x19,0x16,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff, + 0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11,0x12, + 0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x18,0x14,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11, + 0x12,0x1d,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x11, + 0x1a,0xff,0xff,0xff,0x17,0x11,0x18,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d, + 0x1d,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17, + 0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13, + 0xff,0xff,0xff,0x13,0x10,0x1e,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff,0x13,0x10,0x3f,0x19, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17, + 0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f, + 0xff,0xff,0x13,0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13,0x10,0x19,0x19,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x17, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00, + 0x17,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x16,0x12,0x16,0x1e,0xff,0xff,0x17,0x11,0x13,0x16,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x10,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a,0x1e,0xff,0xff, + 0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15, + 0x10,0x16,0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0x18,0x11,0x11,0x14,0x17,0x18,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12,0x19, + 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12,0x12, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x12,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x19,0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff, +}; + + +const unsigned char kDisabledStopButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a, + 0x1a,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x1a,0x1a,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x1a,0x19,0x18,0x17,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x19,0x1a, + 0x1a,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x18,0x1a, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1b,0x19,0x18,0x18,0x1a,0x1a,0xff,0xff,0xff,0xff,0xff, + 0x1a,0x19,0x18,0x19,0x1c,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a,0x18,0x18, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x19,0x1c,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1c,0x1a,0x18,0x1a,0x1c,0xff,0xff,0xff,0x1a,0x19, + 0x18,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x18, + 0x1c,0xff,0xff,0xff,0x1a,0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x1a,0x1c,0xff,0xff,0x19,0x17,0x1c, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x19, + 0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19, + 0x1c,0xff,0xff,0x19,0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x19,0x17,0x1c,0xff,0xff,0x19,0x16,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x19,0x19, + 0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c, + 0xff,0xff,0x19,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x16,0x19,0x19,0x19,0x19,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff,0xff,0x19,0x16,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x19, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff, + 0xff,0x19,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16, + 0x19,0x19,0x19,0x19,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x18,0x19,0x1c,0xff,0xff,0x1a,0x18,0x19,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x17,0x1a,0x1c,0xff,0xff, + 0x1a,0x19,0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a, + 0x18,0x18,0x1c,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1a,0x19,0x17,0x1b,0x1c,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x18,0x19,0x1a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x17,0x1a, + 0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1a,0x18,0x18,0x18, + 0x18,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x18,0x17,0x18,0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1c,0x1c,0x1a,0x19,0x17,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x19,0x1a,0x1c,0x1c,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1d,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff, +}; + + +const unsigned char kPressedStopButtonBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a, + 0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff,0xff,0xff, + 0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11,0x12, + 0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11, + 0x0d,0x0a,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11, + 0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x13, + 0xff,0xff,0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x19,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10,0x0d,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10, + 0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f, + 0xff,0xff,0x13,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x19,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13,0x10,0x0d,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10, + 0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x19,0x13,0x13,0x13,0x13,0x13, + 0x13,0x12,0x0f,0x16,0x1e,0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x10,0x10,0x10, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a,0x1e,0xff,0xff, + 0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x16,0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x0f,0x12,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0x18,0x11,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12,0x19, + 0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x19,0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff, +}; + +// #pragma mark rewind + +const int32 kRewindBitmapWidth = 40; +const int32 kRewindBitmapHeight = 22; +const BPoint kSkipButtonSize(kRewindBitmapWidth - 1, kRewindBitmapHeight - 1); + +const unsigned char kRewindBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11,0x12,0x19,0xff,0xff,0xff, + 0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x14,0x11,0x16,0x1a,0xff,0xff, + 0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x11,0x1a,0xff,0xff, + 0xff,0x17,0x11,0x18,0x3f,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff, + 0xff,0x14,0x11,0x1d,0x1d,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff, + 0xff,0x13,0x10,0x1e,0x19,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff, + 0xff,0x13,0x10,0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x00,0x00,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x00,0x00,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x00,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e,0xff, + 0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a,0x1e,0xff, + 0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16,0x1e,0x1c,0xff, + 0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12,0x19,0x3f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12,0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kDisabledRewindBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x1a,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x19,0x1a,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x18,0x1a,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1b,0x19,0x18,0x18,0x1a, + 0x1a,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x19,0x1c,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a,0x18, + 0x18,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x19,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c, + 0x1a,0x18,0x1a,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x19,0x18,0x1c,0xff,0xff,0xff,0x1a,0x18,0x1a,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16, + 0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1a,0x18,0x1a,0x1c,0xff,0xff,0x19,0x17,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16, + 0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x19,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c,0xff,0xff,0x19,0x16,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x1b,0x1b,0x16,0x16,0x19, + 0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x16,0x16,0x19,0x19,0x19,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x17,0x1c,0xff,0xff,0x19,0x16, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x16,0x16,0x19,0x19, + 0x19,0x19,0x19,0x1c,0x1b,0x16,0x16,0x19,0x19,0x19,0x19,0x19,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff,0x19, + 0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x1c,0x1c,0x19, + 0x19,0x19,0x19,0x19,0x1c,0x1b,0x1c,0x1c,0x19,0x19,0x19,0x19,0x19, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff, + 0x19,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x1b,0x1b, + 0x1c,0x1c,0x19,0x19,0x19,0x1c,0x1b,0x1b,0x1b,0x1c,0x1c,0x19,0x19, + 0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff, + 0xff,0x19,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1c,0x1c,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c, + 0x1c,0x19,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c, + 0xff,0xff,0x1a,0x18,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x17,0x1a, + 0x1c,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x18, + 0x1c,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x19,0x17, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x18,0x19,0x1a,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x17, + 0x1a,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1a,0x18,0x18, + 0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x18,0x17,0x18, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1c, + 0x1a,0x19,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x19,0x1a, + 0x1c,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1d, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kPressedRewindBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19,0xff,0xff,0xff,0xff, + 0xff,0xff,0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11,0x12,0x19,0xff,0xff,0xff, + 0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x16,0x1a,0xff,0xff, + 0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x1a,0xff,0xff, + 0xff,0x17,0x11,0x0d,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff, + 0xff,0x14,0x11,0x0a,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff, + 0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff, + 0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x13,0x13,0x00,0x00,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x00,0x00,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x00,0x00,0x34,0x34,0x34,0x34,0x34,0x19,0x13,0x00,0x00,0x34,0x34,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x19,0x19,0x34,0x34,0x34,0x34,0x34,0x19,0x13,0x19,0x19,0x34,0x34,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x13,0x13,0x19,0x19,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x19,0x19,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e,0xff, + 0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x19,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a,0x1e,0xff, + 0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x0f,0x16,0x1e,0x1c,0xff, + 0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12,0x1b,0x3f,0xff,0xff, + 0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12,0x19,0x3f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16,0x1b,0x3f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a,0x1d,0x3f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e,0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +// #pragma mark skip back + +const unsigned char kSkipBackBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18, + 0x14,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x16,0x12,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x18,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d,0x1d, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x3f,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff,0xff,0x13,0x10,0x1e, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x17,0x17, + 0x3f,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x17,0x17,0x17,0x17, + 0x17,0x3f,0x1a,0x00,0x00,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x17,0x17, + 0x17,0x17,0x3f,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x17,0x17,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f, + 0x17,0x17,0x17,0x3f,0x1a,0x1a,0x1a,0x3f,0x3f,0x17,0x17,0x17,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x3f,0x3f,0x17,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x17, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12, + 0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +const unsigned char kDisabledSkipBackBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x1a,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x19,0x1a,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x18,0x1a,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1b,0x19,0x18,0x18,0x1a, + 0x1a,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x19,0x1c,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a,0x18, + 0x18,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x19,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c, + 0x1a,0x18,0x1a,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x19,0x18,0x1c,0xff,0xff,0xff,0x1a,0x18,0x1a,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1a,0x18,0x1a,0x1c,0xff,0xff,0x19,0x17,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1c,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c,0xff,0xff,0x19,0x16,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b, + 0x1c,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1c,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x17,0x1c,0xff,0xff,0x19,0x16, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1c,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff,0x19, + 0x16,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1c,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff, + 0x19,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1c,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff, + 0xff,0x19,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1c,0x1c,0x1b,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c, + 0xff,0xff,0x1a,0x18,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x17,0x1a, + 0x1c,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x18, + 0x1c,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x19,0x17, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x18,0x19,0x1a,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x17, + 0x1a,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1a,0x18,0x18, + 0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x18,0x17,0x18, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1c, + 0x1a,0x19,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x19,0x1a, + 0x1c,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1d, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kPressedSkipBackBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff,0xff,0x13,0x10,0x0d, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00, + 0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x10,0x19,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x10, + 0x10,0x10,0x19,0x13,0x13,0x13,0x00,0x00,0x10,0x10,0x10,0x19,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x10,0x10, + 0x10,0x10,0x10,0x19,0x13,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x19, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x10, + 0x10,0x10,0x10,0x10,0x19,0x13,0x19,0x19,0x10,0x10,0x10,0x10,0x10, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x19,0x19,0x10,0x10,0x10,0x19,0x13,0x13,0x13,0x19,0x19,0x10,0x10, + 0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x19,0x19,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x19, + 0x19,0x10,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kSkippingSkipBackBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18, + 0x14,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x16,0x12,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x18,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d,0x1d, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x34,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x34,0x3f,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff,0xff,0x13,0x10,0x1e, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x34,0x34,0x34, + 0x3f,0x1a,0x1a,0x1a,0x00,0x00,0x34,0x34,0x34,0x3f,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x34,0x34,0x34,0x34, + 0x34,0x3f,0x1a,0x00,0x00,0x34,0x34,0x34,0x34,0x34,0x3f,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x34,0x34,0x34, + 0x34,0x34,0x3f,0x1a,0x3f,0x3f,0x34,0x34,0x34,0x34,0x34,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f, + 0x34,0x34,0x34,0x3f,0x1a,0x1a,0x1a,0x3f,0x3f,0x34,0x34,0x34,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x3f,0x3f,0x34,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x34, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12, + 0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kPressedSkippingSkipBackBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff,0xff,0x13,0x10,0x0d, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00, + 0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x34,0x19,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x34, + 0x34,0x34,0x19,0x13,0x13,0x13,0x00,0x00,0x34,0x34,0x34,0x19,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x34,0x34, + 0x34,0x34,0x34,0x19,0x13,0x00,0x00,0x34,0x34,0x34,0x34,0x34,0x19, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x34, + 0x34,0x34,0x34,0x34,0x19,0x13,0x19,0x19,0x34,0x34,0x34,0x34,0x34, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x19,0x19,0x34,0x34,0x34,0x19,0x13,0x13,0x13,0x19,0x19,0x34,0x34, + 0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x19,0x19,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x19, + 0x19,0x34,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +// #pragma mark skip forward + +const unsigned char kSkipForwardBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18, + 0x14,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x16,0x12,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x18,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d,0x1d, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x00,0x00,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x00,0x17,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff,0xff,0x13,0x10,0x1e, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x00, + 0x00,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x00,0x00,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17, + 0x17,0x17,0x00,0x00,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x00,0x00, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x17, + 0x17,0x17,0x17,0x3f,0x3f,0x1a,0x00,0x17,0x17,0x17,0x17,0x17,0x3f, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17, + 0x17,0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x00,0x17,0x17,0x17,0x3f,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00, + 0x17,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x17,0x3f,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12, + 0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kDisabledSkipForwardBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x1a,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x1a,0x19,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x19,0x1a,0x1a,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x18,0x1a,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1b,0x19,0x18,0x18,0x1a, + 0x1a,0xff,0xff,0xff,0xff,0xff,0x1a,0x19,0x18,0x19,0x1c,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1a,0x18, + 0x18,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x19,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c, + 0x1a,0x18,0x1a,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x19,0x18,0x1c,0xff,0xff,0xff,0x1a,0x18,0x1a,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1a,0x18,0x1a,0x1c,0xff,0xff,0x19,0x17,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x16,0x16,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x16,0x19,0x16,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c,0xff,0xff,0x19,0x16,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x16, + 0x16,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x16,0x16,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x17,0x1c,0xff,0xff,0x19,0x16, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19, + 0x19,0x19,0x16,0x16,0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x16,0x16, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x16,0x1c,0xff,0xff,0x19, + 0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x19, + 0x19,0x19,0x19,0x1c,0x1c,0x1b,0x16,0x19,0x19,0x19,0x19,0x19,0x1c, + 0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff,0xff, + 0x19,0x16,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19, + 0x19,0x19,0x1c,0x1c,0x1b,0x1b,0x1b,0x16,0x19,0x19,0x19,0x1c,0x1c, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1c,0xff, + 0xff,0x19,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x16, + 0x19,0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x16,0x19,0x1c,0x1c,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x19,0x1c, + 0xff,0xff,0x1a,0x18,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1c,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1c,0x1c,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x17,0x1a, + 0x1c,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1c,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x18, + 0x1c,0x1c,0xff,0xff,0xff,0x1a,0x19,0x18,0x1a,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x19,0x17, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x18,0x19,0x1a,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, + 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x18,0x17, + 0x1a,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1a,0x18,0x18, + 0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, + 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x18,0x17,0x18, + 0x1b,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1c,0x1c, + 0x1a,0x19,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x19,0x1a, + 0x1c,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1d, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kPressedSkipForwardBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff,0xff,0x13,0x10,0x0d, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x00,0x00, + 0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x00,0x00,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x10, + 0x10,0x00,0x00,0x13,0x13,0x13,0x00,0x10,0x10,0x10,0x00,0x00,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x10, + 0x10,0x10,0x10,0x10,0x00,0x00,0x13,0x00,0x10,0x10,0x10,0x10,0x10, + 0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x10,0x10,0x10,0x10,0x10,0x19,0x19,0x13,0x00,0x10,0x10,0x10,0x10, + 0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x10,0x10,0x10,0x19,0x19,0x13,0x13,0x13,0x00,0x10,0x10,0x10, + 0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x00,0x10,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x10,0x19, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kSkippingSkipForwardBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x16,0x1d,0x1e, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1c,0x19,0x16,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x17,0x1c,0x1e,0x1e, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x14,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x17,0x1e,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18, + 0x14,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x12,0x1d,0x1e,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x16,0x12,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x18,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x19,0x14,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x1d,0x1d, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x00,0x00,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x00,0x34,0x00,0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x15,0x12,0x13,0xff,0xff,0xff,0x13,0x10,0x1e, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x00, + 0x00,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x00,0x00,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x3f,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34, + 0x34,0x34,0x00,0x00,0x1a,0x00,0x34,0x34,0x34,0x34,0x34,0x00,0x00, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x1d,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x34, + 0x34,0x34,0x34,0x3f,0x3f,0x1a,0x00,0x34,0x34,0x34,0x34,0x34,0x3f, + 0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x13,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34, + 0x34,0x34,0x3f,0x3f,0x1a,0x1a,0x1a,0x00,0x34,0x34,0x34,0x3f,0x3f, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x18,0x12,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x15,0x18,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x00, + 0x34,0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x00,0x34,0x3f,0x3f,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x16,0x12,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x13,0x16,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x3f,0x3f,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x3f,0x3f,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x14,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x14,0x19,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x14,0x18,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x15,0x10,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x14,0x17,0x18, + 0x19,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, + 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x19,0x18,0x17,0x12,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x11,0x12, + 0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x16,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + + +const unsigned char kPressedSkippingSkipForwardBitmapBits [] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x18,0x18,0x17,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, + 0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x18,0x1a,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x15,0x14,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x18,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1a,0x14,0x11,0x11,0x0e,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x12,0x11,0x11,0x19, + 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x0d,0x0a,0x0f,0x10, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x0f,0x11, + 0x12,0x19,0xff,0xff,0xff,0xff,0x1a,0x16,0x10,0x0d,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x0f,0x11,0x16,0x1a,0xff,0xff,0xff,0x1a,0x11,0x0d,0x0a,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x0f,0x11,0x1a,0xff,0xff,0xff,0x17,0x11,0x0d,0x11,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x0f,0x11,0x15,0xff,0xff,0xff,0x14,0x11,0x0a,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x12,0x0f,0x13,0xff,0xff,0xff,0x13,0x10,0x0d, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x00,0x00, + 0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x00,0x00,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x1c,0xff,0xff,0x13,0x10, + 0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x34, + 0x34,0x00,0x00,0x13,0x13,0x13,0x00,0x34,0x34,0x34,0x00,0x00,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff,0x13, + 0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00,0x34, + 0x34,0x34,0x34,0x34,0x00,0x00,0x13,0x00,0x34,0x34,0x34,0x34,0x34, + 0x00,0x00,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff,0xff, + 0x13,0x10,0x0d,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x00, + 0x34,0x34,0x34,0x34,0x34,0x19,0x19,0x13,0x00,0x34,0x34,0x34,0x34, + 0x34,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x10,0x3f,0xff, + 0xff,0x15,0x10,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x00,0x34,0x34,0x34,0x19,0x19,0x13,0x13,0x13,0x00,0x34,0x34,0x34, + 0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x0f,0x16,0x1e, + 0xff,0xff,0x17,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x00,0x34,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x00,0x34,0x19, + 0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x12,0x10,0x1a, + 0x1e,0xff,0xff,0xff,0x13,0x11,0x11,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x19,0x19,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x19,0x19, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x16, + 0x1e,0x1c,0xff,0xff,0xff,0x18,0x11,0x12,0x10,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x0f,0x12, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0x18,0x11,0x11,0x11,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, + 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x11,0x10,0x12, + 0x19,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x12,0x10,0x11, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, + 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x10,0x16, + 0x1b,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19, + 0x14,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x14,0x17,0x1a, + 0x1d,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1d,0x1e,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, + 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x1e, + 0x1d,0x1c,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + diff --git a/modules/gui/beos/DrawingTidbits.cpp b/modules/gui/beos/DrawingTidbits.cpp new file mode 100644 index 0000000000..f62db43342 --- /dev/null +++ b/modules/gui/beos/DrawingTidbits.cpp @@ -0,0 +1,105 @@ +/***************************************************************************** + * DrawingTidbits.cpp + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: DrawingTidbits.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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 +#include +#include + +#include "DrawingTidbits.h" + +inline uchar +ShiftComponent(uchar component, float percent) +{ + // change the color by , make sure we aren't rounding + // off significant bits + if (percent >= 1) + return (uchar)(component * (2 - percent)); + else + return (uchar)(255 - percent * (255 - component)); +} + +rgb_color +ShiftColor(rgb_color color, float percent) +{ + rgb_color result = { + ShiftComponent(color.red, percent), + ShiftComponent(color.green, percent), + ShiftComponent(color.blue, percent), + 0 + }; + + return result; +} + +static bool +CompareColors(const rgb_color a, const rgb_color b) +{ + return a.red == b.red + && a.green == b.green + && a.blue == b.blue + && a.alpha == b.alpha; +} + +bool +operator==(const rgb_color &a, const rgb_color &b) +{ + return CompareColors(a, b); +} + +bool +operator!=(const rgb_color &a, const rgb_color &b) +{ + return !CompareColors(a, b); +} + +void +ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to) +{ + ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet + + BScreen screen(B_MAIN_SCREEN_ID); + uint32 fromIndex = screen.IndexForColor(from); + uint32 toIndex = screen.IndexForColor(to); + + uchar *bits = (uchar *)bitmap->Bits(); + int32 bitsLength = bitmap->BitsLength(); + for (int32 index = 0; index < bitsLength; index++) + if (bits[index] == fromIndex) + bits[index] = toIndex; +} + +void +ReplaceTransparentColor(BBitmap *bitmap, rgb_color with) +{ + ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet + + BScreen screen(B_MAIN_SCREEN_ID); + uint32 withIndex = screen.IndexForColor(with); + + uchar *bits = (uchar *)bitmap->Bits(); + int32 bitsLength = bitmap->BitsLength(); + for (int32 index = 0; index < bitsLength; index++) + if (bits[index] == B_TRANSPARENT_8_BIT) + bits[index] = withIndex; +} + diff --git a/modules/gui/beos/DrawingTidbits.h b/modules/gui/beos/DrawingTidbits.h new file mode 100644 index 0000000000..716fead679 --- /dev/null +++ b/modules/gui/beos/DrawingTidbits.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * DrawingTidbits.h + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: DrawingTidbits.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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. + *****************************************************************************/ + +#ifndef __DRAWING_TIBITS__ +#define __DRAWING_TIBITS__ + +#include + +rgb_color ShiftColor(rgb_color , float ); + +bool operator==(const rgb_color &, const rgb_color &); +bool operator!=(const rgb_color &, const rgb_color &); + +inline rgb_color +Color(int32 r, int32 g, int32 b, int32 alpha = 255) +{ + rgb_color result; + result.red = r; + result.green = g; + result.blue = b; + result.alpha = alpha; + + return result; +} + +const rgb_color kWhite = { 255, 255, 255, 255}; +const rgb_color kBlack = { 0, 0, 0, 255}; + +const float kDarkness = 1.06; +const float kDimLevel = 0.6; + +void ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to); +void ReplaceTransparentColor(BBitmap *bitmap, rgb_color with); + +#endif diff --git a/modules/gui/beos/Interface.cpp b/modules/gui/beos/Interface.cpp new file mode 100644 index 0000000000..9330575da1 --- /dev/null +++ b/modules/gui/beos/Interface.cpp @@ -0,0 +1,143 @@ +/***************************************************************************** + * intf.cpp: beos interface + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: Interface.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * Tony Castley + * Richard Shepherd + * + * 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 +#include /* malloc(), free() */ +#include +#include + +#include +#include + +#include "VlcWrapper.h" +#include "InterfaceWindow.h" + +/***************************************************************************** + * Local prototype + *****************************************************************************/ +static void Run ( intf_thread_t *p_intf ); + +/***************************************************************************** + * OpenIntf: initialize interface + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + BScreen *screen; + screen = new BScreen(); + BRect rect = screen->Frame(); + rect.top = rect.bottom-100; + rect.bottom -= 50; + rect.left += 50; + rect.right = rect.left + 350; + delete screen; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = (intf_sys_t*) malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } +// p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + p_intf->p_sys->p_input = NULL; + + p_intf->pf_run = Run; + + /* Create the interface window */ + p_intf->p_sys->p_window = + new InterfaceWindow( rect, + VOUT_TITLE " (BeOS interface)", p_intf ); + if( p_intf->p_sys->p_window == 0 ) + { + free( p_intf->p_sys ); + msg_Err( p_intf, "cannot allocate InterfaceWindow" ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * CloseIntf: destroy interface + *****************************************************************************/ +void E_(CloseIntf) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + +// msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + /* Destroy the interface window */ + p_intf->p_sys->p_window->Lock(); + p_intf->p_sys->p_window->Quit(); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + + +/***************************************************************************** + * Run: event loop + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + while( !p_intf->b_die ) + { + /* Update the input */ + if( p_intf->p_sys->p_input != NULL ) + { + if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + /* Manage the slider */ + p_intf->p_sys->p_window->updateInterface(); + } + + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = + (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + + + + /* Wait a bit */ + msleep( INTF_IDLE_SLEEP ); + } + +} + diff --git a/modules/gui/beos/InterfaceWindow.cpp b/modules/gui/beos/InterfaceWindow.cpp new file mode 100644 index 0000000000..8b92974efb --- /dev/null +++ b/modules/gui/beos/InterfaceWindow.cpp @@ -0,0 +1,591 @@ +/***************************************************************************** + * InterfaceWindow.cpp: beos interface + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: InterfaceWindow.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * Tony Castley + * Richard Shepherd + * + * 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. + *****************************************************************************/ + +/* System headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* VLC headers */ +#include +#include +#include + +/* BeOS interface headers */ +#include "MsgVals.h" +#include "MediaControlView.h" +#include "PlayListWindow.h" +#include "VlcWrapper.h" +#include "InterfaceWindow.h" + + +/***************************************************************************** + * InterfaceWindow + *****************************************************************************/ + +InterfaceWindow::InterfaceWindow( BRect frame, const char *name, + intf_thread_t *p_interface ) + : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK + | B_ASYNCHRONOUS_CONTROLS ) +{ + file_panel = NULL; + playlist_window = NULL; + p_intf = p_interface; + p_vlc_wrapper = Intf_VLCWrapper::getVLCWrapper(p_intf); + BRect controlRect(0,0,0,0); + + playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + b_empty_playlist = (p_playlist->i_size < 0); + b_mute = false; + + /* set the title bar */ + SetName( "interface" ); + SetTitle(VOUT_TITLE); + + /* set up the main menu */ + BMenuBar *menu_bar; + menu_bar = new BMenuBar(controlRect, "main menu"); + AddChild( menu_bar ); + + BMenu *mFile; + BMenu *mAudio; + CDMenu *cd_menu; + BMenu *mNavigation; + + /* Add the file Menu */ + BMenuItem *mItem; + menu_bar->AddItem( mFile = new BMenu( "File" ) ); + menu_bar->ResizeToPreferred(); + mFile->AddItem( mItem = new BMenuItem( "Open File" B_UTF8_ELLIPSIS, + new BMessage(OPEN_FILE), 'O') ); + + cd_menu = new CDMenu( "Open Disc" ); + mFile->AddItem( cd_menu ); + + mFile->AddSeparatorItem(); + mFile->AddItem( mItem = new BMenuItem( "Play List" B_UTF8_ELLIPSIS, + new BMessage(OPEN_PLAYLIST), 'P') ); + + mFile->AddSeparatorItem(); + mFile->AddItem( mItem = new BMenuItem( "About" B_UTF8_ELLIPSIS, + new BMessage(B_ABOUT_REQUESTED), 'A') ); + mItem->SetTarget( be_app ); + mFile->AddItem(mItem = new BMenuItem( "Quit", + new BMessage(B_QUIT_REQUESTED), 'Q') ); + + /* Add the Audio menu */ + menu_bar->AddItem ( mAudio = new BMenu( "Audio" ) ); + menu_bar->ResizeToPreferred(); + mAudio->AddItem( new LanguageMenu( "Language", AUDIO_ES, p_intf ) ); + mAudio->AddItem( new LanguageMenu( "Subtitles", SPU_ES, p_intf ) ); + + /* Add the Navigation menu */ + menu_bar->AddItem( mNavigation = new BMenu( "Navigation" ) ); + menu_bar->ResizeToPreferred(); + mNavigation->AddItem( new BMenuItem( "Prev Title", + new BMessage(PREV_TITLE)) ); + mNavigation->AddItem( new BMenuItem( "Next Title", + new BMessage(NEXT_TITLE)) ); + mNavigation->AddItem( new BMenuItem( "Prev Chapter", + new BMessage(PREV_CHAPTER)) ); + mNavigation->AddItem( new BMenuItem( "Next Chapter", + new BMessage(NEXT_CHAPTER)) ); + + ResizeTo(260,50 + menu_bar->Bounds().IntegerHeight()+1); + controlRect = Bounds(); + controlRect.top += menu_bar->Bounds().IntegerHeight() + 1; + + p_mediaControl = new MediaControlView( controlRect ); + p_mediaControl->SetViewColor( ui_color(B_PANEL_BACKGROUND_COLOR) ); + b_empty_playlist = true; + p_mediaControl->SetEnabled( !b_empty_playlist ); + + /* Show */ + AddChild( p_mediaControl ); + Show(); + +} + +InterfaceWindow::~InterfaceWindow() +{ + if (playlist_window) playlist_window->ReallyQuit(); +} + +/***************************************************************************** + * InterfaceWindow::MessageReceived + *****************************************************************************/ +void InterfaceWindow::MessageReceived( BMessage * p_message ) +{ + int vol_val = p_mediaControl->GetVolume(); // remember the current volume + int playback_status; // remember playback state + int i_index; + BAlert *alert; + + Activate(); + playback_status = p_vlc_wrapper->inputGetStatus(); + + switch( p_message->what ) + { + case B_ABOUT_REQUESTED: + alert = new BAlert(VOUT_TITLE, "BeOS " VOUT_TITLE "\n\n", "Ok"); + alert->Go(); + break; + + case TOGGLE_ON_TOP: + break; + + case OPEN_FILE: + if( file_panel ) + { + file_panel->Show(); + break; + } + file_panel = new BFilePanel(); + file_panel->SetTarget( this ); + file_panel->Show(); + b_empty_playlist = false; + p_mediaControl->SetEnabled( !b_empty_playlist ); + break; + + case OPEN_PLAYLIST: + { + BRect rect(20,20,320,420); + playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_window = PlayListWindow::getPlayList(rect, + "Playlist", p_playlist); + playlist_window->Show(); + } + break; + case OPEN_DVD: + { + const char *psz_device; + BString type("dvd"); + if( p_message->FindString("device", &psz_device) != B_ERROR ) + { + BString device(psz_device); + p_vlc_wrapper->openDisc(type, device, 0,0); + } + } + break; + + case STOP_PLAYBACK: + // this currently stops playback not nicely + //p_vlc_wrapper->volume_mute(); + //snooze( 400000 ); + p_vlc_wrapper->playlistStop(); + p_mediaControl->SetStatus(NOT_STARTED_S,DEFAULT_RATE); + break; + + case START_PLAYBACK: + /* starts playing in normal mode */ + + case PAUSE_PLAYBACK: + /* toggle between pause and play */ + if( p_intf->p_sys->p_input != NULL ) + { + /* pause if currently playing */ + if ( playback_status == PLAYING_S ) + { + //p_vlc_wrapper->volume_mute(); + //snooze( 400000 ); + p_vlc_wrapper->playlistPause(); + } + else + { + //p_vlc_wrapper->volume_restore(); + p_vlc_wrapper->playlistPlay(); + } + } + else + { + /* Play a new file */ + p_vlc_wrapper->playlistPlay(); + } + break; + + case FASTER_PLAY: + /* cycle the fast playback modes */ + //p_vlc_wrapper->volume_mute(); + //snooze( 400000 ); + p_vlc_wrapper->playFaster(); + break; + + case SLOWER_PLAY: + /* cycle the slow playback modes */ + //p_vlc_wrapper->volume_mute(); + //snooze( 400000 ); + p_vlc_wrapper->playSlower(); + break; + + case SEEK_PLAYBACK: + /* handled by semaphores */ + break; + + case VOLUME_CHG: + /* adjust the volume */ +// vlc_mutex_lock( &p_intf->p_sys->p_input->lock ); +// for( i_index = 0 ; i_index < p_aout_bank->i_count ; i_index++ ) +// { +// if( p_aout_bank->pp_aout[i_index]->i_savedvolume ) +// { +// p_aout_bank->pp_aout[i_index]->i_savedvolume = vol_val; +// } +// else +// { +// p_aout_bank->pp_aout[i_index]->i_volume = vol_val; +// } +// } +// vlc_mutex_unlock( &p_aout_bank->lock ); + break; + + case VOLUME_MUTE: + /* toggle muting */ + p_vlc_wrapper->toggleMute( ); + break; + + case SELECT_AUDIO: + { + int32 i = p_message->FindInt32( "audio" ); + p_vlc_wrapper->toggleLanguage( i ); + } + break; + + case SELECT_SUBTITLE: + { + int32 i = p_message->FindInt32( "subtitle" ); + p_vlc_wrapper->toggleSubtitle( i ); + } + break; + case PREV_TITLE: + { + int i_id; + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1; + + /* Disallow area 0 since it is used for video_ts.vob */ + if( i_id > 0 ) + { + p_vlc_wrapper->toggleTitle(i_id); + } + break; + } + case NEXT_TITLE: + { + int i_id; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1; + + if( i_id < p_intf->p_sys->p_input->stream.i_area_nb ) + { + p_vlc_wrapper->toggleTitle(i_id); + } + } + break; + case PREV_CHAPTER: + { + int i_id; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_part - 1; + + if( i_id >= 0 ) + { + p_vlc_wrapper->toggleChapter(i_id); + } + } + break; + case NEXT_CHAPTER: + { + int i_id; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_part + 1; + + if( i_id >= 0 ) + { + p_vlc_wrapper->toggleChapter(i_id); + } + } + break; + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + { + entry_ref ref; + BList* files = new BList(); + + int i = 0; + while( p_message->FindRef( "refs", i, &ref ) == B_OK ) + { + BPath path( &ref ); + + files->AddItem(new BString((char*)path.Path()) ); + i++; + } + p_vlc_wrapper->openFiles(files); + delete files; + } + break; + + default: + BWindow::MessageReceived( p_message ); + break; + } + +} + +/***************************************************************************** + * InterfaceWindow::updateInterface + *****************************************************************************/ +void InterfaceWindow::updateInterface() +{ + + if ( p_intf->p_sys->p_input != NULL ) + { + if ( acquire_sem(p_mediaControl->fScrubSem) == B_OK ) + { + p_vlc_wrapper->setTimeAsFloat(p_mediaControl->GetSeekTo()); + } + else if( Lock() ) + { + p_mediaControl->SetStatus(p_intf->p_sys->p_input->stream.control.i_status, + p_intf->p_sys->p_input->stream.control.i_rate); + p_mediaControl->SetProgress(p_intf->p_sys->p_input->stream.p_selected_area->i_tell, + p_intf->p_sys->p_input->stream.p_selected_area->i_size); + Unlock(); + } + } + + playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if ( b_empty_playlist != (p_playlist->i_size < 1) ) + { + if (Lock()) + { + b_empty_playlist = !b_empty_playlist; + p_mediaControl->SetEnabled( !b_empty_playlist ); + Unlock(); + } + } +} + +/***************************************************************************** + * InterfaceWindow::QuitRequested + *****************************************************************************/ +bool InterfaceWindow::QuitRequested() +{ + p_intf->p_vlc->b_die = VLC_TRUE; + + return( true ); +} + +/***************************************************************************** + * CDMenu::CDMenu + *****************************************************************************/ +CDMenu::CDMenu(const char *name) + : BMenu(name) +{ +} + +/***************************************************************************** + * CDMenu::~CDMenu + *****************************************************************************/ +CDMenu::~CDMenu() +{ +} + +/***************************************************************************** + * CDMenu::AttachedToWindow + *****************************************************************************/ +void CDMenu::AttachedToWindow(void) +{ + while (RemoveItem((long int)0) != NULL); // remove all items + GetCD("/dev/disk"); + BMenu::AttachedToWindow(); +} + +/***************************************************************************** + * CDMenu::GetCD + *****************************************************************************/ +int CDMenu::GetCD( const char *directory ) +{ + BVolumeRoster *volRoster; + BVolume *vol; + BDirectory *dir; + int status; + int mounted; + char name[B_FILE_NAME_LENGTH]; + fs_info info; + dev_t dev; + + volRoster = new BVolumeRoster(); + vol = new BVolume(); + dir = new BDirectory(); + status = volRoster->GetNextVolume(vol); + status = vol->GetRootDirectory(dir); + while (status == B_NO_ERROR) + { + mounted = vol->GetName(name); + if ((mounted == B_OK) && /* Disk is currently Mounted */ + (vol->IsReadOnly()) ) /* Disk is read-only */ + { + dev = vol->Device(); + fs_stat_dev(dev, &info); + + device_geometry g; + int i_dev; + i_dev = open( info.device_name, O_RDONLY ); + + if( i_dev >= 0 ) + { + if( ioctl(i_dev, B_GET_GEOMETRY, &g, sizeof(g)) >= 0 ) + { + if( g.device_type == B_CD ) //ensure the drive is a CD-ROM + { + BMessage *msg; + msg = new BMessage( OPEN_DVD ); + msg->AddString( "device", info.device_name ); + BMenuItem *menu_item; + menu_item = new BMenuItem( name, msg ); + AddItem( menu_item ); + } + close(i_dev); + } + } + } + vol->Unset(); + status = volRoster->GetNextVolume(vol); + } +} + +/***************************************************************************** + * LanguageMenu::LanguageMenu + *****************************************************************************/ +LanguageMenu::LanguageMenu(const char *name, int menu_kind, + intf_thread_t *p_interface) + :BMenu(name) +{ + kind = menu_kind; + p_intf = p_interface; +} + +/***************************************************************************** + * LanguageMenu::~LanguageMenu + *****************************************************************************/ +LanguageMenu::~LanguageMenu() +{ +} + +/***************************************************************************** + * LanguageMenu::AttachedToWindow + *****************************************************************************/ +void LanguageMenu::AttachedToWindow(void) +{ + while( RemoveItem((long int)0) != NULL ) + { + ; // remove all items + } + + SetRadioMode(true); + GetChannels(); + BMenu::AttachedToWindow(); +} + +/***************************************************************************** + * LanguageMenu::GetChannels + *****************************************************************************/ +int LanguageMenu::GetChannels() +{ + char *psz_name; + bool b_active; + BMessage *msg; + int i; + es_descriptor_t *p_es = NULL; + + /* Insert the null */ + if( kind == SPU_ES ) //audio + { + msg = new BMessage(SELECT_SUBTITLE); + msg->AddInt32("subtitle", -1); + BMenuItem *menu_item; + menu_item = new BMenuItem("None", msg); + AddItem(menu_item); + menu_item->SetMarked(TRUE); + + } + + if( p_intf->p_sys->p_input == NULL ) + { + return 1; + } + + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + for( i = 0; i < p_intf->p_sys->p_input->stream.i_selected_es_number; i++ ) + { + if( kind == p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat ) + { + p_es = p_intf->p_sys->p_input->stream.pp_selected_es[i]; + } + } + + for( i = 0; i < p_intf->p_sys->p_input->stream.i_es_number; i++ ) + { + if( kind == p_intf->p_sys->p_input->stream.pp_es[i]->i_cat ) + { + psz_name = p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc; + if( kind == AUDIO_ES ) //audio + { + msg = new BMessage(SELECT_AUDIO); + msg->AddInt32("audio", i); + } + else + { + msg = new BMessage(SELECT_SUBTITLE); + msg->AddInt32("subtitle", i); + } + BMenuItem *menu_item; + menu_item = new BMenuItem(psz_name, msg); + AddItem(menu_item); + b_active = (p_es == p_intf->p_sys->p_input->stream.pp_es[i]); + menu_item->SetMarked(b_active); + } + } + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + +} + + + diff --git a/modules/gui/beos/InterfaceWindow.h b/modules/gui/beos/InterfaceWindow.h new file mode 100644 index 0000000000..5f993df908 --- /dev/null +++ b/modules/gui/beos/InterfaceWindow.h @@ -0,0 +1,77 @@ +/***************************************************************************** + * InterfaceWindow.h: BeOS interface window class prototype + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: InterfaceWindow.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Tony Castley + * Richard Shepherd + * + * 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. + *****************************************************************************/ +/***************************************************************************** + * intf_sys_t: description and status of FB interface + *****************************************************************************/ +class MediaControlView; +class PlayListWindow; + +class CDMenu : public BMenu +{ +public: + CDMenu(const char *name); + ~CDMenu(); + void AttachedToWindow(void); +private: + int GetCD(const char *directory); +}; + +class LanguageMenu : public BMenu +{ +public: + LanguageMenu(const char *name, int menu_kind, + intf_thread_t *p_interface); + ~LanguageMenu(); + void AttachedToWindow(void); +private: + intf_thread_t *p_intf; + int kind; + int GetChannels(); +}; + +class InterfaceWindow : public BWindow +{ +public: + InterfaceWindow( BRect frame, const char *name, + intf_thread_t *p_interface ); + ~InterfaceWindow(); + + // standard window member + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *message); + void updateInterface(); + + MediaControlView *p_mediaControl; + +private: + intf_thread_t *p_intf; + bool b_empty_playlist; + bool b_mute; + BFilePanel *file_panel; + PlayListWindow* playlist_window; + BMenuItem *miOnTop; + Intf_VLCWrapper * p_vlc_wrapper; +}; + diff --git a/modules/gui/beos/Makefile b/modules/gui/beos/Makefile new file mode 100644 index 0000000000..404565800b --- /dev/null +++ b/modules/gui/beos/Makefile @@ -0,0 +1 @@ +beos_SOURCES = BeOS.cpp AudioOutput.cpp VideoOutput.cpp Interface.cpp InterfaceWindow.cpp DrawingTidbits.cpp TransportButton.cpp PlayListWindow.cpp MediaControlView.cpp VlcWrapper.cpp diff --git a/modules/gui/beos/MediaControlView.cpp b/modules/gui/beos/MediaControlView.cpp new file mode 100644 index 0000000000..4132a9f194 --- /dev/null +++ b/modules/gui/beos/MediaControlView.cpp @@ -0,0 +1,287 @@ +/***************************************************************************** + * MediaControlView.cpp: beos interface + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: MediaControlView.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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. + *****************************************************************************/ + +/* System headers */ +#include +#include +#include + +/* VLC headers */ +#include +#include + +/* BeOS interface headers */ +#include "MsgVals.h" +#include "Bitmaps.h" +#include "TransportButton.h" +#include "MediaControlView.h" + + +MediaControlView::MediaControlView( BRect frame ) + : BBox( frame, NULL, B_FOLLOW_ALL, B_WILL_DRAW, B_PLAIN_BORDER ) +{ + float xStart = HORZ_SPACE; + float yStart = VERT_SPACE; + fScrubSem = B_ERROR; + + BRect controlRect = BRect(xStart,yStart, + frame.Width() - (HORZ_SPACE * 2), 15); + + /* Seek Status */ + rgb_color fill_color = {0,255,0}; + p_seek = new SeekSlider(controlRect, this, 0, 100, B_TRIANGLE_THUMB); + p_seek->SetValue(0); + p_seek->UseFillColor(true, &fill_color); + AddChild( p_seek ); + yStart += 15 + VERT_SPACE; + + + /* Buttons */ + /* Slow play */ + controlRect.SetLeftTop(BPoint(xStart, yStart)); + controlRect.SetRightBottom(controlRect.LeftTop() + kSkipButtonSize); + xStart += kRewindBitmapWidth; + p_slow = new TransportButton(controlRect, B_EMPTY_STRING, + kSkipBackBitmapBits, + kPressedSkipBackBitmapBits, + kDisabledSkipBackBitmapBits, + new BMessage(SLOWER_PLAY)); + AddChild( p_slow ); + + /* Play Pause */ + controlRect.SetLeftTop(BPoint(xStart, yStart)); + controlRect.SetRightBottom(controlRect.LeftTop() + kPlayButtonSize); + xStart += kPlayPauseBitmapWidth + 1.0; + p_play = new PlayPauseButton(controlRect, B_EMPTY_STRING, + kPlayButtonBitmapBits, + kPressedPlayButtonBitmapBits, + kDisabledPlayButtonBitmapBits, + kPlayingPlayButtonBitmapBits, + kPressedPlayingPlayButtonBitmapBits, + kPausedPlayButtonBitmapBits, + kPressedPausedPlayButtonBitmapBits, + new BMessage(START_PLAYBACK)); + + AddChild( p_play ); + + /* Fast Foward */ + controlRect.SetLeftTop(BPoint(xStart, yStart)); + controlRect.SetRightBottom(controlRect.LeftTop() + kSkipButtonSize); + xStart += kRewindBitmapWidth; + p_fast = new TransportButton(controlRect, B_EMPTY_STRING, + kSkipForwardBitmapBits, + kPressedSkipForwardBitmapBits, + kDisabledSkipForwardBitmapBits, + new BMessage(FASTER_PLAY)); + AddChild( p_fast ); + + /* Stop */ + controlRect.SetLeftTop(BPoint(xStart, yStart)); + controlRect.SetRightBottom(controlRect.LeftTop() + kStopButtonSize); + xStart += kStopBitmapWidth; + p_stop = new TransportButton(controlRect, B_EMPTY_STRING, + kStopButtonBitmapBits, + kPressedStopButtonBitmapBits, + kDisabledStopButtonBitmapBits, + new BMessage(STOP_PLAYBACK)); + AddChild( p_stop ); + + controlRect.SetLeftTop(BPoint(xStart + 5, yStart + 6)); + controlRect.SetRightBottom(controlRect.LeftTop() + kSpeakerButtonSize); + xStart += kSpeakerIconBitmapWidth; + + p_mute = new TransportButton(controlRect, B_EMPTY_STRING, + kSpeakerIconBits, + kPressedSpeakerIconBits, + kSpeakerIconBits, + new BMessage(VOLUME_MUTE)); + + AddChild( p_mute ); + + /* Volume Slider */ + p_vol = new MediaSlider(BRect(xStart,20,255,30), new BMessage(VOLUME_CHG), + 0, VOLUME_MAX); + p_vol->SetValue(VOLUME_DEFAULT); + p_vol->UseFillColor(true, &fill_color); + AddChild( p_vol ); + +} + +MediaControlView::~MediaControlView() +{ +} + +void MediaControlView::MessageReceived(BMessage *message) +{ +} + +void MediaControlView::SetProgress(uint64 seek, uint64 size) +{ + p_seek->SetPosition((float)seek/size); +} + +void MediaControlView::SetStatus(int status, int rate) +{ + switch( status ) + { + case PLAYING_S: + case FORWARD_S: + case BACKWARD_S: + case START_S: + p_play->SetPlaying(); + break; + case PAUSE_S: + p_play->SetPaused(); + break; + case UNDEF_S: + case NOT_STARTED_S: + default: + p_play->SetStopped(); + break; + } + if ( rate < DEFAULT_RATE ) + { + } +} + +void MediaControlView::SetEnabled(bool enabled) +{ + p_slow->SetEnabled(enabled); + p_play->SetEnabled(enabled); + p_fast->SetEnabled(enabled); + p_stop->SetEnabled(enabled); + p_mute->SetEnabled(enabled); + p_vol->SetEnabled(enabled); + p_seek->SetEnabled(enabled); +} + +uint32 MediaControlView::GetSeekTo() +{ + return p_seek->seekTo; +} + +uint32 MediaControlView::GetVolume() +{ + return p_vol->Value(); +} + + +/***************************************************************************** + * MediaSlider + *****************************************************************************/ +MediaSlider::MediaSlider( BRect frame, BMessage *p_message, + int32 i_min, int32 i_max ) + :BSlider(frame, NULL, NULL, p_message, i_min, i_max ) +{ + +} + +MediaSlider::~MediaSlider() +{ + +} + +void MediaSlider::DrawThumb(void) +{ + BRect r; + BView *v; + + rgb_color black = {0,0,0}; + r = ThumbFrame(); + v = OffscreenView(); + + if(IsEnabled()) + { + v->SetHighColor(black); + } + else + { + v->SetHighColor(tint_color(black, B_LIGHTEN_2_TINT)); + } + + r.InsetBy(r.IntegerWidth()/4, r.IntegerHeight()/(4 * r.IntegerWidth() / r.IntegerHeight())); + v->StrokeEllipse(r); + + if(IsEnabled()) + { + v->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + } + else + { + v->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT)); + } + + r.InsetBy(1,1); + v->FillEllipse(r); +} + +/***************************************************************************** + * SeekSlider + *****************************************************************************/ +SeekSlider::SeekSlider( BRect frame, MediaControlView *p_owner, int32 i_min, + int32 i_max, thumb_style thumbType = B_TRIANGLE_THUMB ) + :MediaSlider( frame, NULL, i_min, i_max ) +{ + fOwner = p_owner; + fMouseDown = false; +} + +SeekSlider::~SeekSlider() +{ +} + +/***************************************************************************** + * SeekSlider::MouseDown + *****************************************************************************/ +void SeekSlider::MouseDown(BPoint where) +{ + BSlider::MouseDown(where); + seekTo = ValueForPoint(where); + fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem"); + release_sem(fOwner->fScrubSem); + fMouseDown = true; +} + +/***************************************************************************** + * SeekSlider::MouseUp + *****************************************************************************/ +void SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage *message) +{ + BSlider::MouseMoved(where, code, message); + if (!fMouseDown) + return; + seekTo = ValueForPoint(where); + release_sem(fOwner->fScrubSem); +} + +/***************************************************************************** + * SeekSlider::MouseUp + *****************************************************************************/ +void SeekSlider::MouseUp(BPoint where) +{ + BSlider::MouseUp(where); + seekTo = ValueForPoint(where); + delete_sem(fOwner->fScrubSem); + fOwner->fScrubSem = B_ERROR; + fMouseDown = false; +} diff --git a/modules/gui/beos/MediaControlView.h b/modules/gui/beos/MediaControlView.h new file mode 100644 index 0000000000..7bb53ed0fd --- /dev/null +++ b/modules/gui/beos/MediaControlView.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * MediaControlView.h: beos interface + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: MediaControlView.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ +#define HORZ_SPACE 5.0 +#define VERT_SPACE 5.0 + + +class TransportButton; +class PlayPauseButton; +class MediaSlider; +class SeekSlider; + +class MediaControlView : public BBox +{ +public: + MediaControlView( BRect frame ); + ~MediaControlView(); + + virtual void MessageReceived(BMessage *message); + void SetProgress(uint64 seek, uint64 size); + + void SetStatus(int status, int rate); + void SetEnabled(bool); + uint32 GetSeekTo(); + uint32 GetVolume(); + sem_id fScrubSem; + bool fSeeking; + +private: + MediaSlider * p_vol; + SeekSlider * p_seek; + TransportButton* p_slow; + PlayPauseButton* p_play; + TransportButton* p_fast; + TransportButton* p_stop; + TransportButton* p_mute; + + int current_rate; + int current_status; +}; + +class MediaSlider : public BSlider +{ +public: + MediaSlider(BRect frame, + BMessage *message, + int32 minValue, + int32 maxValue); + ~MediaSlider(); + virtual void DrawThumb(void); +}; + + +class SeekSlider : public MediaSlider +{ +public: + SeekSlider(BRect frame, + MediaControlView *owner, + int32 minValue, + int32 maxValue, + thumb_style thumbType = B_TRIANGLE_THUMB); + + ~SeekSlider(); + uint32 seekTo; + virtual void MouseDown(BPoint); + virtual void MouseUp(BPoint pt); + virtual void MouseMoved(BPoint pt, uint32 c, const BMessage *m); +private: + MediaControlView* fOwner; + bool fMouseDown; +}; + + diff --git a/modules/gui/beos/MsgVals.h b/modules/gui/beos/MsgVals.h new file mode 100644 index 0000000000..297e74a905 --- /dev/null +++ b/modules/gui/beos/MsgVals.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * MsgVals.h + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: MsgVals.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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. + *****************************************************************************/ + +/* MsgVals.h */ +#define PLAYING 0 +#define PAUSED 1 + +const uint32 OPEN_FILE = 'OPFL'; +const uint32 OPEN_DVD = 'OPDV'; +const uint32 OPEN_PLAYLIST = 'OPPL'; +const uint32 STOP_PLAYBACK = 'STPL'; +const uint32 START_PLAYBACK = 'PLAY'; +const uint32 PAUSE_PLAYBACK = 'PAPL'; +const uint32 FASTER_PLAY = 'FAPL'; +const uint32 SLOWER_PLAY = 'SLPL'; +const uint32 SEEK_PLAYBACK = 'SEEK'; +const uint32 VOLUME_CHG = 'VOCH'; +const uint32 VOLUME_MUTE = 'MUTE'; +const uint32 SELECT_AUDIO = 'AUDI'; +const uint32 SELECT_SUBTITLE = 'SUBT'; +const uint32 PREV_TITLE = 'PRTI'; +const uint32 NEXT_TITLE = 'NXTI'; +const uint32 PREV_CHAPTER = 'PRCH'; +const uint32 NEXT_CHAPTER = 'NXCH'; +const uint32 TOGGLE_ON_TOP = 'ONTP'; +const uint32 TOGGLE_FULL_SCREEN = 'TGFS'; +const uint32 RESIZE_100 = 'RSOR'; +const uint32 RESIZE_200 = 'RSDB'; +const uint32 ASPECT_CORRECT = 'ASCO'; +const uint32 VERT_SYNC = 'VSYN'; +const uint32 WINDOW_FEEL = 'WFEL'; + diff --git a/modules/gui/beos/PlayListWindow.cpp b/modules/gui/beos/PlayListWindow.cpp new file mode 100644 index 0000000000..02693c66e9 --- /dev/null +++ b/modules/gui/beos/PlayListWindow.cpp @@ -0,0 +1,170 @@ +/***************************************************************************** + * PlayListWindow.cpp: beos interface + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: PlayListWindow.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * Tony Castley + * Richard Shepherd + * + * 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. + *****************************************************************************/ + +/* System headers */ +#include +#include +#include +#include + +/* VLC headers */ +#include +#include + +/* BeOS interface headers */ +#include "VlcWrapper.h" +#include "InterfaceWindow.h" +#include "MsgVals.h" +#include "PlayListWindow.h" + +/***************************************************************************** + * PlayListWindow + *****************************************************************************/ +PlayListWindow *PlayListWindow::getPlayList( BRect frame, const char *name, + playlist_t *p_pl) +{ + static PlayListWindow *one_playlist; + if (one_playlist == NULL) + { + one_playlist = new PlayListWindow(frame, name, p_pl); + } + return one_playlist; +} + +PlayListWindow::PlayListWindow( BRect frame, const char *name, + playlist_t *p_pl) + : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS ) +{ + SetName( "playlist" ); + SetTitle(name); + p_playlist = p_pl; + + /* set up the main menu */ + BMenuBar *menu_bar; + menu_bar = new BMenuBar(BRect(0,0,0,0), "main menu"); + AddChild( menu_bar ); + + BMenu *mFile; + /* Add the file Menu */ + BMenuItem *mItem; + menu_bar->AddItem( mFile = new BMenu( "File" ) ); + menu_bar->ResizeToPreferred(); + mFile->AddItem( mItem = new BMenuItem( "Open File" B_UTF8_ELLIPSIS, + new BMessage(OPEN_FILE), 'O') ); + + CDMenu *cd_menu = new CDMenu( "Open Disc" ); + mFile->AddItem( cd_menu ); + + BRect rect = Bounds(); + rect.top += menu_bar->Bounds().IntegerHeight() + 1; + BView *p_view = new BView(rect, NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW); + + p_listview = new BListView(rect, "PlayList", + B_MULTIPLE_SELECTION_LIST); + for (int i=0; i < p_playlist->i_size; i++) + { + p_listview->AddItem(new BStringItem(p_playlist->pp_items[i]->psz_name)); + } + p_view->AddChild(new BScrollView("scroll_playlist", p_listview, + B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true)); + + AddChild(p_view); +} + +PlayListWindow::~PlayListWindow() +{ +} + +/***************************************************************************** + * PlayListWindow::MessageReceived + *****************************************************************************/ +void PlayListWindow::MessageReceived( BMessage * p_message ) +{ + Activate(); + + switch( p_message->what ) + { + case OPEN_FILE: + if( file_panel ) + { + file_panel->Show(); + break; + } + file_panel = new BFilePanel(); + file_panel->SetTarget( this ); + file_panel->Show(); + break; + + case OPEN_DVD: + { + const char *psz_device; + BString type("dvd"); + if( p_message->FindString("device", &psz_device) != B_ERROR ) + { + BString device(psz_device); +// p_vlc_wrapper->openDisc(type, device, 0,0); + p_listview->AddItem(new BStringItem(psz_device)); + } + } + break; + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + { + entry_ref ref; + BList* files = new BList(); + + int i = 0; + while( p_message->FindRef( "refs", i, &ref ) == B_OK ) + { + BPath path( &ref ); + + files->AddItem(new BString((char*)path.Path()) ); + p_listview->AddItem(new BStringItem((char*)path.Path())); + i++; + } +// p_vlc_wrapper->openFiles(files); + delete files; + } + break; + default: + BWindow::MessageReceived( p_message ); + break; + } +} + +bool PlayListWindow::QuitRequested() +{ + Hide(); + return false; +} + +void PlayListWindow::ReallyQuit() +{ + Hide(); + Lock(); + Quit(); +} diff --git a/modules/gui/beos/PlayListWindow.h b/modules/gui/beos/PlayListWindow.h new file mode 100644 index 0000000000..5b9dbad2bb --- /dev/null +++ b/modules/gui/beos/PlayListWindow.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * PlayListWindow.h: BeOS interface window class prototype + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: PlayListWindow.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Tony Castley + * Richard Shepherd + * + * 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. + *****************************************************************************/ +class CDMenu; +class PlayListWindow : public BWindow +{ +public: + static PlayListWindow *getPlayList(BRect frame, const char *name, + playlist_t *p_pl); + ~PlayListWindow(); + bool QuitRequested(); + void ReallyQuit(); + + // standard window member + virtual void MessageReceived(BMessage *message); + +private: + PlayListWindow( BRect frame, const char *name, playlist_t *p_pl); + playlist_t *p_playlist; + BListView *p_listview; + BFilePanel *file_panel; +}; + + diff --git a/modules/gui/beos/TransportButton.cpp b/modules/gui/beos/TransportButton.cpp new file mode 100644 index 0000000000..0a82bb470c --- /dev/null +++ b/modules/gui/beos/TransportButton.cpp @@ -0,0 +1,622 @@ +/***************************************************************************** + * TransportButton.cpp + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: TransportButton.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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 +#include +#include +#include +#include + +#include + +#include "TransportButton.h" +#include "DrawingTidbits.h" + +class BitmapStash { +// Bitmap stash is a simple class to hold all the lazily-allocated +// bitmaps that the TransportButton needs when rendering itself. +// signature is a combination of the different enabled, pressed, playing, etc. +// flavors of a bitmap. If the stash does not have a particular bitmap, +// it turns around to ask the button to create one and stores it for next time. +public: + BitmapStash(TransportButton *); + ~BitmapStash(); + BBitmap *GetBitmap(uint32 signature); + +private: + TransportButton *owner; + map stash; +}; + +BitmapStash::BitmapStash(TransportButton *owner) + : owner(owner) +{ +} + +BBitmap * +BitmapStash::GetBitmap(uint32 signature) +{ + if (stash.find(signature) == stash.end()) { + BBitmap *newBits = owner->MakeBitmap(signature); + ASSERT(newBits); + stash[signature] = newBits; + } + + return stash[signature]; +} + +BitmapStash::~BitmapStash() +{ + // delete all the bitmaps + for (map::iterator i = stash.begin(); i != stash.end(); i++) + delete (*i).second; +} + + +class PeriodicMessageSender { + // used to send a specified message repeatedly when holding down a button +public: + static PeriodicMessageSender *Launch(BMessenger target, + const BMessage *message, bigtime_t period); + void Quit(); + +private: + PeriodicMessageSender(BMessenger target, const BMessage *message, + bigtime_t period); + ~PeriodicMessageSender() {} + // use quit + + static status_t TrackBinder(void *); + void Run(); + + BMessenger target; + BMessage message; + + bigtime_t period; + + bool requestToQuit; +}; + + +PeriodicMessageSender::PeriodicMessageSender(BMessenger target, + const BMessage *message, bigtime_t period) + : target(target), + message(*message), + period(period), + requestToQuit(false) +{ +} + +PeriodicMessageSender * +PeriodicMessageSender::Launch(BMessenger target, const BMessage *message, + bigtime_t period) +{ + PeriodicMessageSender *result = new PeriodicMessageSender(target, message, period); + thread_id thread = spawn_thread(&PeriodicMessageSender::TrackBinder, + "ButtonRepeatingThread", B_NORMAL_PRIORITY, result); + + if (thread <= 0 || resume_thread(thread) != B_OK) { + // didn't start, don't leak self + delete result; + result = 0; + } + + return result; +} + +void +PeriodicMessageSender::Quit() +{ + requestToQuit = true; +} + +status_t +PeriodicMessageSender::TrackBinder(void *castToThis) +{ + ((PeriodicMessageSender *)castToThis)->Run(); + return 0; +} + +void +PeriodicMessageSender::Run() +{ + for (;;) { + snooze(period); + if (requestToQuit) + break; + target.SendMessage(&message); + } + delete this; +} + +class SkipButtonKeypressFilter : public BMessageFilter { +public: + SkipButtonKeypressFilter(uint32 shortcutKey, uint32 shortcutModifier, + TransportButton *target); + +protected: + filter_result Filter(BMessage *message, BHandler **handler); + +private: + uint32 shortcutKey; + uint32 shortcutModifier; + TransportButton *target; +}; + +SkipButtonKeypressFilter::SkipButtonKeypressFilter(uint32 shortcutKey, + uint32 shortcutModifier, TransportButton *target) + : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), + shortcutKey(shortcutKey), + shortcutModifier(shortcutModifier), + target(target) +{ +} + +filter_result +SkipButtonKeypressFilter::Filter(BMessage *message, BHandler **handler) +{ + if (target->IsEnabled() + && (message->what == B_KEY_DOWN || message->what == B_KEY_UP)) { + uint32 modifiers; + uint32 rawKeyChar = 0; + uint8 byte = 0; + int32 key = 0; + + if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK + || message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK + || message->FindInt8("byte", (int8 *)&byte) != B_OK + || message->FindInt32("key", &key) != B_OK) + return B_DISPATCH_MESSAGE; + + modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY + | B_OPTION_KEY | B_MENU_KEY; + // strip caps lock, etc. + + if (modifiers == shortcutModifier && rawKeyChar == shortcutKey) { + if (message->what == B_KEY_DOWN) + target->ShortcutKeyDown(); + else + target->ShortcutKeyUp(); + + return B_SKIP_MESSAGE; + } + } + + // let others deal with this + return B_DISPATCH_MESSAGE; +} + +TransportButton::TransportButton(BRect frame, const char *name, + const unsigned char *normalBits, + const unsigned char *pressedBits, + const unsigned char *disabledBits, + BMessage *invokeMessage, BMessage *startPressingMessage, + BMessage *pressingMessage, BMessage *donePressingMessage, bigtime_t period, + uint32 key, uint32 modifiers, uint32 resizeFlags) + : BControl(frame, name, "", invokeMessage, resizeFlags, B_WILL_DRAW | B_NAVIGABLE), + bitmaps(new BitmapStash(this)), + normalBits(normalBits), + pressedBits(pressedBits), + disabledBits(disabledBits), + startPressingMessage(startPressingMessage), + pressingMessage(pressingMessage), + donePressingMessage(donePressingMessage), + pressingPeriod(period), + mouseDown(false), + keyDown(false), + messageSender(0), + keyPressFilter(0) +{ + if (key) + keyPressFilter = new SkipButtonKeypressFilter(key, modifiers, this); +} + + +void +TransportButton::AttachedToWindow() +{ + _inherited::AttachedToWindow(); + if (keyPressFilter) + Window()->AddCommonFilter(keyPressFilter); + + // transparent to reduce flicker + SetViewColor(B_TRANSPARENT_COLOR); +} + +void +TransportButton::DetachedFromWindow() +{ + if (keyPressFilter) { + Window()->RemoveCommonFilter(keyPressFilter); + delete keyPressFilter; + } + _inherited::DetachedFromWindow(); +} + + +TransportButton::~TransportButton() +{ + delete startPressingMessage; + delete pressingMessage; + delete donePressingMessage; + delete bitmaps; +} + +void +TransportButton::WindowActivated(bool state) +{ + if (!state) + ShortcutKeyUp(); + + _inherited::WindowActivated(state); +} + +void +TransportButton::SetEnabled(bool on) +{ + _inherited::SetEnabled(on); + if (!on) + ShortcutKeyUp(); +} + +const unsigned char * +TransportButton::BitsForMask(uint32 mask) const +{ + switch (mask) { + case 0: + return normalBits; + case kDisabledMask: + return disabledBits; + case kPressedMask: + return pressedBits; + default: + break; + } + TRESPASS(); + return 0; +} + + +BBitmap * +TransportButton::MakeBitmap(uint32 mask) +{ + BBitmap *result = new BBitmap(Bounds(), B_COLOR_8_BIT); + result->SetBits(BitsForMask(mask), (Bounds().Width() + 1) * (Bounds().Height() + 1), + 0, B_COLOR_8_BIT); + + ReplaceTransparentColor(result, Parent()->ViewColor()); + + return result; +} + +uint32 +TransportButton::ModeMask() const +{ + return (IsEnabled() ? 0 : kDisabledMask) + | (Value() ? kPressedMask : 0); +} + +void +TransportButton::Draw(BRect) +{ + DrawBitmapAsync(bitmaps->GetBitmap(ModeMask())); +} + + +void +TransportButton::StartPressing() +{ + SetValue(1); + if (startPressingMessage) + Invoke(startPressingMessage); + + if (pressingMessage) { + ASSERT(pressingMessage); + messageSender = PeriodicMessageSender::Launch(Messenger(), + pressingMessage, pressingPeriod); + } +} + +void +TransportButton::MouseCancelPressing() +{ + if (!mouseDown || keyDown) + return; + + mouseDown = false; + + if (pressingMessage) { + ASSERT(messageSender); + PeriodicMessageSender *sender = messageSender; + messageSender = 0; + sender->Quit(); + } + + if (donePressingMessage) + Invoke(donePressingMessage); + SetValue(0); +} + +void +TransportButton::DonePressing() +{ + if (pressingMessage) { + ASSERT(messageSender); + PeriodicMessageSender *sender = messageSender; + messageSender = 0; + sender->Quit(); + } + + Invoke(); + SetValue(0); +} + +void +TransportButton::MouseStartPressing() +{ + if (mouseDown) + return; + + mouseDown = true; + if (!keyDown) + StartPressing(); +} + +void +TransportButton::MouseDonePressing() +{ + if (!mouseDown) + return; + + mouseDown = false; + if (!keyDown) + DonePressing(); +} + +void +TransportButton::ShortcutKeyDown() +{ + if (!IsEnabled()) + return; + + if (keyDown) + return; + + keyDown = true; + if (!mouseDown) + StartPressing(); +} + +void +TransportButton::ShortcutKeyUp() +{ + if (!keyDown) + return; + + keyDown = false; + if (!mouseDown) + DonePressing(); +} + + +void +TransportButton::MouseDown(BPoint) +{ + if (!IsEnabled()) + return; + + ASSERT(Window()->Flags() & B_ASYNCHRONOUS_CONTROLS); + SetTracking(true); + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + MouseStartPressing(); +} + +void +TransportButton::MouseMoved(BPoint point, uint32 code, const BMessage *) +{ + if (IsTracking() && Bounds().Contains(point) != Value()) { + if (!Value()) + MouseStartPressing(); + else + MouseCancelPressing(); + } +} + +void +TransportButton::MouseUp(BPoint point) +{ + if (IsTracking()) { + if (Bounds().Contains(point)) + MouseDonePressing(); + else + MouseCancelPressing(); + SetTracking(false); + } +} + +void +TransportButton::SetStartPressingMessage(BMessage *message) +{ + delete startPressingMessage; + startPressingMessage = message; +} + +void +TransportButton::SetPressingMessage(BMessage *message) +{ + delete pressingMessage; + pressingMessage = message; +} + +void +TransportButton::SetDonePressingMessage(BMessage *message) +{ + delete donePressingMessage; + donePressingMessage = message; +} + +void +TransportButton::SetPressingPeriod(bigtime_t newTime) +{ + pressingPeriod = newTime; +} + + +PlayPauseButton::PlayPauseButton(BRect frame, const char *name, + const unsigned char *normalBits, const unsigned char *pressedBits, + const unsigned char *disabledBits, const unsigned char *normalPlayingBits, + const unsigned char *pressedPlayingBits, const unsigned char *normalPausedBits, + const unsigned char *pressedPausedBits, + BMessage *invokeMessage, uint32 key, uint32 modifiers, uint32 resizeFlags) + : TransportButton(frame, name, normalBits, pressedBits, + disabledBits, invokeMessage, 0, + 0, 0, 0, key, modifiers, resizeFlags), + normalPlayingBits(normalPlayingBits), + pressedPlayingBits(pressedPlayingBits), + normalPausedBits(normalPausedBits), + pressedPausedBits(pressedPausedBits), + state(PlayPauseButton::kStopped), + lastPauseBlinkTime(0), + lastModeMask(0) +{ +} + +void +PlayPauseButton::SetStopped() +{ + if (state == kStopped || state == kAboutToPlay) + return; + + state = kStopped; + Invalidate(); +} + +void +PlayPauseButton::SetPlaying() +{ + if (state == kPlaying || state == kAboutToPause) + return; + + state = kPlaying; + Invalidate(); +} + +const bigtime_t kPauseBlinkPeriod = 600000; + +void +PlayPauseButton::SetPaused() +{ + if (state == kAboutToPlay) + return; + + // in paused state blink the LED on and off + bigtime_t now = system_time(); + if (state == kPausedLedOn || state == kPausedLedOff) { + if (now - lastPauseBlinkTime < kPauseBlinkPeriod) + return; + + if (state == kPausedLedOn) + state = kPausedLedOff; + else + state = kPausedLedOn; + } else + state = kPausedLedOn; + + lastPauseBlinkTime = now; + Invalidate(); +} + +uint32 +PlayPauseButton::ModeMask() const +{ + if (!IsEnabled()) + return kDisabledMask; + + uint32 result = 0; + + if (Value()) + result = kPressedMask; + + if (state == kPlaying || state == kAboutToPlay) + result |= kPlayingMask; + else if (state == kAboutToPause || state == kPausedLedOn) + result |= kPausedMask; + + return result; +} + +const unsigned char * +PlayPauseButton::BitsForMask(uint32 mask) const +{ + switch (mask) { + case kPlayingMask: + return normalPlayingBits; + case kPlayingMask | kPressedMask: + return pressedPlayingBits; + case kPausedMask: + return normalPausedBits; + case kPausedMask | kPressedMask: + return pressedPausedBits; + default: + return _inherited::BitsForMask(mask); + } + TRESPASS(); + return 0; +} + + +void +PlayPauseButton::StartPressing() +{ + if (state == kPlaying) + state = kAboutToPause; + else + state = kAboutToPlay; + + _inherited::StartPressing(); +} + +void +PlayPauseButton::MouseCancelPressing() +{ + if (state == kAboutToPause) + state = kPlaying; + else + state = kStopped; + + _inherited::MouseCancelPressing(); +} + +void +PlayPauseButton::DonePressing() +{ + if (state == kAboutToPause) { + state = kPausedLedOn; + lastPauseBlinkTime = system_time(); + } else if (state == kAboutToPlay) + state = kPlaying; + + _inherited::DonePressing(); +} + + diff --git a/modules/gui/beos/TransportButton.h b/modules/gui/beos/TransportButton.h new file mode 100644 index 0000000000..23bd1f870a --- /dev/null +++ b/modules/gui/beos/TransportButton.h @@ -0,0 +1,183 @@ +/***************************************************************************** + * TransportButton.h + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: TransportButton.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Tony Castley + * + * 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. + *****************************************************************************/ + +#ifndef __MEDIA_BUTTON__ +#define __MEDIA_BUTTON__ + +#include + +class BMessage; +class BBitmap; +class PeriodicMessageSender; +class BitmapStash; + +// TransportButton must be installed into a window with B_ASYNCHRONOUS_CONTROLS on +// currently no button focus drawing + +class TransportButton : public BControl { +public: + + TransportButton(BRect frame, const char *name, + const unsigned char *normalBits, + const unsigned char *pressedBits, + const unsigned char *disabledBits, + BMessage *invokeMessage, // done pressing over button + BMessage *startPressingMessage = 0, // just clicked button + BMessage *pressingMessage = 0, // periodical still pressing + BMessage *donePressing = 0, // tracked out of button/didn't invoke + bigtime_t period = 0, // pressing message period + uint32 key = 0, // optional shortcut key + uint32 modifiers = 0, // optional shortcut key modifier + uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP); + + virtual ~TransportButton(); + + void SetStartPressingMessage(BMessage *); + void SetPressingMessage(BMessage *); + void SetDonePressingMessage(BMessage *); + void SetPressingPeriod(bigtime_t); + + virtual void SetEnabled(bool); + +protected: + + enum { + kDisabledMask = 0x1, + kPressedMask = 0x2 + }; + + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + virtual void Draw(BRect); + virtual void MouseDown(BPoint); + virtual void MouseMoved(BPoint, uint32 code, const BMessage *); + virtual void MouseUp(BPoint); + virtual void WindowActivated(bool); + + virtual BBitmap *MakeBitmap(uint32); + // lazy bitmap builder + + virtual uint32 ModeMask() const; + // mode mask corresponding to the current button state + // - determines which bitmap will be used + virtual const unsigned char *BitsForMask(uint32) const; + // pick the right bits based on a mode mask + + // overriding class can add swapping between two pairs of bitmaps, etc. + virtual void StartPressing(); + virtual void MouseCancelPressing(); + virtual void DonePressing(); + +private: + void ShortcutKeyDown(); + void ShortcutKeyUp(); + + void MouseStartPressing(); + void MouseDonePressing(); + + BitmapStash *bitmaps; + // using BitmapStash * here instead of a direct member so that the class can be private in + // the .cpp file + + // bitmap bits used to build bitmaps for the different states + const unsigned char *normalBits; + const unsigned char *pressedBits; + const unsigned char *disabledBits; + + BMessage *startPressingMessage; + BMessage *pressingMessage; + BMessage *donePressingMessage; + bigtime_t pressingPeriod; + + bool mouseDown; + bool keyDown; + PeriodicMessageSender *messageSender; + BMessageFilter *keyPressFilter; + + typedef BControl _inherited; + + friend class SkipButtonKeypressFilter; + friend class BitmapStash; +}; + +class PlayPauseButton : public TransportButton { +// Knows about playing and paused states, blinks +// the pause LED during paused state +public: + PlayPauseButton(BRect frame, const char *name, + const unsigned char *normalBits, + const unsigned char *pressedBits, + const unsigned char *disabledBits, + const unsigned char *normalPlayingBits, + const unsigned char *pressedPlayingBits, + const unsigned char *normalPausedBits, + const unsigned char *pressedPausedBits, + BMessage *invokeMessage, // done pressing over button + uint32 key = 0, // optional shortcut key + uint32 modifiers = 0, // optional shortcut key modifier + uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP); + + // These need get called periodically to update the button state + // OK to call them over and over - once the state is correct, the call + // is very low overhead + void SetStopped(); + void SetPlaying(); + void SetPaused(); + +protected: + + virtual uint32 ModeMask() const; + virtual const unsigned char *BitsForMask(uint32) const; + + virtual void StartPressing(); + virtual void MouseCancelPressing(); + virtual void DonePressing(); + +private: + const unsigned char *normalPlayingBits; + const unsigned char *pressedPlayingBits; + const unsigned char *normalPausedBits; + const unsigned char *pressedPausedBits; + + enum PlayState { + kStopped, + kAboutToPlay, + kPlaying, + kAboutToPause, + kPausedLedOn, + kPausedLedOff + }; + + enum { + kPlayingMask = 0x4, + kPausedMask = 0x8 + }; + + PlayState state; + bigtime_t lastPauseBlinkTime; + uint32 lastModeMask; + + typedef TransportButton _inherited; +}; + +#endif diff --git a/modules/gui/beos/VideoOutput.cpp b/modules/gui/beos/VideoOutput.cpp new file mode 100644 index 0000000000..92748917c2 --- /dev/null +++ b/modules/gui/beos/VideoOutput.cpp @@ -0,0 +1,653 @@ +/***************************************************************************** + * vout.cpp: beos video output display method + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: VideoOutput.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Samuel Hocevar + * Tony Castley + * Richard Shepherd + * + * 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 /* ENOMEM */ +#include /* free() */ +#include +#include /* strerror() */ +#include +#include +#include +#include + +#include +#include +#include + +#include "VideoWindow.h" +#include "DrawingTidbits.h" +#include "MsgVals.h" + + +/***************************************************************************** + * vout_sys_t: BeOS video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the BeOS specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + VideoWindow * p_window; + + s32 i_width; + s32 i_height; + + u32 source_chroma; + int i_index; +}; + +/***************************************************************************** + * beos_GetAppWindow : retrieve a BWindow pointer from the window name + *****************************************************************************/ +BWindow *beos_GetAppWindow(char *name) +{ + int32 index; + BWindow *window; + + for (index = 0 ; ; index++) + { + window = be_app->WindowAt(index); + if (window == NULL) + break; + if (window->LockWithTimeout(20000) == B_OK) + { + if (strcmp(window->Name(), name) == 0) + { + window->Unlock(); + break; + } + window->Unlock(); + } + } + return window; +} + +/***************************************************************************** + * VideoWindow constructor and destructor + *****************************************************************************/ +VideoWindow::VideoWindow( int v_width, int v_height, + BRect frame ) + : BWindow( frame, NULL, B_TITLED_WINDOW, + B_NOT_CLOSABLE | B_NOT_MINIMIZABLE ) +{ + BView *mainView = new BView( Bounds(), "mainView", + B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE); + AddChild(mainView); + mainView->SetViewColor(kBlack); + + /* create the view to do the display */ + view = new VLCView( Bounds() ); + mainView->AddChild(view); + + /* set the VideoWindow variables */ + teardownwindow = false; + is_zoomed = false; + vsync = false; + i_buffer = 0; + + /* call ScreenChanged to set vsync correctly */ + BScreen *screen; + display_mode disp_mode; + float refresh; + + screen = new BScreen(this); + + screen-> GetMode(&disp_mode); + refresh = + (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* + (disp_mode.timing.v_total)); + if (refresh < 61) + { + vsync = true; + } + delete screen; + + mode = SelectDrawingMode(v_width, v_height); + + // remember current settings + i_width = v_width; + i_height = v_height; + FrameResized(v_width, v_height); + + if (mode == OVERLAY) + { + overlay_restrictions r; + + bitmap[1]->GetOverlayRestrictions(&r); + SetSizeLimits((i_width * r.min_width_scale) + 1, i_width * r.max_width_scale, + (i_height * r.min_height_scale) + 1, i_height * r.max_height_scale); + } + Show(); +} + +VideoWindow::~VideoWindow() +{ + teardownwindow = true; + delete bitmap[0]; + delete bitmap[1]; + delete bitmap[2]; +} + +void VideoWindow::MessageReceived( BMessage *p_message ) +{ + switch( p_message->what ) + { + case TOGGLE_FULL_SCREEN: + ((BWindow *)this)->Zoom(); + break; + case RESIZE_100: + if (is_zoomed) + { + ((BWindow *)this)->Zoom(); + } + ResizeTo(i_width, i_height); + break; + case RESIZE_200: + if (is_zoomed) + { + ((BWindow *)this)->Zoom(); + } + ResizeTo(i_width * 2, i_height * 2); + break; + case VERT_SYNC: + vsync = !vsync; + break; + case WINDOW_FEEL: + { + int16 winFeel; + if (p_message->FindInt16("WinFeel", &winFeel) == B_OK) + { + SetFeel((window_feel)winFeel); + } + } + break; + default: + BWindow::MessageReceived( p_message ); + break; + } +} + +void VideoWindow::drawBuffer(int bufferIndex) +{ + i_buffer = bufferIndex; + + // sync to the screen if required + if (vsync) + { + BScreen *screen; + screen = new BScreen(this); + screen-> WaitForRetrace(22000); + delete screen; + } + if (LockLooper()) + { + // switch the overlay bitmap + if (mode == OVERLAY) + { + rgb_color key; + view->SetViewOverlay(bitmap[i_buffer], + bitmap[i_buffer]->Bounds() , + view->Bounds(), + &key, B_FOLLOW_ALL, + B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL| + B_OVERLAY_TRANSFER_CHANNEL); + view->SetViewColor(key); + } + else + { + // switch the bitmap + view-> DrawBitmap(bitmap[i_buffer], view->Bounds() ); + } + UnlockLooper(); + } +} + +void VideoWindow::Zoom(BPoint origin, float width, float height ) +{ + if(is_zoomed) + { + is_zoomed = !is_zoomed; + MoveTo(winSize.left, winSize.top); + ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight()); + be_app->ShowCursor(); + } + else + { + is_zoomed = !is_zoomed; + BScreen *screen; + screen = new BScreen(this); + BRect rect = screen->Frame(); + delete screen; + MoveTo(0,0); + ResizeTo(rect.IntegerWidth(), rect.IntegerHeight()); + be_app->ObscureCursor(); + } +} + +void VideoWindow::FrameMoved(BPoint origin) +{ + if (is_zoomed) return ; + winSize = Frame(); +} + +void VideoWindow::FrameResized( float width, float height ) +{ + float out_width, out_height; + float out_left, out_top; + float width_scale = width / i_width; + float height_scale = height / i_height; + + if (width_scale <= height_scale) + { + out_width = (i_width * width_scale); + out_height = (i_height * width_scale); + out_left = 0; + out_top = (height - out_height) / 2; + } + else /* if the height is proportionally smaller */ + { + out_width = (i_width * height_scale); + out_height = (i_height * height_scale); + out_top = 0; + out_left = (width - out_width) /2; + } + view->MoveTo(out_left,out_top); + view->ResizeTo(out_width, out_height); + if (!is_zoomed) + { + winSize = Frame(); + } +} + +void VideoWindow::ScreenChanged(BRect frame, color_space mode) +{ + BScreen *screen; + float refresh; + + screen = new BScreen(this); + display_mode disp_mode; + + screen-> GetMode(&disp_mode); + refresh = + (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* + (disp_mode.timing.v_total)); + if (refresh < 61) + { + vsync = true; + } +} + +void VideoWindow::WindowActivated(bool active) +{ +} + +int VideoWindow::SelectDrawingMode(int width, int height) +{ + int drawingMode = BITMAP; + int noOverlay = 0; + +// int noOverlay = !config_GetIntVariable( "overlay" ); + for (int i = 0; i < COLOR_COUNT; i++) + { + if (noOverlay) break; + bitmap[0] = new BBitmap ( BRect( 0, 0, width, height ), + B_BITMAP_WILL_OVERLAY, + colspace[i].colspace); + + if(bitmap[0] && bitmap[0]->InitCheck() == B_OK) + { + colspace_index = i; + + bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY, + colspace[colspace_index].colspace); + bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY, + colspace[colspace_index].colspace); + if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) ) + { + drawingMode = OVERLAY; + rgb_color key; + view->SetViewOverlay(bitmap[0], + bitmap[0]->Bounds() , + view->Bounds(), + &key, B_FOLLOW_ALL, + B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL); + view->SetViewColor(key); + SetTitle(VOUT_TITLE " (Overlay)"); + break; + } + else + { + delete bitmap[0]; + delete bitmap[1]; + delete bitmap[2]; + } + } + else + { + delete bitmap[0]; + } + } + + if (drawingMode == BITMAP) + { + // fallback to RGB16 + colspace_index = DEFAULT_COL; + SetTitle(VOUT_TITLE " (Bitmap)"); + bitmap[0] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace); + bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace); + bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace); + } + return drawingMode; +} + +/***************************************************************************** + * VLCView::VLCView + *****************************************************************************/ +VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_NONE, + B_WILL_DRAW) + +{ + SetViewColor(B_TRANSPARENT_32_BIT); +} + +/***************************************************************************** + * VLCView::~VLCView + *****************************************************************************/ +VLCView::~VLCView() +{ +} + +/***************************************************************************** + * VLCVIew::MouseDown + *****************************************************************************/ +void VLCView::MouseDown(BPoint point) +{ + BMessage* msg = Window()->CurrentMessage(); + int32 clicks = msg->FindInt32("clicks"); + + VideoWindow *vWindow = (VideoWindow *)Window(); + uint32 mouseButtons; + BPoint where; + GetMouse(&where, &mouseButtons, true); + + if ((mouseButtons & B_PRIMARY_MOUSE_BUTTON) && (clicks == 2)) + { + Window()->Zoom(); + return; + } + else + { + if (mouseButtons & B_SECONDARY_MOUSE_BUTTON) + { + BPopUpMenu *menu = new BPopUpMenu("context menu"); + menu->SetRadioMode(false); + // Toggle FullScreen + BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN)); + zoomItem->SetMarked(vWindow->is_zoomed); + menu->AddItem(zoomItem); + // Resize to 100% + BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100)); + menu->AddItem(origItem); + // Resize to 200% + BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200)); + menu->AddItem(doubleItem); + menu->AddSeparatorItem(); + // Toggle vSync + BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC)); + vsyncItem->SetMarked(vWindow->vsync); + menu->AddItem(vsyncItem); + menu->AddSeparatorItem(); + + // Windwo Feel Items + BMessage *winNormFeel = new BMessage(WINDOW_FEEL); + winNormFeel->AddInt16("WinFeel", (int16)B_NORMAL_WINDOW_FEEL); + BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel); + normWindItem->SetMarked(vWindow->Feel() == B_NORMAL_WINDOW_FEEL); + menu->AddItem(normWindItem); + + BMessage *winFloatFeel = new BMessage(WINDOW_FEEL); + winFloatFeel->AddInt16("WinFeel", (int16)B_MODAL_ALL_WINDOW_FEEL); + BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel); + onTopWindItem->SetMarked(vWindow->Feel() == B_MODAL_ALL_WINDOW_FEEL); + menu->AddItem(onTopWindItem); + + BMessage *winAllFeel = new BMessage(WINDOW_FEEL); + winAllFeel->AddInt16("WinFeel", (int16)B_FLOATING_ALL_WINDOW_FEEL); + BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel); + allSpacesWindItem->SetMarked(vWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL); + menu->AddItem(allSpacesWindItem); + + menu->SetTargetForItems(this); + ConvertToScreen(&where); + menu->Go(where, true, false, true); + } + } +} + +/***************************************************************************** + * VLCVIew::Draw + *****************************************************************************/ +void VLCView::Draw(BRect updateRect) +{ + VideoWindow *win = (VideoWindow *) Window(); + if (win->mode == BITMAP) + FillRect(updateRect); +} + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int BeosOpenDisplay ( vout_thread_t *p_vout ); +static void BeosCloseDisplay( vout_thread_t *p_vout ); + +/***************************************************************************** + * OpenVideo: allocates BeOS video thread output method + ***************************************************************************** + * This function allocates and initializes a BeOS vout method. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + p_vout->p_sys->i_width = p_vout->render.i_width; + p_vout->p_sys->i_height = p_vout->render.i_height; + p_vout->p_sys->source_chroma = p_vout->render.i_chroma; + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize BeOS video thread output method + *****************************************************************************/ +int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Open and initialize device */ + if( BeosOpenDisplay( p_vout ) ) + { + msg_Err(p_vout, "vout error: can't open display"); + return 0; + } + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->p_sys->i_width + * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height; + p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma; + p_vout->p_sys->i_index = 0; + + p_vout->b_direct = 1; + + p_vout->output.i_rmask = 0x00ff0000; + p_vout->output.i_gmask = 0x0000ff00; + p_vout->output.i_bmask = 0x000000ff; + + for (int buffer_index = 0 ; buffer_index < 3; buffer_index++) + { + p_pic = NULL; + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + p_pic = NULL; + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + if( p_pic == NULL ) + { + return 0; + } + p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits(); + p_pic->p->i_lines = p_vout->p_sys->i_height; + + p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes; + p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes; + p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow(); + p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 ); + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * End: terminate BeOS video thread output method + *****************************************************************************/ +void End( vout_thread_t *p_vout ) +{ + BeosCloseDisplay( p_vout ); +} + +/***************************************************************************** + * CloseVideo: destroy BeOS video thread output method + ***************************************************************************** + * Terminate an output method created by DummyCreateOutputMethod + *****************************************************************************/ +void E_(CloseVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Display: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to BeOS image, waits until + * it is displayed and switch the two rendering buffers, preparing next frame. + *****************************************************************************/ +void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + VideoWindow * p_win = p_vout->p_sys->p_window; + + /* draw buffer if required */ + if (!p_win->teardownwindow) + { + p_win->drawBuffer(p_vout->p_sys->i_index); + } + /* change buffer */ + p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3; + p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits(); +} + +/* following functions are local */ + +/***************************************************************************** + * BeosOpenDisplay: open and initialize BeOS device + *****************************************************************************/ +static int BeosOpenDisplay( vout_thread_t *p_vout ) +{ + + p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1, + p_vout->p_sys->i_height - 1, + BRect( 20, 50, + 20 + p_vout->i_window_width - 1, + 50 + p_vout->i_window_height - 1 )); + + if( p_vout->p_sys->p_window == NULL ) + { + msg_Err( p_vout, "cannot allocate VideoWindow" ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * BeosDisplay: close and reset BeOS device + ***************************************************************************** + * Returns all resources allocated by BeosOpenDisplay and restore the original + * state of the device. + *****************************************************************************/ +static void BeosCloseDisplay( vout_thread_t *p_vout ) +{ + VideoWindow * p_win = p_vout->p_sys->p_window; + /* Destroy the video window */ + if( p_win != NULL && !p_win->teardownwindow) + { + p_win->Lock(); + p_win->teardownwindow = true; + p_win->Hide(); + p_win->Quit(); + } + p_win = NULL; +} + diff --git a/modules/gui/beos/VideoWindow.h b/modules/gui/beos/VideoWindow.h new file mode 100644 index 0000000000..649b64de0e --- /dev/null +++ b/modules/gui/beos/VideoWindow.h @@ -0,0 +1,97 @@ +/***************************************************************************** + * VideoWindow.h: BeOS video window class prototype + ***************************************************************************** + * Copyright (C) 1999, 2000, 2001 VideoLAN + * $Id: VideoWindow.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Marc Dressler + * Tony Castley + * Richard Shepherd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ +#define BITMAP 0 +#define OVERLAY 1 +#define OPENGL 2 + +typedef struct colorcombo +{ + color_space colspace; + const char *name; + u32 chroma; + int planes; + int pixel_bytes; +} colorcombo; + +colorcombo colspace[]= +{ + {B_YCbCr420, "B_YCbCr420", VLC_FOURCC('I','4','2','0'), 3, 2}, + {B_YUV422, "B_YUV422", VLC_FOURCC('Y','4','2','2'), 3, 2}, + {B_YCbCr422, "B_YCbCr422", VLC_FOURCC('Y','U','Y','2'), 3, 2}, + {B_RGB32, "B_RGB32", VLC_FOURCC('R','V','3','2'), 1, 4}, + {B_RGB16, "B_RGB16", VLC_FOURCC('R','V','1','6'), 1, 2} +}; + +#define COLOR_COUNT 5 +#define DEFAULT_COL 4 + + +class VLCView : public BView +{ +public: + VLCView( BRect bounds); + ~VLCView(); + + void MouseDown(BPoint point); + void Draw(BRect updateRect); +}; + + +class VideoWindow : public BWindow +{ +public: + // standard constructor and destructor + VideoWindow( int v_width, int v_height, + BRect frame); + ~VideoWindow(); + + void Zoom(BPoint origin, float width, float height); + void FrameResized(float width, float height); + void FrameMoved(BPoint origin); + void ScreenChanged(BRect frame, color_space mode); + void drawBuffer(int bufferIndex); + void WindowActivated(bool active); + int SelectDrawingMode(int width, int height); + void MessageReceived(BMessage *message); + + // this is the hook controling direct screen connection + int32 i_width; // incomming bitmap size + int32 i_height; + BRect winSize; // current window size + bool is_zoomed, vsync; + BBitmap *bitmap[3]; + VLCView *view; + int i_buffer; + bool teardownwindow; + thread_id fDrawThreadID; + int mode; + int colspace_index; + +private: + vout_thread_t *p_vout; + +}; + + diff --git a/modules/gui/beos/VlcWrapper.cpp b/modules/gui/beos/VlcWrapper.cpp new file mode 100644 index 0000000000..f35c6ee899 --- /dev/null +++ b/modules/gui/beos/VlcWrapper.cpp @@ -0,0 +1,459 @@ +/***************************************************************************** + * vlc_wrapper.h: BeOS plugin for vlc (derived from MacOS X port ) + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: VlcWrapper.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Florian G. Pflug + * Jon Lech Johansen + * Tony Casltey + * + * 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. + *****************************************************************************/ +/* VLC headers */ +#include + +#include +#include + +#include "vlc_wrapper.h" + +Intf_VLCWrapper *Intf_VLCWrapper::getVLCWrapper(intf_thread_t *p_if) +{ + static Intf_VLCWrapper *one_wrapper; + if (one_wrapper == NULL ) + { + one_wrapper = new Intf_VLCWrapper(p_if); + } + return one_wrapper; +} + +Intf_VLCWrapper::Intf_VLCWrapper(intf_thread_t *p_if) +{ + p_intf = p_if; +} + +Intf_VLCWrapper::~Intf_VLCWrapper() +{ +} + +//bool Intf_VLCWrapper::manage() +//{ +// +// p_intf->pf_manage( p_intf ); +// +// if ( p_intf->b_die ) +// { +// // exit the lot +// return( 1 ); +// } + /* Update the input */ +// if( p_intf->p_sys->p_input != NULL ) +// { +// if( p_intf->p_sys->p_input->b_dead ) +// { +// vlc_object_release( p_intf->p_sys->p_input ); +// p_intf->p_sys->p_input = NULL; +// } +// } +// +// p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, +// FIND_ANYWHERE ); + +// if ( p_intf->p_sys->p_input != NULL ) +// { +// vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); +// if( !p_intf->p_sys->p_input->b_die ) +// { +// /* New input or stream map change */ +// if( p_intf->p_sys->p_input->stream.b_changed || +// p_intf->p_sys->i_part != +// p_intf->p_sys->p_input->stream.p_selected_area->i_part ) +// { +// setupMenus(); +// p_intf->p_sys->b_disabled_menus = 0; +// } +// } +// vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); +// } +// else if ( !p_intf->p_sys->b_disabled_menus ) +// { +// setupMenus(); +// p_intf->p_sys->b_disabled_menus = 1; +// } +// return( 0 ); +//} + +void Intf_VLCWrapper::quit() +{ + p_intf->b_die = 1; +} + +/* playlist control */ + +int Intf_VLCWrapper::inputGetStatus() +{ + if( p_intf->p_sys->p_input != NULL ) + { + return( p_intf->p_sys->p_input->stream.control.i_status ); + } + else + { + return( UNDEF_S ); + } +} + +bool Intf_VLCWrapper::playlistPlay() +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + } + + return( true ); + +} + +void Intf_VLCWrapper::playlistPause() +{ + toggleMute( ); + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + playlist_Pause( p_playlist ); + vlc_object_release( p_playlist ); +} + +void Intf_VLCWrapper::playlistStop() +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + +} + +void Intf_VLCWrapper::playlistNext() +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); +} + +void Intf_VLCWrapper::playlistPrev() +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); +} + +void Intf_VLCWrapper::playlistSkip(int i) +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_Skip( p_playlist, i ); + vlc_object_release( p_playlist ); +} + +void Intf_VLCWrapper::playlistGoto(int i) +{ + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + playlist_Goto( p_playlist, i ); + vlc_object_release( p_playlist ); +} + + /* playback control */ +void Intf_VLCWrapper::playSlower() +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); + } + if (p_intf->p_sys->p_input->stream.control.i_rate == DEFAULT_RATE) + { + toggleMute( ); + } + else + { + toggleMute ( ); + } +} + +void Intf_VLCWrapper::playFaster() +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); + } + if (p_intf->p_sys->p_input->stream.control.i_rate == DEFAULT_RATE) + { + toggleMute( ); + } + else + { + toggleMute ( ); + } +} + +void Intf_VLCWrapper::toggleProgram(int i_program){} + +void Intf_VLCWrapper::toggleTitle(int i_title) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_ChangeArea( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_areas[i_title] ); + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + //setupMenus(); + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +void Intf_VLCWrapper::toggleChapter(int i_chapter) +{ + if( p_intf->p_sys->p_input != NULL ) + { + p_intf->p_sys->p_input->stream.p_selected_area->i_part = i_chapter; + input_ChangeArea( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.p_selected_area ); + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); +// setupMenus(); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +void Intf_VLCWrapper::toggleLanguage(int i_language) +{ + + int32 i_old = -1; + int i_cat = AUDIO_ES; + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + for( int i = 0; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ ) + { + if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == i_cat ) + { + i_old = i; + break; + } + } + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + msg_Info( p_intf, "Old: %d, New: %d", i_old, i_language); + if( i_language != -1 ) + { + input_ToggleES( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_selected_es[i_language], + VLC_TRUE ); + } + + if( (i_old != -1) && (i_old != i_language) ) + { + input_ToggleES( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_selected_es[i_old], + VLC_FALSE ); + } +} + +void Intf_VLCWrapper::toggleSubtitle(int i_subtitle) +{ + int32 i_old = -1; + int i_cat = SPU_ES; + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + for( int i = 0; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ ) + { + if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == i_cat ) + { + i_old = i; + break; + } + } + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + msg_Info( p_intf, "Old: %d, New: %d", i_old, i_subtitle); + if( i_subtitle != -1 ) + { + input_ToggleES( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_selected_es[i_subtitle], + VLC_TRUE ); + } + + if( (i_old != -1) && (i_old != i_subtitle) ) + { + input_ToggleES( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_selected_es[i_old], + VLC_FALSE ); + } +} + + +void Intf_VLCWrapper::channelNext() +{ +} + +void Intf_VLCWrapper::channelPrev() +{ +} + +void Intf_VLCWrapper::eject(){} + + + +/* playback info */ + +BString* Intf_VLCWrapper::getTimeAsString() +{ + static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ]; + + if( p_intf->p_sys->p_input == NULL ) + { + return (new BString("00:00:00")); + } + + input_OffsetToTime( p_intf->p_sys->p_input, + psz_currenttime, + p_intf->p_sys->p_input->stream.p_selected_area->i_tell ); + + return(new BString(psz_currenttime)); +} + +float Intf_VLCWrapper::getTimeAsFloat() +{ + float f_time = 0.0; + + if( p_intf->p_sys->p_input != NULL ) + { + f_time = (float)p_intf->p_sys->p_input->stream.p_selected_area->i_tell / + (float)p_intf->p_sys->p_input->stream.p_selected_area->i_size; + } + else + { + f_time = 0.0; + } + return( f_time ); +} + +void Intf_VLCWrapper::setTimeAsFloat(float f_position) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_Seek( p_intf->p_sys->p_input, + (long long int)(p_intf->p_sys->p_input->stream.p_selected_area->i_size * f_position / 100), + INPUT_SEEK_SET); + } +} + +BList *Intf_VLCWrapper::playlistAsArray() +{ + int i; + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + BList* p_list = new BList(p_playlist->i_size); + + vlc_mutex_lock( &p_playlist->object_lock ); + + for( i = 0; i < p_playlist->i_size; i++ ) + { + p_list->AddItem(new BString(p_playlist->pp_items[i]->psz_name)); + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + return( p_list ); +} + + /* open file/disc/network */ +void Intf_VLCWrapper::openFiles(BList *o_files) +{ + BString *o_file; + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + while( ( o_file = (BString *)o_files->LastItem() ) ) + { + o_files->RemoveItem(o_files->CountItems() - 1); + playlist_Add( p_playlist, o_file->String(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + delete o_file; + } + + vlc_object_release( p_playlist ); + +} + +void Intf_VLCWrapper::openDisc(BString o_type, BString o_device, int i_title, int i_chapter) +{ + BString o_source(""); + o_source << o_type << ":" << o_device ; + + playlist_t *p_playlist = + (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + playlist_Add( p_playlist, o_source.String(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); +} + +void Intf_VLCWrapper::openNet(BString o_addr, int i_port) +{ +} + +void Intf_VLCWrapper::openNetChannel(BString o_addr, int i_port) +{ +} + +void Intf_VLCWrapper::openNetHTTP(BString o_addr) +{ +} + +void Intf_VLCWrapper::toggleMute( ) +{ + input_ToggleMute( p_intf->p_sys->p_input ); +} + +/* menus management */ + diff --git a/modules/gui/beos/VlcWrapper.h b/modules/gui/beos/VlcWrapper.h new file mode 100644 index 0000000000..79db5a6924 --- /dev/null +++ b/modules/gui/beos/VlcWrapper.h @@ -0,0 +1,121 @@ +/***************************************************************************** + * vlc_wrapper.h: BeOS plugin for vlc (derived from MacOS X port ) + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: VlcWrapper.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Florian G. Pflug + * Jon Lech Johansen + * Tony Casltey + * + * 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. + *****************************************************************************/ +class InterfaceWindow; + +/***************************************************************************** + * intf_sys_t: description and status of FB interface + *****************************************************************************/ +struct intf_sys_t +{ + InterfaceWindow *p_window; + char i_key; + + /* The input thread */ + input_thread_t * p_input; + + /* The messages window */ +// msg_subscription_t * p_sub; + + /* DVD mode */ + vlc_bool_t b_disabled_menus; + vlc_bool_t b_loop; + vlc_bool_t b_mute; + int i_part; + int i_saved_volume; + int i_channel; + +}; + +/* Intf_VLCWrapper is a singleton class + (only one instance at any time) */ +class Intf_VLCWrapper +{ +public: + static Intf_VLCWrapper *getVLCWrapper(intf_thread_t *p_if); + ~Intf_VLCWrapper(); + +// bool manage(); + void quit(); + int inputGetStatus(); + /* playlist control */ + bool playlistPlay(); + void playlistPause(); + void playlistStop(); + void playlistNext(); + void playlistPrev(); + void playlistSkip(int i); + void playlistGoto(int i); +/* Playback Modes + PLAYLIST_REPEAT_CURRENT + PLAYLIST_FORWARD + PLAYLIST_BACKWARD + PLAYLIST_FORWARD_LOOP + PLAYLIST_BACKWARD_LOOP + PLAYLIST_RANDOM + PLAYLIST_REVERSE_RANDOM +*/ + + /* Stream Control */ + void playSlower(); + void playFaster(); + + /* input control */ + int getStatus(); + void setStatus(int status); + void inputSeek(); + void toggleProgram(int i_program); + void toggleTitle(int i_title); + void toggleChapter(int i_chapter); + void toggleLanguage(int i_language); + void toggleSubtitle(int i_subtitle); + void channelNext(); + void channelPrev(); + void eject(); + + /* playback info */ + BString* getTimeAsString(); + float getTimeAsFloat(); + void setTimeAsFloat(float i_offset); + BList* playlistAsArray(); + + /* open file/disc/network */ + void openFiles(BList *o_files); + void openDisc(BString o_type, BString o_device, int i_title, int i_chapter); + void openNet(BString o_addr, int i_port); + void openNetChannel(BString o_addr, int i_port); + void openNetHTTP(BString o_addr); + + /* audio stuff */ + void toggleMute( ); + /* menus management */ + void setupMenus(); + +private: + Intf_VLCWrapper( intf_thread_t *p_if ); + es_descriptor_t * p_audio_es; + intf_thread_t *p_intf; + +}; + diff --git a/modules/gui/familiar/.cvsignore b/modules/gui/familiar/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/familiar/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/familiar/Makefile b/modules/gui/familiar/Makefile new file mode 100644 index 0000000000..be8d597e27 --- /dev/null +++ b/modules/gui/familiar/Makefile @@ -0,0 +1 @@ +familiar_SOURCES = familiar.c interface.c support.c callbacks.c diff --git a/modules/gui/familiar/callbacks.c b/modules/gui/familiar/callbacks.c new file mode 100644 index 0000000000..d699105bb0 --- /dev/null +++ b/modules/gui/familiar/callbacks.c @@ -0,0 +1,235 @@ +/***************************************************************************** + * callbacks.c : Callbacks for the Familiar Linux Gtk+ plugin. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: callbacks.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Paul Saman + * + * 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 /* off_t */ +#include + +#include +#include +#include + +#include +#include + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" +#include "familiar.h" + +//#include "netutils.h" + +/***************************************************************************** + * Useful function to retrieve p_intf + ****************************************************************************/ +void * __GtkGetIntf( GtkWidget * widget ) +{ + void *p_data; + + if( GTK_IS_MENU_ITEM( widget ) ) + { + /* Look for a GTK_MENU */ + while( widget->parent && !GTK_IS_MENU( widget ) ) + { + widget = widget->parent; + } + + /* Maybe this one has the data */ + p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" ); + if( p_data ) + { + return p_data; + } + + /* Otherwise, the parent widget has it */ + widget = gtk_menu_get_attach_widget( GTK_MENU( widget ) ); + } + + /* We look for the top widget */ + widget = gtk_widget_get_toplevel( GTK_WIDGET( widget ) ); + + p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" ); + + return p_data; +} + +/* + * Main interface callbacks + */ + +gboolean GtkExit( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + vlc_mutex_lock( &p_intf->change_lock ); + p_intf->p_vlc->b_die = VLC_TRUE; + vlc_mutex_unlock( &p_intf->change_lock ); + + return TRUE; +} + +gboolean +on_familiar_destroy_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + GtkExit( GTK_WIDGET( widget ), user_data ); + return TRUE; +} + + +void +on_toolbar_open_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + if (p_intf) + gtk_widget_show( GTK_WIDGET(p_intf->p_sys->p_notebook) ); +} + + +void +on_toolbar_preferences_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + if (p_intf) + gtk_widget_show( GTK_WIDGET(p_intf->p_sys->p_notebook) ); +} + + +void +on_toolbar_rewind_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + + if( p_intf ) + { + if( p_intf->p_sys->p_input ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); + } + } +} + + +void +on_toolbar_pause_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + + if( p_intf ) + { + if( p_intf->p_sys->p_input ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); + } + } +} + + +void +on_toolbar_play_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + // Display open page + } + + /* If the playlist is empty, open a file requester instead */ + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + // Display open page + } +} + + +void +on_toolbar_stop_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + } +} + + +void +on_toolbar_forward_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + + if( p_intf ) + { + if( p_intf->p_sys->p_input ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); + } + } +} + + +void +on_toolbar_about_clicked (GtkButton *button, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + if (p_intf) + { // Toggle notebook +// if ( gtk_get_data( GTK_WIDGET(p_intf->p_sys->p_notebook), "visible" ) ) +// gtk_widget_hide( GTK_WIDGET(p_intf->p_sys->p_notebook) ); +// else + gtk_widget_show( GTK_WIDGET(p_intf->p_sys->p_notebook) ); + } +} + diff --git a/modules/gui/familiar/callbacks.h b/modules/gui/familiar/callbacks.h new file mode 100644 index 0000000000..4dca132294 --- /dev/null +++ b/modules/gui/familiar/callbacks.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * callbacks.h : familiar plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: callbacks.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Paul Saman + * + * 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 + +gboolean GtkExit ( GtkWidget *, gpointer ); + +gboolean +on_familiar_destroy_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data); + +void +on_toolbar_open_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_preferences_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_rewind_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_pause_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_play_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_stop_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_forward_clicked (GtkButton *button, + gpointer user_data); + +void +on_toolbar_about_clicked (GtkButton *button, + gpointer user_data); diff --git a/modules/gui/familiar/familiar.c b/modules/gui/familiar/familiar.c new file mode 100644 index 0000000000..403dabb8e1 --- /dev/null +++ b/modules/gui/familiar/familiar.c @@ -0,0 +1,203 @@ +/***************************************************************************** + * familiar.c : familiar plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: familiar.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Paul Saman + * + * 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 /* malloc(), free() */ +#include /* ENOMEM */ +#include /* strerror() */ +#include + +#include +#include + +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" +#include "familiar.h" + +/***************************************************************************** + * Local variables (mutex-protected). + *****************************************************************************/ +static void ** pp_global_data = NULL; + +/***************************************************************************** + * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit + ***************************************************************************** + * gtk_init() makes several calls to g_atexit() which calls atexit() to + * register tidying callbacks to be called at program exit. Since the Gtk+ + * plugin is likely to be unloaded at program exit, we have to export this + * symbol to intercept the g_atexit() calls. Talk about crude hack. + *****************************************************************************/ +void g_atexit( GVoidFunc func ) +{ + intf_thread_t *p_intf; + + int i_dummy; + + if( pp_global_data == NULL ) + { + atexit( func ); + return; + } + + p_intf = (intf_thread_t *)*pp_global_data; + if( p_intf == NULL ) + { + return; + } + + for( i_dummy = 0; + i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL; + i_dummy++ ) + { + ; + } + + if( i_dummy >= MAX_ATEXIT - 1 ) + { + msg_Err( p_intf, "too many atexit() callbacks to register" ); + return; + } + + p_intf->p_sys->pf_callback[i_dummy] = func; + p_intf->p_sys->pf_callback[i_dummy + 1] = NULL; +} + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static void Run ( intf_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Familiar Linux Gtk+ interface module") ); + set_capability( "interface", 70 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Open: initialize and create window + *****************************************************************************/ +static int Open( 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 ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + /* Initialize Gtk+ thread */ + p_intf->p_sys->p_input = NULL; + + p_intf->pf_run = Run; + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface window + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + /* Destroy structure */ + if (p_intf->p_sys) free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: Gtk+ thread + ***************************************************************************** + * this part of the interface is in a separate thread so that we can call + * gtk_main() from within it without annoying the rest of the program. + * XXX: the approach may look kludgy, and probably is, but I could not find + * a better way to dynamically load a Gtk+ interface at runtime. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + /* gtk_init needs to know the command line. We don't care, so we + * give it an empty one */ + char *p_args[] = { "" }; + char **pp_args = p_args; + int i_args = 1; + int i_dummy = 0; + + /* Initialize Gtk+ */ + gtk_set_locale (); + + /* gtk_init will register stuff with g_atexit, so we need to take + * the global lock if we want to be able to intercept the calls */ + vlc_mutex_lock( p_intf->p_vlc->p_global_lock ); + *p_intf->p_vlc->pp_global_data = p_intf; + gtk_init( &i_args, &pp_args ); + vlc_mutex_unlock( p_intf->p_vlc->p_global_lock ); + + /* Create some useful widgets that will certainly be used */ +// FIXME: magic path + add_pixmap_directory("share"); + p_intf->p_sys->p_window = create_familiar(); + if (p_intf->p_sys->p_window == NULL) + { + msg_Err( p_intf, "unable to create familiar interface" ); + } + + /* Set the title of the main window */ + gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window), + VOUT_TITLE " (Familiar Linux interface)"); + + /* Get the slider object */ + p_intf->p_sys->p_notebook = GTK_NOTEBOOK( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_window ), "notebook" ) ); +// gtk_widget_hide( GTK_WIDGET(p_intf->p_sys->p_notebook) ); + + /* Store p_intf to keep an eye on it */ + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), + "p_intf", p_intf ); + /* Show the control window */ + gtk_widget_show( p_intf->p_sys->p_window ); + + /* Enter Gtk mode */ + gtk_main(); + + /* Remove the timeout */ + gtk_timeout_remove( i_dummy ); +} + diff --git a/modules/gui/familiar/familiar.glade b/modules/gui/familiar/familiar.glade new file mode 100644 index 0000000000..1ed1cf51d2 --- /dev/null +++ b/modules/gui/familiar/familiar.glade @@ -0,0 +1,546 @@ + + + + + Familiar + familiar + + + ../../share + C + False + True + True + False + False + interface.c + interface.h + callbacks.c + callbacks.h + support.c + support.h + + + + GtkWindow + familiar + 240 + 320 + + destroy_event + on_familiar_destroy_event + Tue, 23 Jul 2002 18:16:11 GMT + + + destroy + gtk_main_quit + Tue, 23 Jul 2002 18:17:28 GMT + + vlc (familiar) + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + True + + + GtkVBox + vbox + False + 0 + + + GtkToolbar + toolbar + 112 + 16 + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_ICONS + 5 + GTK_TOOLBAR_SPACE_EMPTY + GTK_RELIEF_NORMAL + True + + 0 + True + True + + + + GtkButton + Toolbar:button + toolbar_open + Open file + + clicked + on_toolbar_open_clicked + Wed, 24 Jul 2002 18:28:31 GMT + + + familiar-openb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_preferences + Preferences + + clicked + on_toolbar_preferences_clicked + Wed, 24 Jul 2002 18:29:05 GMT + + + familiar-preferencesb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_rewind + Rewind stream + + clicked + on_toolbar_rewind_clicked + Wed, 24 Jul 2002 18:28:45 GMT + + + familiar-rewindb16x16.xpm + + True + + + + + GtkButton + Toolbar:button + toolbar_pause + Pause stream + + clicked + on_toolbar_pause_clicked + Wed, 24 Jul 2002 18:28:58 GMT + + + familiar-pauseb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_play + Play stream + + clicked + on_toolbar_play_clicked + Wed, 24 Jul 2002 18:29:12 GMT + + + familiar-playb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_stop + Stop stream + + clicked + on_toolbar_stop_clicked + Wed, 24 Jul 2002 18:29:18 GMT + + + familiar-stopb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_forward + Forward stream + + clicked + on_toolbar_forward_clicked + Wed, 24 Jul 2002 18:29:25 GMT + + + familiar-forwardb16x16.xpm + + + + GtkButton + Toolbar:button + toolbar_about + About + + clicked + on_toolbar_about_clicked + Wed, 24 Jul 2002 18:29:31 GMT + + + vlc16x16.xpm + + True + + + + + + GtkProgressBar + progress + 0 + 0 + 100 + GTK_PROGRESS_CONTINUOUS + GTK_PROGRESS_LEFT_TO_RIGHT + True + False + %P %% + 0.5 + 0.5 + + 0 + False + False + + + + + GtkNotebook + notebook + True + True + True + GTK_POS_TOP + False + 2 + 2 + False + + 0 + True + True + + + + GtkFixed + fixedMedia + + + GtkLabel + labelUrl + 4 + 8 + 38 + 18 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkList + listMedia + 8 + 40 + 220 + 200 + Select multimedia file. + GTK_SELECTION_MULTIPLE + + + + GtkCombo + comboURL + 46 + 6 + 185 + 24 + False + True + False + True + False + file:// +ftp://localhost +http://localhost +udp://localhost:1234/ + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + True + True + 0 + file:// + + + + + + GtkLabel + Notebook:tab + media + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkFixed + fixedPreferences + + + GtkButton + buttonSave + 8 + 216 + 54 + 24 + True + + GTK_RELIEF_NORMAL + + + + GtkButton + buttonApply + 64 + 216 + 54 + 24 + True + + GTK_RELIEF_NORMAL + + + + GtkButton + buttonCancel + 176 + 216 + 54 + 24 + True + + GTK_RELIEF_NORMAL + + + + GtkFrame + frameDefaultURL + 8 + 8 + 220 + 60 + + 0 + GTK_SHADOW_ETCHED_IN + + + GtkFixed + fixed3 + + + GtkCombo + comboDefaultURL + 8 + 4 + 200 + 24 + False + True + False + True + False + file:// +ftp://localhost +http://localhost +udp://localhost:1234/ + + + + GtkEntry + GtkCombo:entry + combo-entry2 + True + True + True + 0 + file:// + + + + + + + GtkFrame + frameIP + 8 + 72 + 220 + 60 + + 0 + GTK_SHADOW_ETCHED_IN + + + GtkFixed + fixed2 + + + GtkRadioButton + rbIPv4 + 8 + 8 + 104 + 26 + True + + True + True + + + + GtkRadioButton + rbIPv6 + 112 + 8 + 104 + 26 + True + + False + True + + + + + + + GtkLabel + Notebook:tab + preferences + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkFixed + fixedAbout + + + GtkPixmap + logo + 8 + 0 + 50 + 50 + vlc32x32.xpm + 0.5 + 0.5 + 0 + 0 + True + + + + GtkLabel + labelVlc + 64 + 8 + 120 + 40 + + GTK_JUSTIFY_CENTER + True + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + labelCopyright + 16 + 56 + 200 + 18 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + labelAuthors + 16 + 80 + 200 + 40 + + GTK_JUSTIFY_CENTER + True + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + labelAbout + 16 + 128 + 200 + 70 + + GTK_JUSTIFY_LEFT + True + 0.5 + 0.5 + 0 + 0 + + + + + GtkLabel + Notebook:tab + about + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + diff --git a/modules/gui/familiar/familiar.h b/modules/gui/familiar/familiar.h new file mode 100644 index 0000000000..af44ab6644 --- /dev/null +++ b/modules/gui/familiar/familiar.h @@ -0,0 +1,50 @@ +/***************************************************************************** + * familiar.h: private Gtk+ interface description + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: familiar.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jean-Paul Saman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define MAX_ATEXIT 10 + +/***************************************************************************** + * intf_sys_t: description and status of Gtk+ interface + *****************************************************************************/ +struct intf_sys_t +{ + /* windows and widgets */ + GtkWidget * p_window; /* main window */ + GtkNotebook * p_notebook; +// GtkWidget * p_notebook_about; +// GtkWidget * p_notebook_open; +// GtkWidget * p_notebook_preferences; + + /* The input thread */ + input_thread_t * p_input; + + /* XXX: Ugly kludge, see gtk.c */ + void ( *pf_callback[MAX_ATEXIT] ) ( void ); +}; + +/***************************************************************************** + * Useful macro + ****************************************************************************/ +#define GtkGetIntf( widget ) __GtkGetIntf( GTK_WIDGET( widget ) ) +void * __GtkGetIntf( GtkWidget * ); + diff --git a/modules/gui/familiar/interface.c b/modules/gui/familiar/interface.c new file mode 100644 index 0000000000..ac2b6ad98c --- /dev/null +++ b/modules/gui/familiar/interface.c @@ -0,0 +1,516 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "callbacks.h" +#include "interface.h" +#include "support.h" + +GtkWidget* +create_familiar (void) +{ + GtkWidget *familiar; + GtkWidget *vbox; + GtkWidget *toolbar; + GtkWidget *tmp_toolbar_icon; + GtkWidget *toolbar_open; + GtkWidget *toolbar_preferences; + GtkWidget *toolbar_rewind; + GtkWidget *toolbar_pause; + GtkWidget *toolbar_play; + GtkWidget *toolbar_stop; + GtkWidget *toolbar_forward; + GtkWidget *toolbar_about; + GtkWidget *progress; + GtkWidget *notebook; + GtkWidget *fixedMedia; + GtkWidget *labelUrl; + GtkWidget *listMedia; + GtkWidget *comboURL; + GList *comboURL_items = NULL; + GtkWidget *combo_entry1; + GtkWidget *media; + GtkWidget *fixedPreferences; + GtkWidget *buttonSave; + GtkWidget *buttonApply; + GtkWidget *buttonCancel; + GtkWidget *frameDefaultURL; + GtkWidget *fixed3; + GtkWidget *comboDefaultURL; + GList *comboDefaultURL_items = NULL; + GtkWidget *combo_entry2; + GtkWidget *frameIP; + GtkWidget *fixed2; + GSList *fixed2_group = NULL; + GtkWidget *rbIPv4; + GtkWidget *rbIPv6; + GtkWidget *preferences; + GtkWidget *fixedAbout; + GtkWidget *logo; + GtkWidget *labelVlc; + GtkWidget *labelCopyright; + GtkWidget *labelAuthors; + GtkWidget *labelAbout; + GtkWidget *about; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + familiar = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (familiar, "familiar"); + gtk_object_set_data (GTK_OBJECT (familiar), "familiar", familiar); + gtk_widget_set_usize (familiar, 240, 320); + gtk_window_set_title (GTK_WINDOW (familiar), _("vlc (familiar)")); + gtk_window_set_policy (GTK_WINDOW (familiar), TRUE, TRUE, TRUE); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_set_name (vbox, "vbox"); + gtk_widget_ref (vbox); + gtk_object_set_data_full (GTK_OBJECT (familiar), "vbox", vbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (familiar), vbox); + + toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS); + gtk_widget_set_name (toolbar, "toolbar"); + gtk_widget_ref (toolbar); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar", toolbar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar); + gtk_box_pack_start (GTK_BOX (vbox), toolbar, TRUE, TRUE, 0); + gtk_widget_set_usize (toolbar, 112, 16); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-openb16x16.xpm"); + toolbar_open = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Open"), + _("Open file"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_open, "toolbar_open"); + gtk_widget_ref (toolbar_open); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_open", toolbar_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_open); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-preferencesb16x16.xpm"); + toolbar_preferences = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Preferences"), + _("Preferences"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_preferences, "toolbar_preferences"); + gtk_widget_ref (toolbar_preferences); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_preferences", toolbar_preferences, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_preferences); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-rewindb16x16.xpm"); + toolbar_rewind = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Rewind"), + _("Rewind stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_rewind, "toolbar_rewind"); + gtk_widget_ref (toolbar_rewind); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_rewind", toolbar_rewind, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_rewind); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-pauseb16x16.xpm"); + toolbar_pause = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Pause"), + _("Pause stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_pause, "toolbar_pause"); + gtk_widget_ref (toolbar_pause); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_pause", toolbar_pause, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_pause); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-playb16x16.xpm"); + toolbar_play = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Play"), + _("Play stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_play, "toolbar_play"); + gtk_widget_ref (toolbar_play); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_play", toolbar_play, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_play); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-stopb16x16.xpm"); + toolbar_stop = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Stop"), + _("Stop stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_stop, "toolbar_stop"); + gtk_widget_ref (toolbar_stop); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_stop", toolbar_stop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_stop); + + tmp_toolbar_icon = create_pixmap (familiar, "familiar-forwardb16x16.xpm"); + toolbar_forward = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Forward"), + _("Forward stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_forward, "toolbar_forward"); + gtk_widget_ref (toolbar_forward); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_forward", toolbar_forward, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_forward); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + tmp_toolbar_icon = create_pixmap (familiar, "vlc16x16.xpm"); + toolbar_about = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("About"), + _("About"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_set_name (toolbar_about, "toolbar_about"); + gtk_widget_ref (toolbar_about); + gtk_object_set_data_full (GTK_OBJECT (familiar), "toolbar_about", toolbar_about, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_about); + + progress = gtk_progress_bar_new (); + gtk_widget_set_name (progress, "progress"); + gtk_widget_ref (progress); + gtk_object_set_data_full (GTK_OBJECT (familiar), "progress", progress, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (progress); + gtk_box_pack_start (GTK_BOX (vbox), progress, FALSE, FALSE, 0); + gtk_progress_set_activity_mode (GTK_PROGRESS (progress), TRUE); + + notebook = gtk_notebook_new (); + gtk_widget_set_name (notebook, "notebook"); + gtk_widget_ref (notebook); + gtk_object_set_data_full (GTK_OBJECT (familiar), "notebook", notebook, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (notebook); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + fixedMedia = gtk_fixed_new (); + gtk_widget_set_name (fixedMedia, "fixedMedia"); + gtk_widget_ref (fixedMedia); + gtk_object_set_data_full (GTK_OBJECT (familiar), "fixedMedia", fixedMedia, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixedMedia); + gtk_container_add (GTK_CONTAINER (notebook), fixedMedia); + + labelUrl = gtk_label_new (_("URL:")); + gtk_widget_set_name (labelUrl, "labelUrl"); + gtk_widget_ref (labelUrl); + gtk_object_set_data_full (GTK_OBJECT (familiar), "labelUrl", labelUrl, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (labelUrl); + gtk_fixed_put (GTK_FIXED (fixedMedia), labelUrl, 4, 8); + gtk_widget_set_uposition (labelUrl, 4, 8); + gtk_widget_set_usize (labelUrl, 38, 18); + + listMedia = gtk_list_new (); + gtk_widget_set_name (listMedia, "listMedia"); + gtk_widget_ref (listMedia); + gtk_object_set_data_full (GTK_OBJECT (familiar), "listMedia", listMedia, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (listMedia); + gtk_fixed_put (GTK_FIXED (fixedMedia), listMedia, 8, 40); + gtk_widget_set_uposition (listMedia, 8, 40); + gtk_widget_set_usize (listMedia, 220, 200); + gtk_tooltips_set_tip (tooltips, listMedia, _("Select multimedia file."), NULL); + gtk_list_set_selection_mode (GTK_LIST (listMedia), GTK_SELECTION_MULTIPLE); + + comboURL = gtk_combo_new (); + gtk_widget_set_name (comboURL, "comboURL"); + gtk_widget_ref (comboURL); + gtk_object_set_data_full (GTK_OBJECT (familiar), "comboURL", comboURL, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (comboURL); + gtk_fixed_put (GTK_FIXED (fixedMedia), comboURL, 46, 6); + gtk_widget_set_uposition (comboURL, 46, 6); + gtk_widget_set_usize (comboURL, 185, 24); + comboURL_items = g_list_append (comboURL_items, (gpointer) _("file://")); + comboURL_items = g_list_append (comboURL_items, (gpointer) _("ftp://localhost")); + comboURL_items = g_list_append (comboURL_items, (gpointer) _("http://localhost")); + comboURL_items = g_list_append (comboURL_items, (gpointer) _("udp://localhost:1234/")); + gtk_combo_set_popdown_strings (GTK_COMBO (comboURL), comboURL_items); + g_list_free (comboURL_items); + + combo_entry1 = GTK_COMBO (comboURL)->entry; + gtk_widget_set_name (combo_entry1, "combo_entry1"); + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (familiar), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + gtk_entry_set_text (GTK_ENTRY (combo_entry1), _("file://")); + + media = gtk_label_new (_("Media")); + gtk_widget_set_name (media, "media"); + gtk_widget_ref (media); + gtk_object_set_data_full (GTK_OBJECT (familiar), "media", media, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (media); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0), media); + + fixedPreferences = gtk_fixed_new (); + gtk_widget_set_name (fixedPreferences, "fixedPreferences"); + gtk_widget_ref (fixedPreferences); + gtk_object_set_data_full (GTK_OBJECT (familiar), "fixedPreferences", fixedPreferences, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixedPreferences); + gtk_container_add (GTK_CONTAINER (notebook), fixedPreferences); + + buttonSave = gtk_button_new_with_label (_("Save")); + gtk_widget_set_name (buttonSave, "buttonSave"); + gtk_widget_ref (buttonSave); + gtk_object_set_data_full (GTK_OBJECT (familiar), "buttonSave", buttonSave, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (buttonSave); + gtk_fixed_put (GTK_FIXED (fixedPreferences), buttonSave, 8, 216); + gtk_widget_set_uposition (buttonSave, 8, 216); + gtk_widget_set_usize (buttonSave, 54, 24); + + buttonApply = gtk_button_new_with_label (_("Apply")); + gtk_widget_set_name (buttonApply, "buttonApply"); + gtk_widget_ref (buttonApply); + gtk_object_set_data_full (GTK_OBJECT (familiar), "buttonApply", buttonApply, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (buttonApply); + gtk_fixed_put (GTK_FIXED (fixedPreferences), buttonApply, 64, 216); + gtk_widget_set_uposition (buttonApply, 64, 216); + gtk_widget_set_usize (buttonApply, 54, 24); + + buttonCancel = gtk_button_new_with_label (_("Cancel")); + gtk_widget_set_name (buttonCancel, "buttonCancel"); + gtk_widget_ref (buttonCancel); + gtk_object_set_data_full (GTK_OBJECT (familiar), "buttonCancel", buttonCancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (buttonCancel); + gtk_fixed_put (GTK_FIXED (fixedPreferences), buttonCancel, 176, 216); + gtk_widget_set_uposition (buttonCancel, 176, 216); + gtk_widget_set_usize (buttonCancel, 54, 24); + + frameDefaultURL = gtk_frame_new (_("Default URL:")); + gtk_widget_set_name (frameDefaultURL, "frameDefaultURL"); + gtk_widget_ref (frameDefaultURL); + gtk_object_set_data_full (GTK_OBJECT (familiar), "frameDefaultURL", frameDefaultURL, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frameDefaultURL); + gtk_fixed_put (GTK_FIXED (fixedPreferences), frameDefaultURL, 8, 8); + gtk_widget_set_uposition (frameDefaultURL, 8, 8); + gtk_widget_set_usize (frameDefaultURL, 220, 60); + + fixed3 = gtk_fixed_new (); + gtk_widget_set_name (fixed3, "fixed3"); + gtk_widget_ref (fixed3); + gtk_object_set_data_full (GTK_OBJECT (familiar), "fixed3", fixed3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixed3); + gtk_container_add (GTK_CONTAINER (frameDefaultURL), fixed3); + + comboDefaultURL = gtk_combo_new (); + gtk_widget_set_name (comboDefaultURL, "comboDefaultURL"); + gtk_widget_ref (comboDefaultURL); + gtk_object_set_data_full (GTK_OBJECT (familiar), "comboDefaultURL", comboDefaultURL, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (comboDefaultURL); + gtk_fixed_put (GTK_FIXED (fixed3), comboDefaultURL, 8, 4); + gtk_widget_set_uposition (comboDefaultURL, 8, 4); + gtk_widget_set_usize (comboDefaultURL, 200, 24); + comboDefaultURL_items = g_list_append (comboDefaultURL_items, (gpointer) _("file://")); + comboDefaultURL_items = g_list_append (comboDefaultURL_items, (gpointer) _("ftp://localhost")); + comboDefaultURL_items = g_list_append (comboDefaultURL_items, (gpointer) _("http://localhost")); + comboDefaultURL_items = g_list_append (comboDefaultURL_items, (gpointer) _("udp://localhost:1234/")); + gtk_combo_set_popdown_strings (GTK_COMBO (comboDefaultURL), comboDefaultURL_items); + g_list_free (comboDefaultURL_items); + + combo_entry2 = GTK_COMBO (comboDefaultURL)->entry; + gtk_widget_set_name (combo_entry2, "combo_entry2"); + gtk_widget_ref (combo_entry2); + gtk_object_set_data_full (GTK_OBJECT (familiar), "combo_entry2", combo_entry2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry2); + gtk_entry_set_text (GTK_ENTRY (combo_entry2), _("file://")); + + frameIP = gtk_frame_new (_("IP version:")); + gtk_widget_set_name (frameIP, "frameIP"); + gtk_widget_ref (frameIP); + gtk_object_set_data_full (GTK_OBJECT (familiar), "frameIP", frameIP, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frameIP); + gtk_fixed_put (GTK_FIXED (fixedPreferences), frameIP, 8, 72); + gtk_widget_set_uposition (frameIP, 8, 72); + gtk_widget_set_usize (frameIP, 220, 60); + + fixed2 = gtk_fixed_new (); + gtk_widget_set_name (fixed2, "fixed2"); + gtk_widget_ref (fixed2); + gtk_object_set_data_full (GTK_OBJECT (familiar), "fixed2", fixed2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixed2); + gtk_container_add (GTK_CONTAINER (frameIP), fixed2); + + rbIPv4 = gtk_radio_button_new_with_label (fixed2_group, _("IPv4")); + fixed2_group = gtk_radio_button_group (GTK_RADIO_BUTTON (rbIPv4)); + gtk_widget_set_name (rbIPv4, "rbIPv4"); + gtk_widget_ref (rbIPv4); + gtk_object_set_data_full (GTK_OBJECT (familiar), "rbIPv4", rbIPv4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (rbIPv4); + gtk_fixed_put (GTK_FIXED (fixed2), rbIPv4, 8, 8); + gtk_widget_set_uposition (rbIPv4, 8, 8); + gtk_widget_set_usize (rbIPv4, 104, 26); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rbIPv4), TRUE); + + rbIPv6 = gtk_radio_button_new_with_label (fixed2_group, _("IPv6")); + fixed2_group = gtk_radio_button_group (GTK_RADIO_BUTTON (rbIPv6)); + gtk_widget_set_name (rbIPv6, "rbIPv6"); + gtk_widget_ref (rbIPv6); + gtk_object_set_data_full (GTK_OBJECT (familiar), "rbIPv6", rbIPv6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (rbIPv6); + gtk_fixed_put (GTK_FIXED (fixed2), rbIPv6, 112, 8); + gtk_widget_set_uposition (rbIPv6, 112, 8); + gtk_widget_set_usize (rbIPv6, 104, 26); + + preferences = gtk_label_new (_("Preference")); + gtk_widget_set_name (preferences, "preferences"); + gtk_widget_ref (preferences); + gtk_object_set_data_full (GTK_OBJECT (familiar), "preferences", preferences, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (preferences); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1), preferences); + + fixedAbout = gtk_fixed_new (); + gtk_widget_set_name (fixedAbout, "fixedAbout"); + gtk_widget_ref (fixedAbout); + gtk_object_set_data_full (GTK_OBJECT (familiar), "fixedAbout", fixedAbout, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (fixedAbout); + gtk_container_add (GTK_CONTAINER (notebook), fixedAbout); + + logo = create_pixmap (familiar, "vlc32x32.xpm"); + gtk_widget_set_name (logo, "logo"); + gtk_widget_ref (logo); + gtk_object_set_data_full (GTK_OBJECT (familiar), "logo", logo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (logo); + gtk_fixed_put (GTK_FIXED (fixedAbout), logo, 8, 0); + gtk_widget_set_uposition (logo, 8, 0); + gtk_widget_set_usize (logo, 50, 50); + + labelVlc = gtk_label_new (_("VideoLAN Client\n for familiar Linux")); + gtk_widget_set_name (labelVlc, "labelVlc"); + gtk_widget_ref (labelVlc); + gtk_object_set_data_full (GTK_OBJECT (familiar), "labelVlc", labelVlc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (labelVlc); + gtk_fixed_put (GTK_FIXED (fixedAbout), labelVlc, 64, 8); + gtk_widget_set_uposition (labelVlc, 64, 8); + gtk_widget_set_usize (labelVlc, 120, 40); + gtk_label_set_line_wrap (GTK_LABEL (labelVlc), TRUE); + + labelCopyright = gtk_label_new (_("(c) 2002, the VideoLAN Team")); + gtk_widget_set_name (labelCopyright, "labelCopyright"); + gtk_widget_ref (labelCopyright); + gtk_object_set_data_full (GTK_OBJECT (familiar), "labelCopyright", labelCopyright, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (labelCopyright); + gtk_fixed_put (GTK_FIXED (fixedAbout), labelCopyright, 16, 56); + gtk_widget_set_uposition (labelCopyright, 16, 56); + gtk_widget_set_usize (labelCopyright, 200, 18); + + labelAuthors = gtk_label_new (_("Authors: The VideoLAN Team, http://www.videolan.org")); + gtk_widget_set_name (labelAuthors, "labelAuthors"); + gtk_widget_ref (labelAuthors); + gtk_object_set_data_full (GTK_OBJECT (familiar), "labelAuthors", labelAuthors, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (labelAuthors); + gtk_fixed_put (GTK_FIXED (fixedAbout), labelAuthors, 16, 80); + gtk_widget_set_uposition (labelAuthors, 16, 80); + gtk_widget_set_usize (labelAuthors, 200, 40); + gtk_label_set_line_wrap (GTK_LABEL (labelAuthors), TRUE); + + labelAbout = gtk_label_new (_("The VideoLAN Client is a MPEG, MPEG 2, MP3, DivX player, that accepts input from local or network sources.")); + gtk_widget_set_name (labelAbout, "labelAbout"); + gtk_widget_ref (labelAbout); + gtk_object_set_data_full (GTK_OBJECT (familiar), "labelAbout", labelAbout, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (labelAbout); + gtk_fixed_put (GTK_FIXED (fixedAbout), labelAbout, 16, 128); + gtk_widget_set_uposition (labelAbout, 16, 128); + gtk_widget_set_usize (labelAbout, 200, 70); + gtk_label_set_justify (GTK_LABEL (labelAbout), GTK_JUSTIFY_LEFT); + gtk_label_set_line_wrap (GTK_LABEL (labelAbout), TRUE); + + about = gtk_label_new (_("About")); + gtk_widget_set_name (about, "about"); + gtk_widget_ref (about); + gtk_object_set_data_full (GTK_OBJECT (familiar), "about", about, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (about); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), about); + + gtk_signal_connect (GTK_OBJECT (familiar), "destroy_event", + GTK_SIGNAL_FUNC (on_familiar_destroy_event), + NULL); + gtk_signal_connect (GTK_OBJECT (familiar), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_open), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_open_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_preferences), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_preferences_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_rewind), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_rewind_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_pause), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_pause_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_play), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_play_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_stop), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_stop_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_forward), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_forward_clicked), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_about), "clicked", + GTK_SIGNAL_FUNC (on_toolbar_about_clicked), + NULL); + + gtk_object_set_data (GTK_OBJECT (familiar), "tooltips", tooltips); + + return familiar; +} + diff --git a/modules/gui/familiar/interface.h b/modules/gui/familiar/interface.h new file mode 100644 index 0000000000..27a3bcf646 --- /dev/null +++ b/modules/gui/familiar/interface.h @@ -0,0 +1,5 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_familiar (void); diff --git a/modules/gui/familiar/support.c b/modules/gui/familiar/support.c new file mode 100644 index 0000000000..4af2461458 --- /dev/null +++ b/modules/gui/familiar/support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("../../share", filename); + } + + if (!found_filename) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning (_("Error loading pixmap file: %s"), found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/modules/gui/familiar/support.h b/modules/gui/familiar/support.h new file mode 100644 index 0000000000..931bc5ad04 --- /dev/null +++ b/modules/gui/familiar/support.h @@ -0,0 +1,61 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/modules/gui/gtk/.cvsignore b/modules/gui/gtk/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/gtk/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/gtk/Makefile b/modules/gui/gtk/Makefile new file mode 100644 index 0000000000..cfab85edbd --- /dev/null +++ b/modules/gui/gtk/Makefile @@ -0,0 +1,4 @@ +COMMON_SOURCES = display.c open.c control.c menu.c playlist.c modules.c preferences.c gtk_callbacks.c + +gtk_SOURCES = gtk.c gtk_interface.c gtk_support.c $(COMMON_SOURCES) +gnome_SOURCES = gnome.c gnome_interface.c gnome_support.c $(COMMON_SOURCES) diff --git a/modules/gui/gtk/common.h b/modules/gui/gtk/common.h new file mode 100644 index 0000000000..35ce29065a --- /dev/null +++ b/modules/gui/gtk/common.h @@ -0,0 +1,101 @@ +/***************************************************************************** + * gtk_common.h: private Gtk+ interface description + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: common.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * Drag'n'drop stuff + *****************************************************************************/ +#define DROP_ACCEPT_TEXT_URI_LIST 0 +#define DROP_ACCEPT_TEXT_PLAIN 1 +#define DROP_ACCEPT_STRING 2 + +#define MAX_ATEXIT 10 + +/***************************************************************************** + * intf_sys_t: description and status of Gtk+ interface + *****************************************************************************/ +struct intf_sys_t +{ + /* special actions */ + vlc_bool_t b_playing; + vlc_bool_t b_popup_changed; /* display menu ? */ + vlc_bool_t b_window_changed; /* window display toggled ? */ + vlc_bool_t b_playlist_changed; /* playlist display toggled ? */ + vlc_bool_t b_slider_free; /* slider status */ + + /* menus handlers */ + vlc_bool_t b_program_update; /* do we need to update programs + menu */ + vlc_bool_t b_title_update; /* do we need to update title menus */ + vlc_bool_t b_chapter_update; /* do we need to update + chapter menus */ + vlc_bool_t b_audio_update; /* do we need to update audio menus */ + vlc_bool_t b_spu_update; /* do we need to update spu menus */ + + /* windows and widgets */ + GtkWidget * p_window; /* main window */ + GtkWidget * p_popup; /* popup menu */ + GtkWidget * p_playwin; /* playlist */ + GtkWidget * p_modules; /* module manager */ + GtkWidget * p_about; /* about window */ + GtkWidget * p_open; /* multiopen window */ + GtkWidget * p_jump; /* jump window */ + + GtkTooltips * p_tooltips; /* tooltips */ + + /* The input thread */ + input_thread_t * p_input; + + /* The slider */ + GtkFrame * p_slider_frame; + GtkAdjustment * p_adj; /* slider adjustment object */ + float f_adj_oldvalue; /* previous value */ + + /* The messages window */ + GtkWidget * p_messages; /* messages window */ + GtkText * p_messages_text; /* messages frame */ + msg_subscription_t* p_sub; /* message bank subscription */ + + /* Playlist management */ + int i_playing; /* playlist selected item */ + + /* The window labels for DVD mode */ + GtkLabel * p_label_title; + GtkLabel * p_label_chapter; + gint i_part; /* current chapter */ + + /* XXX: Ugly kludge, see gtk.c */ + void ( *pf_callback[MAX_ATEXIT] ) ( void ); +}; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +gint GtkModeManage ( intf_thread_t * p_intf ); +void GtkDisplayDate ( GtkAdjustment *p_adj ); + +/***************************************************************************** + * Useful macro + ****************************************************************************/ +#define GtkGetIntf( widget ) __GtkGetIntf( GTK_WIDGET( widget ) ) +void * __GtkGetIntf( GtkWidget * ); + diff --git a/modules/gui/gtk/control.c b/modules/gui/gtk/control.c new file mode 100644 index 0000000000..9f4273bace --- /dev/null +++ b/modules/gui/gtk/control.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * control.c : functions to handle stream control buttons. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: control.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 /* off_t */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "playlist.h" +#include "common.h" + +/**************************************************************************** + * Control functions: this is where the functions are defined + **************************************************************************** + * These functions are button-items callbacks, and are used + * by other callbacks + ****************************************************************************/ +gboolean GtkControlBack( GtkWidget *widget, + gpointer user_data ) +{ + return FALSE; +} + + +gboolean GtkControlStop( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + + return TRUE; +} + + +gboolean GtkControlPlay( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + GtkFileOpenShow( widget, user_data ); + return TRUE; + } + + /* If the playlist is empty, open a file requester instead */ + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + GtkFileOpenShow( widget, user_data ); + } + + return TRUE; +} + + +gboolean GtkControlPause( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + + if( p_intf->p_sys->p_input == NULL ) + { + return FALSE; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); + + return TRUE; +} + + +gboolean GtkControlSlow( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + + if( p_intf->p_sys->p_input == NULL ) + { + return FALSE; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); + + return TRUE; +} + + +gboolean GtkControlFast( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + + if( p_intf->p_sys->p_input == NULL ) + { + return FALSE; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); + + return TRUE; +} + diff --git a/modules/gui/gtk/control.h b/modules/gui/gtk/control.h new file mode 100644 index 0000000000..719908d9f1 --- /dev/null +++ b/modules/gui/gtk/control.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * gtk_control.h: prototypes for control functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: control.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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. + *****************************************************************************/ + +gboolean GtkControlBack ( GtkWidget *, gpointer ); +gboolean GtkControlStop ( GtkWidget *, gpointer ); +gboolean GtkControlPlay ( GtkWidget *, gpointer ); +gboolean GtkControlPause( GtkWidget *, gpointer ); +gboolean GtkControlSlow ( GtkWidget *, gpointer ); +gboolean GtkControlFast ( GtkWidget *, gpointer ); + diff --git a/modules/gui/gtk/display.c b/modules/gui/gtk/display.c new file mode 100644 index 0000000000..dbcc8e9dce --- /dev/null +++ b/modules/gui/gtk/display.c @@ -0,0 +1,294 @@ +/***************************************************************************** + * display.c: Gtk+ tools for main interface + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: display.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "menu.h" +#include "display.h" +#include "common.h" + +/***************************************************************************** + * GtkDisplayDate: display stream date + ***************************************************************************** + * This function displays the current date related to the position in + * the stream. It is called whenever the slider changes its value. + * The lock has to be taken before you call the function. + *****************************************************************************/ +void GtkDisplayDate( GtkAdjustment *p_adj ) +{ + intf_thread_t *p_intf; + + p_intf = gtk_object_get_data( GTK_OBJECT( p_adj ), "p_intf" ); + + if( p_intf->p_sys->p_input ) + { +#define p_area p_intf->p_sys->p_input->stream.p_selected_area + char psz_time[ OFFSETTOTIME_MAX_SIZE ]; + + gtk_frame_set_label( GTK_FRAME( p_intf->p_sys->p_slider_frame ), + input_OffsetToTime( p_intf->p_sys->p_input, psz_time, + ( p_area->i_size * p_adj->value ) / 100 ) ); +#undef p_area + } +} + + +/***************************************************************************** + * GtkModeManage: actualise the aspect of the interface whenever the input + * changes. + ***************************************************************************** + * The lock has to be taken before you call the function. + *****************************************************************************/ +gint GtkModeManage( intf_thread_t * p_intf ) +{ + GtkWidget * p_dvd_box; + GtkWidget * p_file_box; + GtkWidget * p_network_box; + GtkWidget * p_slider; + GtkWidget * p_label; + GtkWidget * p_channel; + vlc_bool_t b_control; + +#define GETWIDGET( ptr, name ) GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( \ + p_intf->p_sys->ptr ) , ( name ) ) ) + /* hide all boxes except default file box */ + p_file_box = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "file_box" ) ); + gtk_widget_hide( GTK_WIDGET( p_file_box ) ); + + p_network_box = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "network_box" ) ); + gtk_widget_hide( GTK_WIDGET( p_network_box ) ); + + p_dvd_box = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "dvd_box" ) ); + gtk_widget_hide( GTK_WIDGET( p_dvd_box ) ); + + /* hide slider */ + p_slider = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "slider_frame" ) ); + gtk_widget_hide( GTK_WIDGET( p_slider ) ); + + /* controls unavailable */ + b_control = 0; + + /* show the box related to current input mode */ + if( p_intf->p_sys->p_input ) + { + switch( p_intf->p_sys->p_input->stream.i_method & 0xf0 ) + { + case INPUT_METHOD_FILE: +//intf_WarnMsg( 2, "intf info: file method" ); + gtk_widget_show( GTK_WIDGET( p_file_box ) ); + p_label = gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), + "label_status" ); + gtk_label_set_text( GTK_LABEL( p_label ), + p_intf->p_sys->p_input->psz_source ); + break; + case INPUT_METHOD_DISC: +//intf_WarnMsg( 2, "intf info: disc method" ); + gtk_widget_show( GTK_WIDGET( p_dvd_box ) ); + break; + case INPUT_METHOD_NETWORK: +//intf_WarnMsg( 2, "intf info: network method" ); + gtk_widget_show( GTK_WIDGET( p_network_box ) ); + p_label = gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), + "network_address_label" ); + gtk_label_set_text( GTK_LABEL( p_label ), + p_intf->p_sys->p_input->psz_source ); + p_channel = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "network_channel_box" ) ); + if( config_GetInt( p_intf, "network-channel" ) ) + { + gtk_widget_show( GTK_WIDGET( p_channel ) ); + } + else + { + gtk_widget_hide( GTK_WIDGET( p_channel ) ); + } + + break; + default: + msg_Warn( p_intf, "cannot determine input method" ); + gtk_widget_show( GTK_WIDGET( p_file_box ) ); + p_label = gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), + "label_status" ); + gtk_label_set_text( GTK_LABEL( p_label ), + p_intf->p_sys->p_input->psz_source ); + break; + } + + /* initialize and show slider for seekable streams */ + if( p_intf->p_sys->p_input->stream.b_seekable ) + { + p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue = 0; + gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), + "value_changed" ); + gtk_widget_show( GTK_WIDGET( p_slider ) ); + } + + /* control buttons for free pace streams */ + b_control = p_intf->p_sys->p_input->stream.b_pace_control; + + /* get ready for menu regeneration */ + p_intf->p_sys->b_program_update = 1; + p_intf->p_sys->b_title_update = 1; + p_intf->p_sys->b_chapter_update = 1; + p_intf->p_sys->b_audio_update = 1; + p_intf->p_sys->b_spu_update = 1; + p_intf->p_sys->i_part = 0; + + p_intf->p_sys->p_input->stream.b_changed = 0; + msg_Dbg( p_intf, "stream has changed, refreshing interface" ); + } + else + { + if( config_GetInt( p_intf, "network-channel" ) ) + { + gtk_widget_show( GTK_WIDGET( p_network_box ) ); + + p_channel = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "network_channel_box" ) ); + gtk_widget_show( GTK_WIDGET( p_channel ) ); + } + else + { +//intf_WarnMsg( 2, "intf info: default to file method" ); + /* default mode */ + p_label = gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_window ), "label_status" ); + gtk_label_set_text( GTK_LABEL( p_label ), "" ); + gtk_widget_show( GTK_WIDGET( p_file_box ) ); + } + + /* unsensitize menus */ + gtk_widget_set_sensitive( GETWIDGET(p_window,"menubar_program"), + FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_window,"menubar_title"), FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_window,"menubar_chapter"), + FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_window,"menubar_audio"), FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_window,"menubar_subpictures"), + FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_popup,"popup_navigation"), + FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_popup,"popup_audio"), FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_popup,"popup_subpictures"), + FALSE ); + } + + /* set control items */ + gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_back"), FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_eject"), !b_control); + gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_pause"), b_control ); + gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_slow"), b_control ); + gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_fast"), b_control ); + gtk_widget_set_sensitive( GETWIDGET(p_popup, "popup_back"), FALSE ); + gtk_widget_set_sensitive( GETWIDGET(p_popup, "popup_pause"), b_control ); + gtk_widget_set_sensitive( GETWIDGET(p_popup, "popup_slow"), b_control ); + gtk_widget_set_sensitive( GETWIDGET(p_popup, "popup_fast"), b_control ); + +#undef GETWIDGET + return TRUE; +} + +/***************************************************************************** + * GtkHideTooltips: show or hide the tooltips depending on the configuration + * option gnome-tooltips + *****************************************************************************/ +void GtkHideTooltips( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = vlc_object_find( p_this, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + + if( !p_intf ) + { + return; + } + + if( config_GetInt( p_this, "gnome-tooltips" ) ) + { + gtk_tooltips_enable( p_intf->p_sys->p_tooltips ); + } + else + { + gtk_tooltips_disable( p_intf->p_sys->p_tooltips ); + } + + vlc_object_release( p_intf ); +} + +#ifdef MODULE_NAME_IS_gnome +/***************************************************************************** + * GtkHideToolbartext: show or hide the tooltips depending on the + * configuration option gnome-toolbartext + ***************************************************************************** + * FIXME: GNOME only because of missing icons in gtk interface + *****************************************************************************/ +void GtkHideToolbarText( vlc_object_t *p_this ) +{ + GtkToolbarStyle style; + GtkToolbar * p_toolbar; + + intf_thread_t *p_intf = vlc_object_find( p_this, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + + if( !p_intf ) + { + return; + } + + style = config_GetInt( p_this, "gnome-toolbartext" ) + ? GTK_TOOLBAR_BOTH + : GTK_TOOLBAR_ICONS; + + p_toolbar = GTK_TOOLBAR(lookup_widget( p_intf->p_sys->p_window, + "toolbar" )); + gtk_toolbar_set_style( p_toolbar, style ); + + vlc_object_release( p_intf ); +} +#endif diff --git a/modules/gui/gtk/display.h b/modules/gui/gtk/display.h new file mode 100644 index 0000000000..e73d774d66 --- /dev/null +++ b/modules/gui/gtk/display.h @@ -0,0 +1,33 @@ +/***************************************************************************** + * gtk_dsiplay.h: Gtk+ tools for main interface. + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: display.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 + *****************************************************************************/ + +gint GtkModeManage ( intf_thread_t * p_intf ); +void GtkDisplayDate ( GtkAdjustment *p_adj ); +void GtkHideTooltips ( vlc_object_t * ); +void GtkHideToolbarText ( vlc_object_t * ); + diff --git a/modules/gui/gtk/gnome.c b/modules/gui/gtk/gnome.c new file mode 100644 index 0000000000..8b58538457 --- /dev/null +++ b/modules/gui/gtk/gnome.c @@ -0,0 +1,512 @@ +/***************************************************************************** + * gnome.c : Gnome plugin for vlc + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * $Id: gnome.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include /* ENOMEM */ +#include /* strerror() */ +#include + +#include +#include + +#include + +#include "gnome_callbacks.h" +#include "gnome_interface.h" +#include "gnome_support.h" +#include "display.h" +#include "common.h" + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static void Run ( intf_thread_t * ); +static gint Manage ( gpointer ); + +/***************************************************************************** + * Local variables (mutex-protected). + *****************************************************************************/ +static void ** pp_global_data = NULL; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define TOOLTIPS_TEXT N_("show tooltips") +#define TOOLTIPS_LONGTEXT N_("Show tooltips for configuration options.") + +#define TOOLBAR_TEXT N_("show text on toolbar buttons") +#define TOOLBAR_LONGTEXT N_("Show the text below icons on the toolbar.") + +#define PREFS_MAXH_TEXT N_("maximum height for the configuration windows") +#define PREFS_MAXH_LONGTEXT N_( \ + "You can set the maximum height that the configuration windows in the " \ + "preferences menu will occupy.") + +vlc_module_begin(); +#ifdef WIN32 + int i = 90; +#else + int i = getenv( "DISPLAY" ) == NULL ? 15 : 100; +#endif + pp_global_data = p_module->p_vlc->pp_global_data; + + add_category_hint( N_("Miscellaneous"), NULL ); + add_bool( "gnome-tooltips", 1, GtkHideTooltips, + TOOLTIPS_TEXT, TOOLTIPS_LONGTEXT ); + add_bool( "gnome-toolbartext", 1, GtkHideToolbarText, TOOLBAR_TEXT, + TOOLBAR_LONGTEXT ); + add_integer( "gnome-prefs-maxh", 480, NULL, + PREFS_MAXH_TEXT, PREFS_MAXH_LONGTEXT ); + + set_description( _("GNOME interface module") ); + set_capability( "interface", i ); + set_callbacks( Open, Close ); + set_program( "gnome-vlc" ); +vlc_module_end(); + +/***************************************************************************** + * g_atexit: kludge to avoid the Gnome thread to segfault at exit + ***************************************************************************** + * gtk_init() makes several calls to g_atexit() which calls atexit() to + * register tidying callbacks to be called at program exit. Since the Gnome + * plugin is likely to be unloaded at program exit, we have to export this + * symbol to intercept the g_atexit() calls. Talk about crude hack. + *****************************************************************************/ +void g_atexit( GVoidFunc func ) +{ + intf_thread_t *p_intf; + + int i_dummy; + + if( pp_global_data == NULL ) + { + atexit( func ); + return; + } + + p_intf = (intf_thread_t *)*pp_global_data; + if( p_intf == NULL ) + { + return; + } + + for( i_dummy = 0; + i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL; + i_dummy++ ) + { + ; + } + + if( i_dummy >= MAX_ATEXIT - 1 ) + { + msg_Err( p_intf, "too many atexit() callbacks to register" ); + return; + } + + p_intf->p_sys->pf_callback[i_dummy] = func; + p_intf->p_sys->pf_callback[i_dummy + 1] = NULL; +} + +/***************************************************************************** + * Open: initialize and create window + *****************************************************************************/ +static int Open( 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 ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + p_intf->pf_run = Run; + + p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + + /* Initialize Gnome thread */ + p_intf->p_sys->b_playing = 0; + p_intf->p_sys->b_popup_changed = 0; + p_intf->p_sys->b_window_changed = 0; + p_intf->p_sys->b_playlist_changed = 0; + + p_intf->p_sys->p_input = NULL; + p_intf->p_sys->i_playing = -1; + p_intf->p_sys->b_slider_free = 1; + + p_intf->p_sys->pf_callback[0] = NULL; + + p_intf->p_sys->i_part = 0; + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface window + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: Gnome thread + ***************************************************************************** + * this part of the interface is in a separate thread so that we can call + * gtk_main() from within it without annoying the rest of the program. + * XXX: the approach may look kludgy, and probably is, but I could not find + * a better way to dynamically load a Gnome interface at runtime. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + /* gnome_init needs to know the command line. We don't care, so we + * give it an empty one */ + char *p_args[] = { "" }; + int i_args = 1; + int i_dummy; + + /* The data types we are allowed to receive */ + static GtkTargetEntry target_table[] = + { + { "STRING", 0, DROP_ACCEPT_STRING }, + { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST }, + { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN } + }; + + /* Initialize Gnome */ + + /* gnome_init will register stuff with g_atexit, so we need to take + * the global lock if we want to be able to intercept the calls */ + vlc_mutex_lock( p_intf->p_vlc->p_global_lock ); + *p_intf->p_vlc->pp_global_data = p_intf; + gnome_init( p_intf->p_vlc->psz_object_name, VERSION, i_args, p_args ); + vlc_mutex_unlock( p_intf->p_vlc->p_global_lock ); + + /* Create some useful widgets that will certainly be used */ + p_intf->p_sys->p_window = create_intf_window( ); + p_intf->p_sys->p_popup = create_intf_popup( ); + p_intf->p_sys->p_playwin = create_intf_playlist(); + p_intf->p_sys->p_messages = create_intf_messages(); + + /* Set the title of the main window */ + gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window), + VOUT_TITLE " (Gnome interface)"); + + /* Accept file drops on the main window */ + gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ), + GTK_DEST_DEFAULT_ALL, target_table, + 1, GDK_ACTION_COPY ); + /* Accept file drops on the playlist window */ + gtk_drag_dest_set( GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist") ), + GTK_DEST_DEFAULT_ALL, target_table, + 1, GDK_ACTION_COPY ); + + /* Get the slider object */ + p_intf->p_sys->p_slider_frame = gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_window ), "slider_frame" ); + + /* Configure the log window */ + p_intf->p_sys->p_messages_text = GTK_TEXT( gtk_object_get_data( + GTK_OBJECT(p_intf->p_sys->p_messages ), "messages_textbox" ) ); + gtk_text_set_line_wrap( p_intf->p_sys->p_messages_text, TRUE); + gtk_text_set_word_wrap( p_intf->p_sys->p_messages_text, FALSE); + + /* Get the interface labels */ + #define P_LABEL( name ) GTK_LABEL( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), name ) ) + p_intf->p_sys->p_label_title = P_LABEL( "title_label" ); + p_intf->p_sys->p_label_chapter = P_LABEL( "chapter_label" ); + #undef P_LABEL + + /* Connect the date display to the slider */ + #define P_SLIDER GTK_RANGE( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), "slider" ) ) + p_intf->p_sys->p_adj = gtk_range_get_adjustment( P_SLIDER ); + + gtk_signal_connect ( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed", + GTK_SIGNAL_FUNC( GtkDisplayDate ), NULL ); + p_intf->p_sys->f_adj_oldvalue = 0; + #undef P_SLIDER + + p_intf->p_sys->p_tooltips = gtk_tooltips_new(); + + /* We don't create these ones yet because we perhaps won't need them */ + p_intf->p_sys->p_about = NULL; + p_intf->p_sys->p_modules = NULL; + p_intf->p_sys->p_open = NULL; + p_intf->p_sys->p_jump = NULL; + + /* Hide tooltips if the option is set */ + if( !config_GetInt( p_intf, "gnome-tooltips" ) ) + { + gtk_tooltips_disable( p_intf->p_sys->p_tooltips ); + } + + /* Hide toolbar text of the option is set */ + if( !config_GetInt( p_intf, "gnome-toolbartext" ) ) + { + gtk_toolbar_set_style( + GTK_TOOLBAR(lookup_widget( p_intf->p_sys->p_window, "toolbar" )), + GTK_TOOLBAR_ICONS ); + } + + /* Store p_intf to keep an eye on it */ + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_playwin ), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_messages ), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_adj), + "p_intf", p_intf ); + + /* Show the control window */ + gtk_widget_show( p_intf->p_sys->p_window ); + + /* Sleep to avoid using all CPU - since some interfaces needs to access + * keyboard events, a 100ms delay is a good compromise */ + i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, Manage, p_intf ); + + /* Enter gnome mode */ + gtk_main(); + + /* Remove the timeout */ + gtk_timeout_remove( i_dummy ); + + /* Destroy the Tooltips structure */ + gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_tooltips) ); + + /* Get rid of stored callbacks so we can unload the plugin */ + for( i_dummy = 0; + i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL; + i_dummy++ ) + { + p_intf->p_sys->pf_callback[i_dummy](); + } +} + +/* following functions are local */ + +/***************************************************************************** + * Manage: manage main thread messages + ***************************************************************************** + * In this function, called approx. 10 times a second, we check what the + * main program wanted to tell us. + *****************************************************************************/ +static gint Manage( gpointer p_data ) +{ +#define p_intf ((intf_thread_t *)p_data) + int i_start, i_stop; + + vlc_mutex_lock( &p_intf->change_lock ); + + /* If the "display popup" flag has changed */ + if( p_intf->b_menu_change ) + { + if( !GTK_IS_WIDGET( p_intf->p_sys->p_popup ) ) + { + p_intf->p_sys->p_popup = create_intf_popup(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_popup ), + "p_popup", p_intf ); + } + + gnome_popup_menu_do_popup( p_intf->p_sys->p_popup, + NULL, NULL, NULL, NULL ); + p_intf->b_menu_change = 0; + } + + /* Update the log window */ + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + i_stop = *p_intf->p_sys->p_sub->pi_stop; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + + if( p_intf->p_sys->p_sub->i_start != i_stop ) + { + static GdkColor white = { 0, 0xffff, 0xffff, 0xffff }; + static GdkColor gray = { 0, 0xaaaa, 0xaaaa, 0xaaaa }; + static GdkColor yellow = { 0, 0xffff, 0xffff, 0x6666 }; + static GdkColor red = { 0, 0xffff, 0x6666, 0x6666 }; + + static const char * ppsz_type[4] = { ": ", " error: ", " warning: ", + " debug: " }; + static GdkColor * pp_color[4] = { &white, &red, &yellow, &gray }; + + for( i_start = p_intf->p_sys->p_sub->i_start; + i_start != i_stop; + i_start = (i_start+1) % VLC_MSG_QSIZE ) + { + /* Append all messages to log window */ + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, p_intf->p_sys->p_sub->p_msg[i_start].psz_module, -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, ppsz_type[p_intf->p_sys->p_sub->p_msg[i_start].i_type], + -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, + pp_color[p_intf->p_sys->p_sub->p_msg[i_start].i_type], NULL, + p_intf->p_sys->p_sub->p_msg[i_start].psz_msg, -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, "\n", -1 ); + } + + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + p_intf->p_sys->p_sub->i_start = i_start; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + + gtk_text_set_point( p_intf->p_sys->p_messages_text, + gtk_text_get_length( p_intf->p_sys->p_messages_text ) ); + } + + /* Update the playlist */ + GtkPlayListManage( p_intf ); + + /* Update the input */ + if( p_intf->p_sys->p_input != NULL ) + { + if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + } + + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + + if( p_intf->p_sys->p_input ) + { + input_thread_t *p_input = p_intf->p_sys->p_input; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( !p_input->b_die ) + { + /* New input or stream map change */ + if( p_input->stream.b_changed ) + { + GtkModeManage( p_intf ); + GtkSetupMenus( p_intf ); + p_intf->p_sys->b_playing = 1; + } + + /* Manage the slider */ + if( p_input->stream.b_seekable && p_intf->p_sys->b_playing ) + { + float newvalue = p_intf->p_sys->p_adj->value; + +#define p_area p_input->stream.p_selected_area + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( newvalue == p_intf->p_sys->f_adj_oldvalue ) + { + /* Update the value */ + p_intf->p_sys->p_adj->value = + p_intf->p_sys->f_adj_oldvalue = + ( 100. * p_area->i_tell ) / p_area->i_size; + + gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), + "value_changed" ); + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else if( p_intf->p_sys->b_slider_free ) + { + if( newvalue > 0. && newvalue < 100. ) + { + off_t i_seek = ( newvalue * p_area->i_size ) / 100; + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + input_Seek( p_input, i_seek, INPUT_SEEK_SET ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + } + + /* Update the old value */ + p_intf->p_sys->f_adj_oldvalue = newvalue; + } +#undef p_area + } + + if( p_intf->p_sys->i_part != + p_input->stream.p_selected_area->i_part ) + { + p_intf->p_sys->b_chapter_update = 1; + GtkSetupMenus( p_intf ); + } + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + else if( p_intf->p_sys->b_playing && !p_intf->b_die ) + { + GtkModeManage( p_intf ); + p_intf->p_sys->b_playing = 0; + } + + if( p_intf->b_die ) + { + vlc_mutex_unlock( &p_intf->change_lock ); + + /* Prepare to die, young Skywalker */ + gtk_main_quit(); + + /* Just in case */ + return( FALSE ); + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + return( TRUE ); + +#undef p_intf +} + diff --git a/modules/gui/gtk/gnome.glade b/modules/gui/gtk/gnome.glade new file mode 100644 index 0000000000..1d101e13b3 --- /dev/null +++ b/modules/gui/gtk/gnome.glade @@ -0,0 +1,3507 @@ + + + + + VideoLAN Client + vlc + + + pixmaps + C + True + True + False + False + False + gnome_interface.c + gnome_interface.h + gnome_callbacks.c + gnome_callbacks.h + gnome_support.c + gnome_support.h + + + + GnomeApp + intf_window + + delete_event + GtkWindowDelete + Sat, 19 May 2001 03:20:57 GMT + + + drag_data_received + GtkWindowDrag + Sat, 19 May 2001 02:30:24 GMT + + VideoLAN Client + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + True + True + + + GnomeDock + GnomeApp:dock + dockitem + True + + 0 + True + True + + + + GnomeDockItem + dockitem_menubar + 2 + GNOME_DOCK_TOP + 0 + 0 + 0 + False + True + False + True + False + GTK_SHADOW_OUT + + + GtkMenuBar + menubar + 2 + GTK_SHADOW_NONE + + + GtkMenuItem + menubar_file + GNOMEUIINFO_MENU_FILE_TREE + + + GtkMenu + menubar_file_menu + + + GtkPixmapMenuItem + menubar_open + Open a File + + activate + GtkFileOpenShow + Sat, 19 May 2001 16:27:02 GMT + + + False + GNOME_STOCK_MENU_OPEN + + + + GtkPixmapMenuItem + menubar_disc + Open a DVD or VCD + + activate + GtkDiscOpenShow + Sat, 19 May 2001 16:27:10 GMT + + + False + GNOME_STOCK_MENU_CDROM + + + + GtkPixmapMenuItem + menubar_network + Select a Network Stream + + activate + GtkNetworkOpenShow + Fri, 21 Dec 2001 13:11:28 GMT + + + False + GNOME_STOCK_MENU_REFRESH + + + + GtkMenuItem + separator1 + False + + + + GtkPixmapMenuItem + menubar_eject + Eject disc + + activate + GtkDiscEject + Fri, 21 Dec 2001 13:11:28 GMT + + + False + GNOME_STOCK_MENU_TOP + + + + GtkMenuItem + separator15 + False + + + + GtkPixmapMenuItem + menubar_close + + activate + GtkClose + Mon, 15 Jul 2002 09:14:55 GMT + + GNOMEUIINFO_MENU_CLOSE_ITEM + + + + GtkPixmapMenuItem + menubar_exit + + activate + GtkExit + Sat, 19 May 2001 16:27:52 GMT + + GNOMEUIINFO_MENU_EXIT_ITEM + + + + + + GtkMenuItem + menubar_view + GNOMEUIINFO_MENU_VIEW_TREE + + + GtkMenu + menubar_view_menu + + + GtkMenuItem + menubar_hide_interface + + activate + GtkWindowToggle + Sat, 19 May 2001 16:28:06 GMT + + + False + + + + GtkMenuItem + menubar_fullscreen + + activate + GtkFullscreen + Sat, 19 May 2001 16:28:15 GMT + + + False + + + + GtkMenuItem + separator9 + False + + + + GtkMenuItem + menubar_program + False + Choose the program + + False + + + + GtkMenuItem + menubar_title + False + Choose title + + False + + + + GtkMenuItem + menubar_chapter + False + Choose chapter + + False + + + + GtkMenuItem + separator7 + False + + + + GtkPixmapMenuItem + menubar_playlist + Open the playlist window + + activate + GtkPlaylistShow + Sat, 19 May 2001 16:28:41 GMT + + + False + GNOME_STOCK_MENU_INDEX + + + + GtkPixmapMenuItem + menubar_modules + False + Open the module manager + + activate + GtkModulesShow + Sat, 19 May 2001 16:28:53 GMT + + + False + GNOME_STOCK_MENU_ATTACH + + + + GtkMenuItem + menubar_messages + Open the messages window + + activate + GtkMessagesShow + Wed, 20 Feb 2002 05:43:55 GMT + + + False + + + + + + GtkMenuItem + menubar_settings + GNOMEUIINFO_MENU_SETTINGS_TREE + + + GtkMenu + menubar_settings_menu + + + GtkMenuItem + menubar_audio + False + Select audio channel + + False + + + + GtkMenuItem + menubar_subpictures + False + Select subtitles channel + + False + + + + GtkMenuItem + separator5 + False + + + + GtkPixmapMenuItem + menubar_preferences + + activate + GtkPreferencesShow + Sat, 19 May 2001 16:29:03 GMT + + GNOMEUIINFO_MENU_PREFERENCES_ITEM + + + + + + GtkMenuItem + menubar_help + GNOMEUIINFO_MENU_HELP_TREE + + + GtkMenu + menubar_help_menu + + + GtkPixmapMenuItem + menubar_about + + activate + GtkAboutShow + Sat, 19 May 2001 16:29:19 GMT + + GNOMEUIINFO_MENU_ABOUT_ITEM + + + + + + + + GnomeDockItem + dockitem_toolbar + 2 + GNOME_DOCK_TOP + 1 + 0 + 2 + False + True + False + False + False + GTK_SHADOW_OUT + + + GtkToolbar + toolbar + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + 16 + GTK_TOOLBAR_SPACE_LINE + GTK_RELIEF_NONE + True + + + GtkButton + Toolbar:button + toolbar_file + Open a File + + clicked + GtkFileOpenShow + Sat, 19 May 2001 03:14:43 GMT + + + GNOME_STOCK_PIXMAP_OPEN + + + + GtkButton + Toolbar:button + toolbar_disc + Open a DVD or VCD + + clicked + GtkDiscOpenShow + Sat, 19 May 2001 03:14:38 GMT + + + GNOME_STOCK_PIXMAP_CDROM + + + + GtkButton + Toolbar:button + toolbar_network + Select a Network Stream + + clicked + GtkNetworkOpenShow + Sat, 19 May 2001 03:14:33 GMT + + + GNOME_STOCK_PIXMAP_REFRESH + + + + GtkButton + Toolbar:button + toolbar_sat + Open a Satellite Card + + clicked + GtkSatOpenShow + Mon, 25 Mar 2002 01:02:49 GMT + + + GNOME_STOCK_PIXMAP_MIC + + + + GtkButton + Toolbar:button + toolbar_back + False + Go Backward + + clicked + GtkControlBack + Sat, 19 May 2001 03:14:27 GMT + + + GNOME_STOCK_PIXMAP_BACK + + True + + + + + GtkButton + Toolbar:button + toolbar_stop + Stop Stream + + clicked + GtkControlStop + Sat, 19 May 2001 03:14:22 GMT + + + GNOME_STOCK_PIXMAP_STOP + + + + GtkButton + Toolbar:button + toolbar_eject + Eject disc + + clicked + GtkDiscEject + Fri, 21 Dec 2001 15:24:18 GMT + + + GNOME_STOCK_PIXMAP_TOP + + + + GtkButton + Toolbar:button + toolbar_play + Play Stream + + clicked + GtkControlPlay + Wed, 05 Jun 2002 15:10:19 GMT + + + GNOME_STOCK_PIXMAP_FORWARD + + + + GtkButton + Toolbar:button + toolbar_pause + False + Pause Stream + + clicked + GtkControlPause + Sat, 19 May 2001 03:14:05 GMT + + + GNOME_STOCK_PIXMAP_BOTTOM + + + + GtkButton + Toolbar:button + toolbar_slow + False + Play Slower + + clicked + GtkControlSlow + Sat, 19 May 2001 03:13:58 GMT + + + GNOME_STOCK_PIXMAP_TIMER_STOP + + True + + + + + GtkButton + Toolbar:button + toolbar_fast + False + Play Faster + + clicked + GtkControlFast + Sat, 19 May 2001 03:13:53 GMT + + + GNOME_STOCK_PIXMAP_TIMER + + + + GtkButton + Toolbar:button + toolbar_playlist + Open Playlist + + clicked + GtkPlaylistShow + Sat, 19 May 2001 03:13:48 GMT + + + GNOME_STOCK_PIXMAP_INDEX + + + + GtkButton + Toolbar:button + toolbar_prev + Previous File + + clicked + GtkPlaylistPrev + Sat, 19 May 2001 03:13:44 GMT + + + GNOME_STOCK_PIXMAP_FIRST + + + + GtkButton + Toolbar:button + toolbar_next + Next File + + clicked + GtkPlaylistNext + Sat, 19 May 2001 03:13:40 GMT + + + GNOME_STOCK_PIXMAP_LAST + + + + + + GtkVBox + GnomeDock:contents + vbox8 + False + 0 + + + GtkFrame + slider_frame + False + + 0.05 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHScale + slider + True + + button_press_event + GtkSliderPress + Sat, 19 May 2001 03:12:57 GMT + + + button_release_event + GtkSliderRelease + Sat, 19 May 2001 03:13:00 GMT + + False + GTK_POS_TOP + 3 + GTK_UPDATE_CONTINUOUS + 0 + 0 + 100 + 1 + 6.25 + 0 + + + + + GtkHBox + file_box + False + 0 + + 0 + True + True + + + + GtkLabel + label_status + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + + GtkHBox + dvd_box + False + False + 0 + + 0 + True + True + + + + GtkLabel + label21 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + False + + + + + GtkHBox + title_chapter_box + False + 10 + + 0 + True + False + + + + GtkLabel + label19 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + title_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkButton + button_title_prev + Select previous title + True + + clicked + GtkTitlePrev + Sat, 19 May 2001 03:13:28 GMT + + GNOME_STOCK_BUTTON_PREV + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + GtkButton + button_title_next + True + + clicked + GtkTitleNext + Sat, 19 May 2001 03:13:23 GMT + + GNOME_STOCK_BUTTON_NEXT + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + + GtkVSeparator + vseparator1 + + 0 + False + False + + + + + GtkHBox + dvd_chapter_box + False + 10 + + 0 + True + False + + + + GtkLabel + label20 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkLabel + chapter_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkButton + button_chapter_prev + Select previous chapter + True + + clicked + GtkChapterPrev + Tue, 29 May 2001 13:13:41 GMT + + GNOME_STOCK_BUTTON_DOWN + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + GtkButton + button_chapter_next + Select next chapter + True + + clicked + GtkChapterNext + Sat, 19 May 2001 03:13:08 GMT + + GNOME_STOCK_BUTTON_UP + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + + + GtkHBox + network_box + False + True + 0 + + 0 + False + False + + + + GtkLabel + network_address_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkHBox + network_channel_box + False + 0 + + 0 + False + False + + + + GtkLabel + label_network + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + True + False + + + + + GtkSpinButton + network_channel_spinbutton + True + + activate + GtkNetworkJoin + Wed, 30 May 2001 02:28:48 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 100 + 1 + 10 + 10 + + 5 + False + True + + + + + GtkButton + network_channel_go_button + True + + clicked + GtkChannelGo + Wed, 30 May 2001 02:38:25 GMT + + + GTK_RELIEF_NONE + + 0 + False + False + + + + + + + + + GnomeAppBar + GnomeApp:appbar + appbar + False + True + + 0 + True + True + + + + + + GtkMenu + intf_popup + + + GtkPixmapMenuItem + popup_play + + activate + GtkControlPlay + Sat, 19 May 2001 16:16:58 GMT + + + False + GNOME_STOCK_MENU_FORWARD + + + + GtkPixmapMenuItem + popup_pause + + activate + GtkControlPause + Sat, 19 May 2001 16:17:31 GMT + + + False + GNOME_STOCK_MENU_BOTTOM + + + + GtkPixmapMenuItem + popup_stop + + activate + GtkControlStop + Sat, 19 May 2001 16:18:10 GMT + + + False + GNOME_STOCK_MENU_STOP + + + + GtkPixmapMenuItem + popup_back + False + + activate + GtkControlBack + Sat, 19 May 2001 16:18:21 GMT + + + False + GNOME_STOCK_MENU_BACK + + + + GtkPixmapMenuItem + popup_slow + + activate + GtkControlSlow + Sat, 19 May 2001 16:18:29 GMT + + + False + GNOME_STOCK_MENU_TIMER_STOP + + + + GtkPixmapMenuItem + popup_fast + + activate + GtkControlFast + Sat, 19 May 2001 16:18:37 GMT + + + False + GNOME_STOCK_MENU_TIMER + + + + GtkMenuItem + separator3 + False + + + + GtkMenuItem + popup_interface_toggle + + activate + GtkWindowToggle + Sat, 19 May 2001 16:18:51 GMT + + + False + + + + GtkMenuItem + popup_fullscreen + Toggle fullscreen mode + + activate + GtkFullscreen + Sat, 19 May 2001 16:19:07 GMT + + + False + + + + GtkMenuItem + separator8 + False + + + + GtkMenuItem + popup_next + + activate + GtkPlaylistNext + Sat, 19 May 2001 16:19:18 GMT + + + False + + + + GtkMenuItem + popup_prev + + activate + GtkPlaylistPrev + Sat, 19 May 2001 16:19:26 GMT + + + False + + + + GtkPixmapMenuItem + popup_jump + Got directly so specified point + + activate + GtkJumpShow + Sat, 19 May 2001 16:34:46 GMT + + + False + GNOME_STOCK_MENU_JUMP_TO + + + + GtkMenuItem + popup_program + False + Switch program + + False + + + + GtkPixmapMenuItem + popup_navigation + False + Navigate through titles and chapters + + False + GNOME_STOCK_MENU_SEARCH + + + + GtkPixmapMenuItem + popup_audio + False + Select audio channel + + False + GNOME_STOCK_MENU_VOLUME + + + + GtkPixmapMenuItem + popup_subpictures + False + Select subtitles channel + + False + GNOME_STOCK_MENU_FONT + + + + GtkMenuItem + separator13 + False + + + + GtkMenuItem + popup_file + GNOMEUIINFO_MENU_FILE_TREE + + + GtkMenu + popup_file_menu + + + GtkPixmapMenuItem + popup_open + Open a File + + activate + GtkFileOpenShow + Sat, 19 May 2001 16:20:08 GMT + + + False + GNOME_STOCK_MENU_OPEN + + + + GtkPixmapMenuItem + popup_disc + Open a DVD or VCD + + activate + GtkDiscOpenShow + Sat, 19 May 2001 16:20:44 GMT + + + False + GNOME_STOCK_MENU_CDROM + + + + GtkPixmapMenuItem + popup_network + Select a Network Stream + + activate + GtkNetworkOpenShow + Sat, 19 May 2001 16:20:54 GMT + + + False + GNOME_STOCK_MENU_REFRESH + + + + GtkMenuItem + separator4 + False + + + + GtkPixmapMenuItem + popup_about + + activate + GtkAboutShow + Sat, 19 May 2001 16:21:02 GMT + + GNOMEUIINFO_MENU_ABOUT_ITEM + + + + + + GtkMenuItem + popup_playlist + + activate + GtkPlaylistShow + Sat, 19 May 2001 16:21:14 GMT + + + False + + + + GtkPixmapMenuItem + popup_preferences + + activate + GtkPreferencesShow + Sat, 19 May 2001 16:21:25 GMT + + GNOMEUIINFO_MENU_PREFERENCES_ITEM + + + + GtkMenuItem + separator2 + False + + + + GtkPixmapMenuItem + popup_exit + + activate + GtkExit + Sat, 19 May 2001 16:21:45 GMT + + GNOMEUIINFO_MENU_EXIT_ITEM + + + + + GnomeAbout + intf_about + False + (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team + the VideoLAN team <videolan@videolan.org> +http://www.videolan.org/ + + This is the VideoLAN client, a DVD and MPEG player. It can play MPEG and MPEG 2 files from a file or from a network source. + + + + GnomeDialog + intf_open + Open Stream + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + True + False + False + False + False + True + + + GtkVBox + GnomeDialog:vbox + dialog-vbox5 + False + 8 + + 4 + True + True + + + + GtkHButtonBox + GnomeDialog:action_area + dialog-action_area5 + GTK_BUTTONBOX_END + 8 + 85 + 27 + 7 + 0 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + button1 + True + True + + clicked + GtkOpenOk + Thu, 11 Jul 2002 09:10:19 GMT + + GNOME_STOCK_BUTTON_OK + + + + GtkButton + button3 + True + True + + clicked + GtkOpenCancel + Thu, 11 Jul 2002 09:10:29 GMT + + GNOME_STOCK_BUTTON_CANCEL + + + + + GtkVBox + open_vbox + False + 5 + + 0 + True + True + + + + GtkFrame + frame10 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + False + True + + + + GtkHBox + hbox21 + 5 + False + 5 + + + GtkHBox + hbox22 + False + 0 + + 0 + False + True + + + + GtkLabel + label34 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + + GtkCombo + combo2 + False + True + False + True + False + + + 0 + True + True + + + + GtkEntry + GtkCombo:entry + entry_open + True + True + True + 0 + + + + + + + + GtkLabel + label36 + + GTK_JUSTIFY_LEFT + False + 0 + 1 + 0 + 0 + + 0 + True + True + + + + + GtkNotebook + open_notebook + True + + switch_page + GtkOpenNotebookChanged + True + Tue, 09 Jul 2002 14:01:19 GMT + + True + True + GTK_POS_TOP + False + 2 + 2 + False + + 0 + True + True + + + + GtkHBox + hbox20 + 5 + False + 5 + + + GtkCombo + combo1 + False + True + False + True + False + + + 0 + False + True + + + + GtkEntry + GtkCombo:entry + entry_file + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:22:33 GMT + + True + True + 0 + + + + + + GtkVBox + vbox13 + True + 0 + + 0 + False + False + + + + Placeholder + + + + GtkButton + open_browse + True + + clicked + GtkFileShow + Wed, 10 Jul 2002 11:37:05 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + Placeholder + + + + + + GtkLabel + Notebook:tab + open_file + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table5 + 5 + 4 + 2 + False + 5 + 5 + + + GtkLabel + label21 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label20 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + disc_chapter + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:45:38 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 + 1 + 65536 + 1 + 10 + 10 + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label35 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkHBox + hbox24 + False + 0 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + True + + + + GtkRadioButton + disc_dvd + True + + toggled + GtkDiscOpenDvd + Sun, 13 May 2001 14:48:29 GMT + + + False + True + disc + + 0 + False + False + + + + + GtkRadioButton + disc_vcd + True + + toggled + GtkDiscOpenVcd + Sun, 13 May 2001 14:48:39 GMT + + + False + True + disc + + 0 + False + False + + + + + + GtkLabel + label19 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + disc_title + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:45:04 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 + 1 + 65536 + 1 + 10 + 10 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkEntry + disc_name + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:46:05 GMT + + True + True + 0 + /dev/dvd + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + + GtkLabel + Notebook:tab + open_disc + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table4 + 5 + 4 + 6 + False + 5 + 5 + + + GtkRadioButton + network_udp + True + + toggled + GtkNetworkOpenUDP + Thu, 16 May 2002 00:47:18 GMT + + + False + True + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_multicast + True + + toggled + GtkNetworkOpenMulticast + Thu, 16 May 2002 00:47:05 GMT + + + False + True + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_channel + True + + toggled + GtkNetworkOpenChannel + Thu, 16 May 2002 01:44:15 GMT + + + False + True + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_http + True + + toggled + GtkNetworkOpenHTTP + Thu, 16 May 2002 00:47:42 GMT + + + False + True + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_udp_port_label + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_multicast_address_label + False + + GTK_JUSTIFY_RIGHT + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_channel_address_label + False + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_http_url_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCombo + network_multicast_address_combo + False + False + True + False + True + False + + + 2 + 4 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + network_multicast_address + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:06 GMT + + True + True + 0 + + + + + + GtkCombo + network_channel_address_combo + False + False + True + False + True + False + + + 2 + 4 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + network_channel_address + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:16 GMT + + True + True + 0 + + + + + + GtkLabel + network_multicast_port_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 4 + 5 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_channel_port_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 4 + 5 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + network_multicast_port + 75 + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:36 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1234 + 0 + 65535 + 1 + 10 + 10 + + 5 + 6 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + + GtkSpinButton + network_channel_port + 75 + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:45 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 6010 + 0 + 65535 + 1 + 10 + 10 + + 5 + 6 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + network_http_url + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:26 GMT + + True + True + 0 + + + 2 + 6 + 3 + 4 + 0 + 0 + True + False + False + False + True + False + + + + + GtkSpinButton + network_udp_port + 1 + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:56:55 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1234 + 0 + 65535 + 1 + 10 + 10 + + 2 + 3 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + + GtkLabel + Notebook:tab + open_net + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table3 + 5 + 4 + 2 + False + 5 + 5 + + + GtkLabel + label24 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label25 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label26 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + sat_freq + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:00 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 11954 + 10000 + 12999 + 1 + 10 + 10 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label27 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkHBox + hbox23 + False + 0 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + True + + + + GtkRadioButton + sat_pol_vert + True + + toggled + GtkSatOpenToggle + Tue, 09 Jul 2002 15:16:25 GMT + + + False + True + pol + + 0 + False + False + + + + + GtkRadioButton + sat_pol_hor + True + + toggled + GtkSatOpenToggle + Tue, 09 Jul 2002 15:16:36 GMT + + + False + True + pol + + 0 + False + False + + + + + + GtkSpinButton + sat_srate + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:09 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 27500 + 1000 + 30000 + 1 + 10 + 10 + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCombo + sat_fec + False + True + False + True + False + 1/2 +2/3 +3/4 +4/5 +5/6 +7/8 + + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:26 GMT + + True + True + 0 + 3/4 + + + + + + GtkLabel + Notebook:tab + open_sat + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + + GtkFileSelection + intf_file + 10 + Open File + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + True + False + True + False + False + + + GtkButton + FileSel:ok_button + file_ok + True + True + + clicked + GtkFileOk + Thu, 11 Jul 2002 09:07:44 GMT + + GNOME_STOCK_BUTTON_OK + GTK_RELIEF_NORMAL + + + + GtkButton + FileSel:cancel_button + file_cancel + True + True + + clicked + GtkFileCancel + Thu, 11 Jul 2002 09:07:50 GMT + + GNOME_STOCK_BUTTON_CANCEL + GTK_RELIEF_NORMAL + + + + + GnomeDialog + intf_modules + Modules + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + False + False + False + + + GtkVBox + GnomeDialog:vbox + dialog-vbox1 + False + 8 + + 4 + True + True + + + + GtkHButtonBox + GnomeDialog:action_area + dialog-action_area1 + GTK_BUTTONBOX_END + 8 + 85 + 27 + 7 + 0 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + modules_ok + True + True + GNOME_STOCK_BUTTON_OK + + + + GtkButton + modules_apply + True + True + GNOME_STOCK_BUTTON_APPLY + + + + GtkButton + modules_cancel + True + True + GNOME_STOCK_BUTTON_CANCEL + + + + + GtkLabel + label12 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + + + GnomeDialog + intf_playlist + + destroy + gtk_widget_hide + Sat, 19 May 2001 03:09:08 GMT + + + delete_event + gtk_widget_hide + Sat, 19 May 2001 03:09:12 GMT + + Playlist + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 400 + 300 + True + True + False + False + True + + + GtkVBox + GnomeDialog:vbox + playlist_vbox + False + 8 + + 4 + True + True + + + + GtkHButtonBox + GnomeDialog:action_area + playlist_action + GTK_BUTTONBOX_END + 8 + 100 + 38 + 7 + 0 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + playlist_ok + True + True + + clicked + GtkPlaylistOk + Sat, 19 May 2001 03:09:00 GMT + + GNOME_STOCK_BUTTON_OK + + + + GtkButton + playlist_cancel + True + True + + clicked + GtkPlaylistCancel + Sat, 19 May 2001 03:08:56 GMT + + GNOME_STOCK_BUTTON_CANCEL + + + + + GtkScrolledWindow + playlist_scrolledwindow + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkViewport + playlist_viewport + GTK_SHADOW_IN + + + GtkFrame + playlist_frame + 4 + + 0.05 + GTK_SHADOW_ETCHED_IN + + + GtkCList + playlist_clist + True + + event + GtkPlaylistEvent + Sat, 19 May 2001 03:08:43 GMT + + + drag_data_received + GtkPlaylistDragData + Sat, 19 May 2001 03:08:45 GMT + + + drag_motion + GtkPlaylistDragMotion + Sat, 19 May 2001 03:08:49 GMT + + 2 + 287,70 + GTK_SELECTION_EXTENDED + True + GTK_SHADOW_IN + + + GtkLabel + CList:title + playlist_label_url + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + playlist_label_duration + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + + GtkMenuBar + playlist_menubar + GTK_SHADOW_OUT + + 0 + False + False + + + + GtkMenuItem + playlist_add + + False + + + GtkMenu + playlist_add_menu + + + GtkMenuItem + playlist_add_disc + + activate + GtkDiscOpenShow + Sat, 19 May 2001 16:22:26 GMT + + + False + + + + GtkMenuItem + playlist_add_file + + activate + GtkFileOpenShow + Sat, 19 May 2001 16:22:37 GMT + + + False + + + + GtkMenuItem + playlist_add_network + + activate + GtkNetworkOpenShow + Sat, 19 May 2001 16:22:52 GMT + + + False + + + + GtkMenuItem + playlist_add_url + + activate + GtkPlaylistAddUrl + Sat, 19 May 2001 16:24:27 GMT + + + False + + + + + + GtkMenuItem + playlist_delete + + False + + + GtkMenu + playlist_delete_menu + + + GtkMenuItem + playlist_delete_all + + activate + GtkPlaylistDeleteAll + Sat, 19 May 2001 03:08:11 GMT + + + False + + + + GtkMenuItem + playlist_delete_item + + activate + GtkPlaylistDeleteSelected + Sat, 19 May 2001 03:08:05 GMT + + + False + + + + + + GtkMenuItem + playlist_selection + + False + + + GtkMenu + playlist_selection_menu + + + GtkMenuItem + playlist_selection_crop + + activate + GtkPlaylistCrop + Sat, 19 May 2001 03:07:56 GMT + + + False + + + + GtkMenuItem + playlist_selection_invert + + activate + GtkPlaylistInvert + Sat, 19 May 2001 03:07:51 GMT + + + False + + + + GtkMenuItem + playlist_selection_select + + activate + GtkPlaylistSelect + Sat, 19 May 2001 03:07:45 GMT + + + False + + + + + + + + + GnomeDialog + intf_jump + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + False + False + False + False + + + GtkVBox + GnomeDialog:vbox + jump_vbox + False + 8 + + 0 + True + True + + + + GtkHButtonBox + GnomeDialog:action_area + jump_action + GTK_BUTTONBOX_END + 8 + 85 + 27 + 7 + 0 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + jump_ok + True + True + + clicked + GtkJumpOk + Sat, 19 May 2001 03:07:27 GMT + + GNOME_STOCK_BUTTON_OK + + + + GtkButton + jump_cancel + True + True + + clicked + GtkJumpCancel + Sat, 19 May 2001 03:07:20 GMT + + GNOME_STOCK_BUTTON_CANCEL + + + + + GtkFrame + jump_frame + 5 + + 0.05 + GTK_SHADOW_ETCHED_IN + + 0 + False + False + + + + GtkHBox + jump_box + 5 + False + 0 + + + GtkLabel + jump_label3 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_second_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 100 + 1 + 10 + 10 + + 5 + False + False + GTK_PACK_END + + + + + GtkLabel + jump_label1 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_minute_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 59 + 1 + 10 + 10 + + 5 + False + False + GTK_PACK_END + + + + + GtkLabel + jump_label2 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_hour_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 10 + 1 + 10 + 10 + + 5 + False + False + GTK_PACK_END + + + + + + + + + GnomeDialog + intf_messages + + destroy + gtk_widget_hide + Wed, 20 Feb 2002 05:11:27 GMT + + + delete_event + gtk_widget_hide + Wed, 20 Feb 2002 05:11:27 GMT + + Messages + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + False + False + True + + + GtkVBox + GnomeDialog:vbox + dialog-vbox6 + False + 8 + + 4 + True + True + + + + GtkHButtonBox + GnomeDialog:action_area + dialog-action_area6 + GTK_BUTTONBOX_END + 8 + 85 + 27 + 7 + 0 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + messages_ok + True + True + + clicked + GtkMessagesOk + Wed, 20 Feb 2002 05:12:11 GMT + + GNOME_STOCK_BUTTON_OK + + + + + GtkScrolledWindow + scrolledwindow1 + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkText + messages_textbox + 600 + 400 + True + False + + + + + + + diff --git a/modules/gui/gtk/gnome_callbacks.c b/modules/gui/gtk/gnome_callbacks.c new file mode 100644 index 0000000000..afc407c51f --- /dev/null +++ b/modules/gui/gtk/gnome_callbacks.c @@ -0,0 +1,3 @@ +/***************************************************************************** + * This file is not used: everything is in gtk_callbacks.c + *****************************************************************************/ diff --git a/modules/gui/gtk/gnome_callbacks.h b/modules/gui/gtk/gnome_callbacks.h new file mode 100644 index 0000000000..3899961701 --- /dev/null +++ b/modules/gui/gtk/gnome_callbacks.h @@ -0,0 +1,4 @@ +/***************************************************************************** + * This file is not needed: everything is in gtk_callbacks.h + *****************************************************************************/ +#include "gtk_callbacks.h" diff --git a/modules/gui/gtk/gnome_interface.c b/modules/gui/gtk/gnome_interface.c new file mode 100644 index 0000000000..cb92d64be8 --- /dev/null +++ b/modules/gui/gtk/gnome_interface.c @@ -0,0 +1,2442 @@ +/* This file was created automatically by glade and fixed by bootstrap.sh */ + +#include + +#include +#include +#include +#include + +#include + +#include "gnome_callbacks.h" +#include "gnome_interface.h" +#include "gnome_support.h" + +static GnomeUIInfo menubar_file_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("_Open File..."), + N_("Open a File"), + (gpointer) GtkFileOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Open _Disc..."), + N_("Open a DVD or VCD"), + (gpointer) GtkDiscOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CDROM, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Network Stream..."), + N_("Select a Network Stream"), + (gpointer) GtkNetworkOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REFRESH, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_("_Eject Disc"), + N_("Eject disc"), + (gpointer) GtkDiscEject, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_TOP, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_CLOSE_ITEM (GtkClose, NULL), + GNOMEUIINFO_MENU_EXIT_ITEM (GtkExit, NULL), + GNOMEUIINFO_END +}; + +static GnomeUIInfo menubar_view_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("_Hide interface"), + NULL, + (gpointer) GtkWindowToggle, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Fullscreen"), + NULL, + (gpointer) GtkFullscreen, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_("Progr_am"), + N_("Choose the program"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Title"), + N_("Choose title"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Chapter"), + N_("Choose chapter"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_("_Playlist..."), + N_("Open the playlist window"), + (gpointer) GtkPlaylistShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_INDEX, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Modules..."), + N_("Open the module manager"), + (gpointer) GtkModulesShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ATTACH, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Messages..."), + N_("Open the messages window"), + (gpointer) GtkMessagesShow, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +static GnomeUIInfo menubar_settings_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("_Audio"), + N_("Select audio channel"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Subtitles"), + N_("Select subtitles channel"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_PREFERENCES_ITEM (GtkPreferencesShow, NULL), + GNOMEUIINFO_END +}; + +static GnomeUIInfo menubar_help_menu_uiinfo[] = +{ + GNOMEUIINFO_MENU_ABOUT_ITEM (GtkAboutShow, NULL), + GNOMEUIINFO_END +}; + +static GnomeUIInfo menubar_uiinfo[] = +{ + GNOMEUIINFO_MENU_FILE_TREE (menubar_file_menu_uiinfo), + GNOMEUIINFO_MENU_VIEW_TREE (menubar_view_menu_uiinfo), + GNOMEUIINFO_MENU_SETTINGS_TREE (menubar_settings_menu_uiinfo), + GNOMEUIINFO_MENU_HELP_TREE (menubar_help_menu_uiinfo), + GNOMEUIINFO_END +}; + +GtkWidget* +create_intf_window (void) +{ + GtkWidget *intf_window; + GtkWidget *dockitem; + GtkWidget *toolbar; + GtkWidget *tmp_toolbar_icon; + GtkWidget *toolbar_file; + GtkWidget *toolbar_disc; + GtkWidget *toolbar_network; + GtkWidget *toolbar_sat; + GtkWidget *toolbar_back; + GtkWidget *toolbar_stop; + GtkWidget *toolbar_eject; + GtkWidget *toolbar_play; + GtkWidget *toolbar_pause; + GtkWidget *toolbar_slow; + GtkWidget *toolbar_fast; + GtkWidget *toolbar_playlist; + GtkWidget *toolbar_prev; + GtkWidget *toolbar_next; + GtkWidget *vbox8; + GtkWidget *slider_frame; + GtkWidget *slider; + GtkWidget *file_box; + GtkWidget *label_status; + GtkWidget *dvd_box; + GtkWidget *label21; + GtkWidget *title_chapter_box; + GtkWidget *label19; + GtkWidget *title_label; + GtkWidget *button_title_prev; + GtkWidget *button_title_next; + GtkWidget *vseparator1; + GtkWidget *dvd_chapter_box; + GtkWidget *label20; + GtkWidget *chapter_label; + GtkWidget *button_chapter_prev; + GtkWidget *button_chapter_next; + GtkWidget *network_box; + GtkWidget *network_address_label; + GtkWidget *network_channel_box; + GtkWidget *label_network; + GtkObject *network_channel_spinbutton_adj; + GtkWidget *network_channel_spinbutton; + GtkWidget *network_channel_go_button; + GtkWidget *appbar; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + intf_window = gnome_app_new ("VideoLAN Client", _("VideoLAN Client")); + gtk_object_set_data (GTK_OBJECT (intf_window), "intf_window", intf_window); + gtk_window_set_policy (GTK_WINDOW (intf_window), FALSE, TRUE, TRUE); + + dockitem = GNOME_APP (intf_window)->dock; + gtk_widget_ref (dockitem); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dockitem", dockitem, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (dockitem); + + gnome_app_create_menus (GNOME_APP (intf_window), menubar_uiinfo); + + gtk_widget_ref (menubar_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_file", + menubar_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_open", + menubar_file_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_disc", + menubar_file_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_network", + menubar_file_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator1", + menubar_file_menu_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[4].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_eject", + menubar_file_menu_uiinfo[4].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[5].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator15", + menubar_file_menu_uiinfo[5].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[6].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_close", + menubar_file_menu_uiinfo[6].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_file_menu_uiinfo[7].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_exit", + menubar_file_menu_uiinfo[7].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_view", + menubar_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_hide_interface", + menubar_view_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_fullscreen", + menubar_view_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator9", + menubar_view_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_program", + menubar_view_menu_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_view_menu_uiinfo[3].widget, FALSE); + + gtk_widget_ref (menubar_view_menu_uiinfo[4].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_title", + menubar_view_menu_uiinfo[4].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_view_menu_uiinfo[4].widget, FALSE); + + gtk_widget_ref (menubar_view_menu_uiinfo[5].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_chapter", + menubar_view_menu_uiinfo[5].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_view_menu_uiinfo[5].widget, FALSE); + + gtk_widget_ref (menubar_view_menu_uiinfo[6].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator7", + menubar_view_menu_uiinfo[6].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[7].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_playlist", + menubar_view_menu_uiinfo[7].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_view_menu_uiinfo[8].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_modules", + menubar_view_menu_uiinfo[8].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_view_menu_uiinfo[8].widget, FALSE); + + gtk_widget_ref (menubar_view_menu_uiinfo[9].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_messages", + menubar_view_menu_uiinfo[9].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_settings", + menubar_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_settings_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_audio", + menubar_settings_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[0].widget, FALSE); + + gtk_widget_ref (menubar_settings_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_subpictures", + menubar_settings_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (menubar_settings_menu_uiinfo[1].widget, FALSE); + + gtk_widget_ref (menubar_settings_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator5", + menubar_settings_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_settings_menu_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences", + menubar_settings_menu_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_help", + menubar_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (menubar_help_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_about", + menubar_help_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH); + gtk_widget_ref (toolbar); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar", toolbar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar); + gnome_app_add_toolbar (GNOME_APP (intf_window), GTK_TOOLBAR (toolbar), "toolbar", + GNOME_DOCK_ITEM_BEH_EXCLUSIVE, + GNOME_DOCK_TOP, 1, 0, 2); + gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 16); + gtk_toolbar_set_space_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_SPACE_LINE); + gtk_toolbar_set_button_relief (GTK_TOOLBAR (toolbar), GTK_RELIEF_NONE); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_OPEN); + toolbar_file = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("File"), + _("Open a File"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_file); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_file", toolbar_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_file); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_CDROM); + toolbar_disc = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Disc"), + _("Open a DVD or VCD"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_disc", toolbar_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_disc); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_REFRESH); + toolbar_network = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Net"), + _("Select a Network Stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_network); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_network", toolbar_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_network); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_MIC); + toolbar_sat = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Sat"), + _("Open a Satellite Card"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_sat); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_sat", toolbar_sat, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_sat); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_BACK); + toolbar_back = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Back"), + _("Go Backward"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_back); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_back", toolbar_back, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_back); + gtk_widget_set_sensitive (toolbar_back, FALSE); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_STOP); + toolbar_stop = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Stop"), + _("Stop Stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_stop); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_stop", toolbar_stop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_stop); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_TOP); + toolbar_eject = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Eject"), + _("Eject disc"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_eject); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_eject", toolbar_eject, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_eject); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_FORWARD); + toolbar_play = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Play"), + _("Play Stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_play); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_play", toolbar_play, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_play); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_BOTTOM); + toolbar_pause = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Pause"), + _("Pause Stream"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_pause); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_pause", toolbar_pause, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_pause); + gtk_widget_set_sensitive (toolbar_pause, FALSE); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_TIMER_STOP); + toolbar_slow = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Slow"), + _("Play Slower"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_slow); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_slow", toolbar_slow, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_slow); + gtk_widget_set_sensitive (toolbar_slow, FALSE); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_TIMER); + toolbar_fast = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Fast"), + _("Play Faster"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_fast); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_fast", toolbar_fast, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_fast); + gtk_widget_set_sensitive (toolbar_fast, FALSE); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_INDEX); + toolbar_playlist = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Playlist"), + _("Open Playlist"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_playlist); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_playlist", toolbar_playlist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_playlist); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_FIRST); + toolbar_prev = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Prev"), + _("Previous File"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_prev); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_prev", toolbar_prev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_prev); + + tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_LAST); + toolbar_next = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Next"), + _("Next File"), NULL, + tmp_toolbar_icon, NULL, NULL); + gtk_widget_ref (toolbar_next); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_next", toolbar_next, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_next); + + vbox8 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox8); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "vbox8", vbox8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox8); + gnome_app_set_contents (GNOME_APP (intf_window), vbox8); + + slider_frame = gtk_frame_new ("-:--:--"); + gtk_widget_ref (slider_frame); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "slider_frame", slider_frame, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (vbox8), slider_frame, TRUE, TRUE, 0); + gtk_frame_set_label_align (GTK_FRAME (slider_frame), 0.05, 0.5); + + slider = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 1, 6.25, 0))); + gtk_widget_ref (slider); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "slider", slider, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (slider); + gtk_container_add (GTK_CONTAINER (slider_frame), slider); + gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE); + gtk_scale_set_digits (GTK_SCALE (slider), 3); + + file_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (file_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "file_box", file_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (file_box); + gtk_box_pack_start (GTK_BOX (vbox8), file_box, TRUE, TRUE, 0); + + label_status = gtk_label_new (""); + gtk_widget_ref (label_status); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label_status", label_status, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label_status); + gtk_box_pack_start (GTK_BOX (file_box), label_status, TRUE, TRUE, 0); + + dvd_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (dvd_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dvd_box", dvd_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (vbox8), dvd_box, TRUE, TRUE, 0); + + label21 = gtk_label_new (_("Disc")); + gtk_widget_ref (label21); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label21", label21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label21); + gtk_box_pack_start (GTK_BOX (dvd_box), label21, TRUE, FALSE, 0); + + title_chapter_box = gtk_hbox_new (FALSE, 10); + gtk_widget_ref (title_chapter_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_chapter_box", title_chapter_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_chapter_box); + gtk_box_pack_start (GTK_BOX (dvd_box), title_chapter_box, TRUE, FALSE, 0); + + label19 = gtk_label_new (_("Title:")); + gtk_widget_ref (label19); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label19", label19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label19); + gtk_box_pack_start (GTK_BOX (title_chapter_box), label19, FALSE, FALSE, 0); + + title_label = gtk_label_new ("--"); + gtk_widget_ref (title_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_label", title_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_label); + gtk_box_pack_start (GTK_BOX (title_chapter_box), title_label, FALSE, FALSE, 0); + + button_title_prev = gnome_stock_button (GNOME_STOCK_BUTTON_PREV); + gtk_widget_ref (button_title_prev); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "button_title_prev", button_title_prev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button_title_prev); + gtk_box_pack_start (GTK_BOX (title_chapter_box), button_title_prev, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, button_title_prev, _("Select previous title"), NULL); + gtk_button_set_relief (GTK_BUTTON (button_title_prev), GTK_RELIEF_NONE); + + button_title_next = gnome_stock_button (GNOME_STOCK_BUTTON_NEXT); + gtk_widget_ref (button_title_next); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "button_title_next", button_title_next, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button_title_next); + gtk_box_pack_start (GTK_BOX (title_chapter_box), button_title_next, FALSE, FALSE, 0); + gtk_button_set_relief (GTK_BUTTON (button_title_next), GTK_RELIEF_NONE); + + vseparator1 = gtk_vseparator_new (); + gtk_widget_ref (vseparator1); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "vseparator1", vseparator1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vseparator1); + gtk_box_pack_start (GTK_BOX (dvd_box), vseparator1, FALSE, FALSE, 0); + + dvd_chapter_box = gtk_hbox_new (FALSE, 10); + gtk_widget_ref (dvd_chapter_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dvd_chapter_box", dvd_chapter_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (dvd_chapter_box); + gtk_box_pack_start (GTK_BOX (dvd_box), dvd_chapter_box, TRUE, FALSE, 0); + + label20 = gtk_label_new (_("Chapter:")); + gtk_widget_ref (label20); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label20", label20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label20); + gtk_box_pack_start (GTK_BOX (dvd_chapter_box), label20, FALSE, FALSE, 0); + + chapter_label = gtk_label_new ("---"); + gtk_widget_ref (chapter_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter_label", chapter_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter_label); + gtk_box_pack_start (GTK_BOX (dvd_chapter_box), chapter_label, FALSE, FALSE, 0); + + button_chapter_prev = gnome_stock_button (GNOME_STOCK_BUTTON_DOWN); + gtk_widget_ref (button_chapter_prev); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "button_chapter_prev", button_chapter_prev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button_chapter_prev); + gtk_box_pack_start (GTK_BOX (dvd_chapter_box), button_chapter_prev, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, button_chapter_prev, _("Select previous chapter"), NULL); + gtk_button_set_relief (GTK_BUTTON (button_chapter_prev), GTK_RELIEF_NONE); + + button_chapter_next = gnome_stock_button (GNOME_STOCK_BUTTON_UP); + gtk_widget_ref (button_chapter_next); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "button_chapter_next", button_chapter_next, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button_chapter_next); + gtk_box_pack_start (GTK_BOX (dvd_chapter_box), button_chapter_next, FALSE, FALSE, 0); + gtk_tooltips_set_tip (tooltips, button_chapter_next, _("Select next chapter"), NULL); + gtk_button_set_relief (GTK_BUTTON (button_chapter_next), GTK_RELIEF_NONE); + + network_box = gtk_hbox_new (TRUE, 0); + gtk_widget_ref (network_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_box", network_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (vbox8), network_box, FALSE, FALSE, 0); + + network_address_label = gtk_label_new (_("No server")); + gtk_widget_ref (network_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_address_label", network_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_address_label); + gtk_box_pack_start (GTK_BOX (network_box), network_address_label, FALSE, FALSE, 0); + + network_channel_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (network_channel_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_box", network_channel_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_box); + gtk_box_pack_start (GTK_BOX (network_box), network_channel_box, FALSE, FALSE, 0); + + label_network = gtk_label_new (_("Network Channel:")); + gtk_widget_ref (label_network); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label_network", label_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label_network); + gtk_box_pack_start (GTK_BOX (network_channel_box), label_network, TRUE, FALSE, 5); + + network_channel_spinbutton_adj = gtk_adjustment_new (0, 0, 100, 1, 10, 10); + network_channel_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (network_channel_spinbutton_adj), 1, 0); + gtk_widget_ref (network_channel_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_spinbutton", network_channel_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_spinbutton); + gtk_box_pack_start (GTK_BOX (network_channel_box), network_channel_spinbutton, FALSE, TRUE, 5); + + network_channel_go_button = gtk_button_new_with_label (_("Go!")); + gtk_widget_ref (network_channel_go_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_go_button", network_channel_go_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_go_button); + gtk_box_pack_start (GTK_BOX (network_channel_box), network_channel_go_button, FALSE, FALSE, 0); + gtk_button_set_relief (GTK_BUTTON (network_channel_go_button), GTK_RELIEF_NONE); + + appbar = gnome_appbar_new (FALSE, TRUE, GNOME_PREFERENCES_NEVER); + gtk_widget_ref (appbar); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "appbar", appbar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (appbar); + gnome_app_set_statusbar (GNOME_APP (intf_window), appbar); + + gtk_signal_connect (GTK_OBJECT (intf_window), "delete_event", + GTK_SIGNAL_FUNC (GtkWindowDelete), + NULL); + gtk_signal_connect (GTK_OBJECT (intf_window), "drag_data_received", + GTK_SIGNAL_FUNC (GtkWindowDrag), + NULL); + gnome_app_install_menu_hints (GNOME_APP (intf_window), menubar_uiinfo); + gtk_signal_connect (GTK_OBJECT (toolbar_file), "clicked", + GTK_SIGNAL_FUNC (GtkFileOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_disc), "clicked", + GTK_SIGNAL_FUNC (GtkDiscOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_network), "clicked", + GTK_SIGNAL_FUNC (GtkNetworkOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_sat), "clicked", + GTK_SIGNAL_FUNC (GtkSatOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_back), "clicked", + GTK_SIGNAL_FUNC (GtkControlBack), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_stop), "clicked", + GTK_SIGNAL_FUNC (GtkControlStop), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_eject), "clicked", + GTK_SIGNAL_FUNC (GtkDiscEject), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_play), "clicked", + GTK_SIGNAL_FUNC (GtkControlPlay), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_pause), "clicked", + GTK_SIGNAL_FUNC (GtkControlPause), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_slow), "clicked", + GTK_SIGNAL_FUNC (GtkControlSlow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_fast), "clicked", + GTK_SIGNAL_FUNC (GtkControlFast), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_playlist), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_prev), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistPrev), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_next), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistNext), + NULL); + gtk_signal_connect (GTK_OBJECT (slider), "button_press_event", + GTK_SIGNAL_FUNC (GtkSliderPress), + NULL); + gtk_signal_connect (GTK_OBJECT (slider), "button_release_event", + GTK_SIGNAL_FUNC (GtkSliderRelease), + NULL); + gtk_signal_connect (GTK_OBJECT (button_title_prev), "clicked", + GTK_SIGNAL_FUNC (GtkTitlePrev), + NULL); + gtk_signal_connect (GTK_OBJECT (button_title_next), "clicked", + GTK_SIGNAL_FUNC (GtkTitleNext), + NULL); + gtk_signal_connect (GTK_OBJECT (button_chapter_prev), "clicked", + GTK_SIGNAL_FUNC (GtkChapterPrev), + NULL); + gtk_signal_connect (GTK_OBJECT (button_chapter_next), "clicked", + GTK_SIGNAL_FUNC (GtkChapterNext), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_spinbutton), "activate", + GTK_SIGNAL_FUNC (GtkNetworkJoin), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_go_button), "clicked", + GTK_SIGNAL_FUNC (GtkChannelGo), + NULL); + + gtk_object_set_data (GTK_OBJECT (intf_window), "tooltips", tooltips); + + return intf_window; +} + +static GnomeUIInfo popup_file_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("_Open File..."), + N_("Open a File"), + (gpointer) GtkFileOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Open _Disc..."), + N_("Open a DVD or VCD"), + (gpointer) GtkDiscOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CDROM, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Network Stream..."), + N_("Select a Network Stream"), + (gpointer) GtkNetworkOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REFRESH, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_ABOUT_ITEM (GtkAboutShow, NULL), + GNOMEUIINFO_END +}; + +static GnomeUIInfo intf_popup_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("Play"), + NULL, + (gpointer) GtkControlPlay, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_FORWARD, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Pause"), + NULL, + (gpointer) GtkControlPause, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_BOTTOM, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Stop"), + NULL, + (gpointer) GtkControlStop, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_STOP, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Back"), + NULL, + (gpointer) GtkControlBack, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_BACK, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Slow"), + NULL, + (gpointer) GtkControlSlow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_TIMER_STOP, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Fast"), + NULL, + (gpointer) GtkControlFast, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_TIMER, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_("Toggle _Interface"), + NULL, + (gpointer) GtkWindowToggle, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Fullscreen"), + N_("Toggle fullscreen mode"), + (gpointer) GtkFullscreen, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + { + GNOME_APP_UI_ITEM, N_("Next"), + NULL, + (gpointer) GtkPlaylistNext, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Prev"), + NULL, + (gpointer) GtkPlaylistPrev, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Jump..."), + N_("Got directly so specified point"), + (gpointer) GtkJumpShow, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_JUMP_TO, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Program"), + N_("Switch program"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Navigation"), + N_("Navigate through titles and chapters"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SEARCH, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Audio"), + N_("Select audio channel"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_VOLUME, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("_Subtitles"), + N_("Select subtitles channel"), + (gpointer) NULL, NULL, NULL, + GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_FONT, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_FILE_TREE (popup_file_menu_uiinfo), + { + GNOME_APP_UI_ITEM, N_("Playlist..."), + NULL, + (gpointer) GtkPlaylistShow, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_MENU_PREFERENCES_ITEM (GtkPreferencesShow, NULL), + GNOMEUIINFO_SEPARATOR, + GNOMEUIINFO_MENU_EXIT_ITEM (GtkExit, NULL), + GNOMEUIINFO_END +}; + +GtkWidget* +create_intf_popup (void) +{ + GtkWidget *intf_popup; + + intf_popup = gtk_menu_new (); + gtk_object_set_data (GTK_OBJECT (intf_popup), "intf_popup", intf_popup); + gnome_app_fill_menu (GTK_MENU_SHELL (intf_popup), intf_popup_uiinfo, + NULL, FALSE, 0); + + gtk_widget_ref (intf_popup_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_play", + intf_popup_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_pause", + intf_popup_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_stop", + intf_popup_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_back", + intf_popup_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (intf_popup_uiinfo[3].widget, FALSE); + + gtk_widget_ref (intf_popup_uiinfo[4].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_slow", + intf_popup_uiinfo[4].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[5].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_fast", + intf_popup_uiinfo[5].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[6].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator3", + intf_popup_uiinfo[6].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[7].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_interface_toggle", + intf_popup_uiinfo[7].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[8].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_fullscreen", + intf_popup_uiinfo[8].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[9].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator8", + intf_popup_uiinfo[9].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[10].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_next", + intf_popup_uiinfo[10].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[11].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_prev", + intf_popup_uiinfo[11].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[12].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_jump", + intf_popup_uiinfo[12].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[13].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_program", + intf_popup_uiinfo[13].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (intf_popup_uiinfo[13].widget, FALSE); + + gtk_widget_ref (intf_popup_uiinfo[14].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_navigation", + intf_popup_uiinfo[14].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (intf_popup_uiinfo[14].widget, FALSE); + + gtk_widget_ref (intf_popup_uiinfo[15].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_audio", + intf_popup_uiinfo[15].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (intf_popup_uiinfo[15].widget, FALSE); + + gtk_widget_ref (intf_popup_uiinfo[16].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_subpictures", + intf_popup_uiinfo[16].widget, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_set_sensitive (intf_popup_uiinfo[16].widget, FALSE); + + gtk_widget_ref (intf_popup_uiinfo[17].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator13", + intf_popup_uiinfo[17].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[18].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_file", + intf_popup_uiinfo[18].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (popup_file_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_open", + popup_file_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (popup_file_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_disc", + popup_file_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (popup_file_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_network", + popup_file_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (popup_file_menu_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator4", + popup_file_menu_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (popup_file_menu_uiinfo[4].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about", + popup_file_menu_uiinfo[4].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[19].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_playlist", + intf_popup_uiinfo[19].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[20].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_preferences", + intf_popup_uiinfo[20].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[21].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator2", + intf_popup_uiinfo[21].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (intf_popup_uiinfo[22].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit", + intf_popup_uiinfo[22].widget, + (GtkDestroyNotify) gtk_widget_unref); + + return intf_popup; +} + +GtkWidget* +create_intf_about (void) +{ + const gchar *authors[] = { + "the VideoLAN team ", + "http://www.videolan.org/", + NULL + }; + GtkWidget *intf_about; + + intf_about = gnome_about_new ("VideoLAN Client", VERSION, + _("(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team"), + authors, + _("This is the VideoLAN client, a DVD and MPEG player. It can play MPEG and MPEG 2 files from a file or from a network source."), + NULL); + gtk_object_set_data (GTK_OBJECT (intf_about), "intf_about", intf_about); + + return intf_about; +} + +GtkWidget* +create_intf_open (void) +{ + GtkWidget *intf_open; + GtkWidget *dialog_vbox5; + GtkWidget *open_vbox; + GtkWidget *frame10; + GtkWidget *hbox21; + GtkWidget *hbox22; + GtkWidget *label34; + GtkWidget *combo2; + GtkWidget *entry_open; + GtkWidget *label36; + GtkWidget *open_notebook; + GtkWidget *hbox20; + GtkWidget *combo1; + GtkWidget *entry_file; + GtkWidget *vbox13; + GtkWidget *open_browse; + GtkWidget *open_file; + GtkWidget *table5; + GtkWidget *label21; + GtkWidget *label20; + GtkObject *disc_chapter_adj; + GtkWidget *disc_chapter; + GtkWidget *label35; + GtkWidget *hbox24; + GSList *disc_group = NULL; + GtkWidget *disc_dvd; + GtkWidget *disc_vcd; + GtkWidget *label19; + GtkObject *disc_title_adj; + GtkWidget *disc_title; + GtkWidget *disc_name; + GtkWidget *open_disc; + GtkWidget *table4; + GSList *table4_group = NULL; + GtkWidget *network_udp; + GtkWidget *network_multicast; + GtkWidget *network_channel; + GtkWidget *network_http; + GtkWidget *network_udp_port_label; + GtkWidget *network_multicast_address_label; + GtkWidget *network_channel_address_label; + GtkWidget *network_http_url_label; + GtkWidget *network_multicast_address_combo; + GtkWidget *network_multicast_address; + GtkWidget *network_channel_address_combo; + GtkWidget *network_channel_address; + GtkWidget *network_multicast_port_label; + GtkWidget *network_channel_port_label; + GtkObject *network_multicast_port_adj; + GtkWidget *network_multicast_port; + GtkObject *network_channel_port_adj; + GtkWidget *network_channel_port; + GtkWidget *network_http_url; + GtkObject *network_udp_port_adj; + GtkWidget *network_udp_port; + GtkWidget *open_net; + GtkWidget *table3; + GtkWidget *label24; + GtkWidget *label25; + GtkWidget *label26; + GtkObject *sat_freq_adj; + GtkWidget *sat_freq; + GtkWidget *label27; + GtkWidget *hbox23; + GSList *pol_group = NULL; + GtkWidget *sat_pol_vert; + GtkWidget *sat_pol_hor; + GtkObject *sat_srate_adj; + GtkWidget *sat_srate; + GtkWidget *sat_fec; + GList *sat_fec_items = NULL; + GtkWidget *combo_entry1; + GtkWidget *open_sat; + GtkWidget *dialog_action_area5; + GtkWidget *button1; + GtkWidget *button3; + + intf_open = gnome_dialog_new (_("Open Stream"), NULL); + gtk_object_set_data (GTK_OBJECT (intf_open), "intf_open", intf_open); + gtk_window_set_modal (GTK_WINDOW (intf_open), TRUE); + gtk_window_set_policy (GTK_WINDOW (intf_open), FALSE, FALSE, FALSE); + gnome_dialog_close_hides (GNOME_DIALOG (intf_open), TRUE); + + dialog_vbox5 = GNOME_DIALOG (intf_open)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_open), "dialog_vbox5", dialog_vbox5); + gtk_widget_show (dialog_vbox5); + + open_vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (open_vbox); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_vbox", open_vbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_vbox); + gtk_box_pack_start (GTK_BOX (dialog_vbox5), open_vbox, TRUE, TRUE, 0); + + frame10 = gtk_frame_new (_("Media Resource Locator (MRL)")); + gtk_widget_ref (frame10); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "frame10", frame10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame10); + gtk_box_pack_start (GTK_BOX (open_vbox), frame10, FALSE, TRUE, 0); + + hbox21 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox21); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox21", hbox21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox21); + gtk_container_add (GTK_CONTAINER (frame10), hbox21); + gtk_container_set_border_width (GTK_CONTAINER (hbox21), 5); + + hbox22 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox22); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox22", hbox22, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox22); + gtk_box_pack_start (GTK_BOX (hbox21), hbox22, FALSE, TRUE, 0); + + label34 = gtk_label_new (_("Open Target:")); + gtk_widget_ref (label34); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label34", label34, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label34); + gtk_box_pack_start (GTK_BOX (hbox22), label34, FALSE, FALSE, 0); + + combo2 = gtk_combo_new (); + gtk_widget_ref (combo2); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo2", combo2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo2); + gtk_box_pack_start (GTK_BOX (hbox21), combo2, TRUE, TRUE, 0); + + entry_open = GTK_COMBO (combo2)->entry; + gtk_widget_ref (entry_open); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "entry_open", entry_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry_open); + + label36 = gtk_label_new (_("Alternatively, you can build an MRL using one of the following predefined targets:")); + gtk_widget_ref (label36); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label36", label36, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label36); + gtk_box_pack_start (GTK_BOX (open_vbox), label36, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label36), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label36), 0, 1); + + open_notebook = gtk_notebook_new (); + gtk_widget_ref (open_notebook); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_notebook", open_notebook, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_notebook); + gtk_box_pack_start (GTK_BOX (open_vbox), open_notebook, TRUE, TRUE, 0); + + hbox20 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox20); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox20", hbox20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox20); + gtk_container_add (GTK_CONTAINER (open_notebook), hbox20); + gtk_container_set_border_width (GTK_CONTAINER (hbox20), 5); + + combo1 = gtk_combo_new (); + gtk_widget_ref (combo1); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo1", combo1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo1); + gtk_box_pack_start (GTK_BOX (hbox20), combo1, FALSE, TRUE, 0); + + entry_file = GTK_COMBO (combo1)->entry; + gtk_widget_ref (entry_file); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "entry_file", entry_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry_file); + + vbox13 = gtk_vbox_new (TRUE, 0); + gtk_widget_ref (vbox13); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "vbox13", vbox13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox13); + gtk_box_pack_start (GTK_BOX (hbox20), vbox13, FALSE, FALSE, 0); + + open_browse = gtk_button_new_with_label (_("Browse...")); + gtk_widget_ref (open_browse); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_browse", open_browse, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_browse); + gtk_box_pack_start (GTK_BOX (vbox13), open_browse, FALSE, FALSE, 0); + + open_file = gtk_label_new (_("File")); + gtk_widget_ref (open_file); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_file", open_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_file); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 0), open_file); + + table5 = gtk_table_new (4, 2, FALSE); + gtk_widget_ref (table5); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table5", table5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (open_notebook), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_row_spacings (GTK_TABLE (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 5); + + label21 = gtk_label_new (_("Title")); + gtk_widget_ref (label21); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label21", label21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label21); + gtk_table_attach (GTK_TABLE (table5), label21, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label21), 0, 0.5); + + label20 = gtk_label_new (_("Chapter")); + gtk_widget_ref (label20); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label20", label20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label20); + gtk_table_attach (GTK_TABLE (table5), label20, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label20), 0, 0.5); + + disc_chapter_adj = gtk_adjustment_new (1, 1, 65536, 1, 10, 10); + disc_chapter = gtk_spin_button_new (GTK_ADJUSTMENT (disc_chapter_adj), 1, 0); + gtk_widget_ref (disc_chapter); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_chapter", disc_chapter, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_chapter); + gtk_table_attach (GTK_TABLE (table5), disc_chapter, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label35 = gtk_label_new (_("Disc type")); + gtk_widget_ref (label35); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label35", label35, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label35); + gtk_table_attach (GTK_TABLE (table5), label35, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label35), 0, 0.5); + + hbox24 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox24); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox24", hbox24, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox24); + gtk_table_attach (GTK_TABLE (table5), hbox24, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + disc_dvd = gtk_radio_button_new_with_label (disc_group, _("DVD")); + disc_group = gtk_radio_button_group (GTK_RADIO_BUTTON (disc_dvd)); + gtk_widget_ref (disc_dvd); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_dvd", disc_dvd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_dvd); + gtk_box_pack_start (GTK_BOX (hbox24), disc_dvd, FALSE, FALSE, 0); + + disc_vcd = gtk_radio_button_new_with_label (disc_group, _("VCD")); + disc_group = gtk_radio_button_group (GTK_RADIO_BUTTON (disc_vcd)); + gtk_widget_ref (disc_vcd); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_vcd", disc_vcd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_vcd); + gtk_box_pack_start (GTK_BOX (hbox24), disc_vcd, FALSE, FALSE, 0); + + label19 = gtk_label_new (_("Device name")); + gtk_widget_ref (label19); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label19", label19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label19); + gtk_table_attach (GTK_TABLE (table5), label19, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + disc_title_adj = gtk_adjustment_new (1, 1, 65536, 1, 10, 10); + disc_title = gtk_spin_button_new (GTK_ADJUSTMENT (disc_title_adj), 1, 0); + gtk_widget_ref (disc_title); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_title", disc_title, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_title); + gtk_table_attach (GTK_TABLE (table5), disc_title, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + disc_name = gtk_entry_new (); + gtk_widget_ref (disc_name); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_name", disc_name, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_name); + gtk_table_attach (GTK_TABLE (table5), disc_name, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_text (GTK_ENTRY (disc_name), "/dev/dvd"); + + open_disc = gtk_label_new (_("Disc")); + gtk_widget_ref (open_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_disc", open_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_disc); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 1), open_disc); + + table4 = gtk_table_new (4, 6, FALSE); + gtk_widget_ref (table4); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table4", table4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (open_notebook), table4); + gtk_container_set_border_width (GTK_CONTAINER (table4), 5); + gtk_table_set_row_spacings (GTK_TABLE (table4), 5); + gtk_table_set_col_spacings (GTK_TABLE (table4), 5); + + network_udp = gtk_radio_button_new_with_label (table4_group, _("UDP")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_udp)); + gtk_widget_ref (network_udp); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp", network_udp, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp); + gtk_table_attach (GTK_TABLE (table4), network_udp, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_multicast = gtk_radio_button_new_with_label (table4_group, _("UDP Multicast")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_multicast)); + gtk_widget_ref (network_multicast); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast", network_multicast, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast); + gtk_table_attach (GTK_TABLE (table4), network_multicast, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_channel = gtk_radio_button_new_with_label (table4_group, _("Channel server ")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_channel)); + gtk_widget_ref (network_channel); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel", network_channel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel); + gtk_table_attach (GTK_TABLE (table4), network_channel, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_http = gtk_radio_button_new_with_label (table4_group, _("HTTP")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_http)); + gtk_widget_ref (network_http); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http", network_http, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http); + gtk_table_attach (GTK_TABLE (table4), network_http, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_udp_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_udp_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp_port_label", network_udp_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp_port_label); + gtk_table_attach (GTK_TABLE (table4), network_udp_port_label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (network_udp_port_label), 1, 0.5); + + network_multicast_address_label = gtk_label_new (_("Address")); + gtk_widget_ref (network_multicast_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address_label", network_multicast_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address_label); + gtk_table_attach (GTK_TABLE (table4), network_multicast_address_label, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_address_label, FALSE); + gtk_label_set_justify (GTK_LABEL (network_multicast_address_label), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (network_multicast_address_label), 1, 0.5); + + network_channel_address_label = gtk_label_new (_("Address")); + gtk_widget_ref (network_channel_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address_label", network_channel_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address_label); + gtk_table_attach (GTK_TABLE (table4), network_channel_address_label, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_address_label, FALSE); + + network_http_url_label = gtk_label_new (_("URL")); + gtk_widget_ref (network_http_url_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http_url_label", network_http_url_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http_url_label); + gtk_table_attach (GTK_TABLE (table4), network_http_url_label, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_http_url_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_http_url_label), 1, 0.5); + + network_multicast_address_combo = gtk_combo_new (); + gtk_widget_ref (network_multicast_address_combo); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address_combo", network_multicast_address_combo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address_combo); + gtk_table_attach (GTK_TABLE (table4), network_multicast_address_combo, 2, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_address_combo, FALSE); + + network_multicast_address = GTK_COMBO (network_multicast_address_combo)->entry; + gtk_widget_ref (network_multicast_address); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address", network_multicast_address, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address); + + network_channel_address_combo = gtk_combo_new (); + gtk_widget_ref (network_channel_address_combo); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address_combo", network_channel_address_combo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address_combo); + gtk_table_attach (GTK_TABLE (table4), network_channel_address_combo, 2, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_address_combo, FALSE); + + network_channel_address = GTK_COMBO (network_channel_address_combo)->entry; + gtk_widget_ref (network_channel_address); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address", network_channel_address, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address); + + network_multicast_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_multicast_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_port_label", network_multicast_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_port_label); + gtk_table_attach (GTK_TABLE (table4), network_multicast_port_label, 4, 5, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_port_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_multicast_port_label), 1, 0.5); + + network_channel_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_channel_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_port_label", network_channel_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_port_label); + gtk_table_attach (GTK_TABLE (table4), network_channel_port_label, 4, 5, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_port_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_channel_port_label), 1, 0.5); + + network_multicast_port_adj = gtk_adjustment_new (1234, 0, 65535, 1, 10, 10); + network_multicast_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_multicast_port_adj), 1, 0); + gtk_widget_ref (network_multicast_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_port", network_multicast_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_port); + gtk_table_attach (GTK_TABLE (table4), network_multicast_port, 5, 6, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_multicast_port, 75, -2); + gtk_widget_set_sensitive (network_multicast_port, FALSE); + + network_channel_port_adj = gtk_adjustment_new (6010, 0, 65535, 1, 10, 10); + network_channel_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_channel_port_adj), 1, 0); + gtk_widget_ref (network_channel_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_port", network_channel_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_port); + gtk_table_attach (GTK_TABLE (table4), network_channel_port, 5, 6, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_channel_port, 75, -2); + gtk_widget_set_sensitive (network_channel_port, FALSE); + + network_http_url = gtk_entry_new (); + gtk_widget_ref (network_http_url); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http_url", network_http_url, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http_url); + gtk_table_attach (GTK_TABLE (table4), network_http_url, 2, 6, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_http_url, FALSE); + + network_udp_port_adj = gtk_adjustment_new (1234, 0, 65535, 1, 10, 10); + network_udp_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_udp_port_adj), 1, 0); + gtk_widget_ref (network_udp_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp_port", network_udp_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp_port); + gtk_table_attach (GTK_TABLE (table4), network_udp_port, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_udp_port, 1, -2); + + open_net = gtk_label_new (_("Network")); + gtk_widget_ref (open_net); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_net", open_net, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_net); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 2), open_net); + + table3 = gtk_table_new (4, 2, FALSE); + gtk_widget_ref (table3); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table3", table3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table3); + gtk_container_add (GTK_CONTAINER (open_notebook), table3); + gtk_container_set_border_width (GTK_CONTAINER (table3), 5); + gtk_table_set_row_spacings (GTK_TABLE (table3), 5); + gtk_table_set_col_spacings (GTK_TABLE (table3), 5); + + label24 = gtk_label_new (_("Symbol Rate")); + gtk_widget_ref (label24); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label24", label24, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label24); + gtk_table_attach (GTK_TABLE (table3), label24, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label24), 0, 0.5); + + label25 = gtk_label_new (_("Frequency")); + gtk_widget_ref (label25); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label25", label25, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label25); + gtk_table_attach (GTK_TABLE (table3), label25, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label25), 0, 0.5); + + label26 = gtk_label_new (_("Polarization")); + gtk_widget_ref (label26); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label26", label26, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label26); + gtk_table_attach (GTK_TABLE (table3), label26, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label26), 0, 0.5); + + sat_freq_adj = gtk_adjustment_new (11954, 10000, 12999, 1, 10, 10); + sat_freq = gtk_spin_button_new (GTK_ADJUSTMENT (sat_freq_adj), 1, 0); + gtk_widget_ref (sat_freq); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_freq", sat_freq, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_freq); + gtk_table_attach (GTK_TABLE (table3), sat_freq, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label27 = gtk_label_new (_("FEC")); + gtk_widget_ref (label27); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label27", label27, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label27); + gtk_table_attach (GTK_TABLE (table3), label27, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label27), 0, 0.5); + + hbox23 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox23); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox23", hbox23, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox23); + gtk_table_attach (GTK_TABLE (table3), hbox23, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + sat_pol_vert = gtk_radio_button_new_with_label (pol_group, _("Vertical")); + pol_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sat_pol_vert)); + gtk_widget_ref (sat_pol_vert); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_pol_vert", sat_pol_vert, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_pol_vert); + gtk_box_pack_start (GTK_BOX (hbox23), sat_pol_vert, FALSE, FALSE, 0); + + sat_pol_hor = gtk_radio_button_new_with_label (pol_group, _("Horizontal")); + pol_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sat_pol_hor)); + gtk_widget_ref (sat_pol_hor); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_pol_hor", sat_pol_hor, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_pol_hor); + gtk_box_pack_start (GTK_BOX (hbox23), sat_pol_hor, FALSE, FALSE, 0); + + sat_srate_adj = gtk_adjustment_new (27500, 1000, 30000, 1, 10, 10); + sat_srate = gtk_spin_button_new (GTK_ADJUSTMENT (sat_srate_adj), 1, 0); + gtk_widget_ref (sat_srate); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_srate", sat_srate, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_srate); + gtk_table_attach (GTK_TABLE (table3), sat_srate, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + sat_fec = gtk_combo_new (); + gtk_widget_ref (sat_fec); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_fec", sat_fec, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_fec); + gtk_table_attach (GTK_TABLE (table3), sat_fec, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "1/2"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "2/3"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "3/4"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "4/5"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "5/6"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "7/8"); + gtk_combo_set_popdown_strings (GTK_COMBO (sat_fec), sat_fec_items); + g_list_free (sat_fec_items); + + combo_entry1 = GTK_COMBO (sat_fec)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + gtk_entry_set_text (GTK_ENTRY (combo_entry1), "3/4"); + + open_sat = gtk_label_new (_("Satellite")); + gtk_widget_ref (open_sat); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_sat", open_sat, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_sat); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 3), open_sat); + + dialog_action_area5 = GNOME_DIALOG (intf_open)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_open), "dialog_action_area5", dialog_action_area5); + gtk_widget_show (dialog_action_area5); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area5), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (dialog_action_area5), 8); + + gnome_dialog_append_button (GNOME_DIALOG (intf_open), GNOME_STOCK_BUTTON_OK); + button1 = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_open)->buttons)->data); + gtk_widget_ref (button1); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "button1", button1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button1); + GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); + + gnome_dialog_append_button (GNOME_DIALOG (intf_open), GNOME_STOCK_BUTTON_CANCEL); + button3 = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_open)->buttons)->data); + gtk_widget_ref (button3); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "button3", button3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (button3); + GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT); + + gtk_signal_connect_after (GTK_OBJECT (open_notebook), "switch_page", + GTK_SIGNAL_FUNC (GtkOpenNotebookChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (entry_file), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (open_browse), "clicked", + GTK_SIGNAL_FUNC (GtkFileShow), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_chapter), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_dvd), "toggled", + GTK_SIGNAL_FUNC (GtkDiscOpenDvd), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_vcd), "toggled", + GTK_SIGNAL_FUNC (GtkDiscOpenVcd), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_title), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_name), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_udp), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenUDP), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenMulticast), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenChannel), + NULL); + gtk_signal_connect (GTK_OBJECT (network_http), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenHTTP), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast_address), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_address), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_http_url), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_udp_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_freq), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_pol_vert), "toggled", + GTK_SIGNAL_FUNC (GtkSatOpenToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_pol_hor), "toggled", + GTK_SIGNAL_FUNC (GtkSatOpenToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_srate), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (combo_entry1), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (button1), "clicked", + GTK_SIGNAL_FUNC (GtkOpenOk), + NULL); + gtk_signal_connect (GTK_OBJECT (button3), "clicked", + GTK_SIGNAL_FUNC (GtkOpenCancel), + NULL); + + return intf_open; +} + +GtkWidget* +create_intf_file (void) +{ + GtkWidget *intf_file; + GtkWidget *file_ok; + GtkWidget *file_cancel; + + intf_file = gtk_file_selection_new (_("Open File")); + gtk_object_set_data (GTK_OBJECT (intf_file), "intf_file", intf_file); + gtk_container_set_border_width (GTK_CONTAINER (intf_file), 10); + gtk_window_set_modal (GTK_WINDOW (intf_file), TRUE); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (intf_file)); + + file_ok = GTK_FILE_SELECTION (intf_file)->ok_button; + gtk_object_set_data (GTK_OBJECT (intf_file), "file_ok", file_ok); + gtk_widget_show (file_ok); + GTK_WIDGET_SET_FLAGS (file_ok, GTK_CAN_DEFAULT); + + file_cancel = GTK_FILE_SELECTION (intf_file)->cancel_button; + gtk_object_set_data (GTK_OBJECT (intf_file), "file_cancel", file_cancel); + gtk_widget_show (file_cancel); + GTK_WIDGET_SET_FLAGS (file_cancel, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (file_ok), "clicked", + GTK_SIGNAL_FUNC (GtkFileOk), + NULL); + gtk_signal_connect (GTK_OBJECT (file_cancel), "clicked", + GTK_SIGNAL_FUNC (GtkFileCancel), + NULL); + + return intf_file; +} + +GtkWidget* +create_intf_modules (void) +{ + GtkWidget *intf_modules; + GtkWidget *dialog_vbox1; + GtkWidget *label12; + GtkWidget *dialog_action_area1; + GtkWidget *modules_ok; + GtkWidget *modules_apply; + GtkWidget *modules_cancel; + + intf_modules = gnome_dialog_new (_("Modules"), NULL); + gtk_object_set_data (GTK_OBJECT (intf_modules), "intf_modules", intf_modules); + gtk_window_set_policy (GTK_WINDOW (intf_modules), FALSE, FALSE, FALSE); + + dialog_vbox1 = GNOME_DIALOG (intf_modules)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_modules), "dialog_vbox1", dialog_vbox1); + gtk_widget_show (dialog_vbox1); + + label12 = gtk_label_new (_("Sorry, the module manager isn't functional yet. Please retry in a later version.")); + gtk_widget_ref (label12); + gtk_object_set_data_full (GTK_OBJECT (intf_modules), "label12", label12, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label12); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), label12, FALSE, FALSE, 0); + + dialog_action_area1 = GNOME_DIALOG (intf_modules)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_modules), "dialog_action_area1", dialog_action_area1); + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (dialog_action_area1), 8); + + gnome_dialog_append_button (GNOME_DIALOG (intf_modules), GNOME_STOCK_BUTTON_OK); + modules_ok = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_modules)->buttons)->data); + gtk_widget_ref (modules_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_modules), "modules_ok", modules_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (modules_ok); + GTK_WIDGET_SET_FLAGS (modules_ok, GTK_CAN_DEFAULT); + + gnome_dialog_append_button (GNOME_DIALOG (intf_modules), GNOME_STOCK_BUTTON_APPLY); + modules_apply = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_modules)->buttons)->data); + gtk_widget_ref (modules_apply); + gtk_object_set_data_full (GTK_OBJECT (intf_modules), "modules_apply", modules_apply, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (modules_apply); + GTK_WIDGET_SET_FLAGS (modules_apply, GTK_CAN_DEFAULT); + + gnome_dialog_append_button (GNOME_DIALOG (intf_modules), GNOME_STOCK_BUTTON_CANCEL); + modules_cancel = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_modules)->buttons)->data); + gtk_widget_ref (modules_cancel); + gtk_object_set_data_full (GTK_OBJECT (intf_modules), "modules_cancel", modules_cancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (modules_cancel); + GTK_WIDGET_SET_FLAGS (modules_cancel, GTK_CAN_DEFAULT); + + return intf_modules; +} + +static GnomeUIInfo playlist_add_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("Disc"), + NULL, + (gpointer) GtkDiscOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("File"), + NULL, + (gpointer) GtkFileOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Network"), + NULL, + (gpointer) GtkNetworkOpenShow, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Url"), + NULL, + (gpointer) GtkPlaylistAddUrl, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +static GnomeUIInfo playlist_delete_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("All"), + NULL, + (gpointer) GtkPlaylistDeleteAll, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Item"), + NULL, + (gpointer) GtkPlaylistDeleteSelected, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +static GnomeUIInfo playlist_selection_menu_uiinfo[] = +{ + { + GNOME_APP_UI_ITEM, N_("Crop"), + NULL, + (gpointer) GtkPlaylistCrop, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Invert"), + NULL, + (gpointer) GtkPlaylistInvert, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_ITEM, N_("Select"), + NULL, + (gpointer) GtkPlaylistSelect, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +static GnomeUIInfo playlist_menubar_uiinfo[] = +{ + { + GNOME_APP_UI_SUBTREE, N_("Add"), + NULL, + playlist_add_menu_uiinfo, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_SUBTREE, N_("Delete"), + NULL, + playlist_delete_menu_uiinfo, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + { + GNOME_APP_UI_SUBTREE, N_("Selection"), + NULL, + playlist_selection_menu_uiinfo, NULL, NULL, + GNOME_APP_PIXMAP_NONE, NULL, + 0, (GdkModifierType) 0, NULL + }, + GNOMEUIINFO_END +}; + +GtkWidget* +create_intf_playlist (void) +{ + GtkWidget *intf_playlist; + GtkWidget *playlist_vbox; + GtkWidget *playlist_scrolledwindow; + GtkWidget *playlist_viewport; + GtkWidget *playlist_frame; + GtkWidget *playlist_clist; + GtkWidget *playlist_label_url; + GtkWidget *playlist_label_duration; + GtkWidget *playlist_menubar; + GtkWidget *playlist_action; + GtkWidget *playlist_ok; + GtkWidget *playlist_cancel; + + intf_playlist = gnome_dialog_new (_("Playlist"), NULL); + gtk_object_set_data (GTK_OBJECT (intf_playlist), "intf_playlist", intf_playlist); + gtk_window_set_default_size (GTK_WINDOW (intf_playlist), 400, 300); + gtk_window_set_policy (GTK_WINDOW (intf_playlist), TRUE, TRUE, FALSE); + gnome_dialog_close_hides (GNOME_DIALOG (intf_playlist), TRUE); + + playlist_vbox = GNOME_DIALOG (intf_playlist)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_playlist), "playlist_vbox", playlist_vbox); + gtk_widget_show (playlist_vbox); + + playlist_scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (playlist_scrolledwindow); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_scrolledwindow", playlist_scrolledwindow, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_scrolledwindow); + gtk_box_pack_start (GTK_BOX (playlist_vbox), playlist_scrolledwindow, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (playlist_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + playlist_viewport = gtk_viewport_new (NULL, NULL); + gtk_widget_ref (playlist_viewport); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_viewport", playlist_viewport, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_viewport); + gtk_container_add (GTK_CONTAINER (playlist_scrolledwindow), playlist_viewport); + + playlist_frame = gtk_frame_new (_("Playlist")); + gtk_widget_ref (playlist_frame); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_frame", playlist_frame, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_frame); + gtk_container_add (GTK_CONTAINER (playlist_viewport), playlist_frame); + gtk_container_set_border_width (GTK_CONTAINER (playlist_frame), 4); + gtk_frame_set_label_align (GTK_FRAME (playlist_frame), 0.05, 0.5); + + playlist_clist = gtk_clist_new (2); + gtk_widget_ref (playlist_clist); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_clist", playlist_clist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_clist); + gtk_container_add (GTK_CONTAINER (playlist_frame), playlist_clist); + gtk_clist_set_column_width (GTK_CLIST (playlist_clist), 0, 287); + gtk_clist_set_column_width (GTK_CLIST (playlist_clist), 1, 70); + gtk_clist_set_selection_mode (GTK_CLIST (playlist_clist), GTK_SELECTION_EXTENDED); + gtk_clist_column_titles_show (GTK_CLIST (playlist_clist)); + + playlist_label_url = gtk_label_new (_("Url")); + gtk_widget_ref (playlist_label_url); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_label_url", playlist_label_url, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_label_url); + gtk_clist_set_column_widget (GTK_CLIST (playlist_clist), 0, playlist_label_url); + + playlist_label_duration = gtk_label_new (_("Duration")); + gtk_widget_ref (playlist_label_duration); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_label_duration", playlist_label_duration, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_label_duration); + gtk_clist_set_column_widget (GTK_CLIST (playlist_clist), 1, playlist_label_duration); + + playlist_menubar = gtk_menu_bar_new (); + gtk_widget_ref (playlist_menubar); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_menubar", playlist_menubar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_menubar); + gtk_box_pack_start (GTK_BOX (playlist_vbox), playlist_menubar, FALSE, FALSE, 0); + gnome_app_fill_menu (GTK_MENU_SHELL (playlist_menubar), playlist_menubar_uiinfo, + NULL, FALSE, 0); + + gtk_widget_ref (playlist_menubar_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add", + playlist_menubar_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_add_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_disc", + playlist_add_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_add_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_file", + playlist_add_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_add_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_network", + playlist_add_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_add_menu_uiinfo[3].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_url", + playlist_add_menu_uiinfo[3].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_menubar_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete", + playlist_menubar_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_delete_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete_all", + playlist_delete_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_delete_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete_item", + playlist_delete_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_menubar_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection", + playlist_menubar_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_selection_menu_uiinfo[0].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_crop", + playlist_selection_menu_uiinfo[0].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_selection_menu_uiinfo[1].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_invert", + playlist_selection_menu_uiinfo[1].widget, + (GtkDestroyNotify) gtk_widget_unref); + + gtk_widget_ref (playlist_selection_menu_uiinfo[2].widget); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_select", + playlist_selection_menu_uiinfo[2].widget, + (GtkDestroyNotify) gtk_widget_unref); + + playlist_action = GNOME_DIALOG (intf_playlist)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_playlist), "playlist_action", playlist_action); + gtk_widget_show (playlist_action); + gtk_button_box_set_layout (GTK_BUTTON_BOX (playlist_action), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (playlist_action), 8); + gtk_button_box_set_child_size (GTK_BUTTON_BOX (playlist_action), 100, 38); + + gnome_dialog_append_button (GNOME_DIALOG (intf_playlist), GNOME_STOCK_BUTTON_OK); + playlist_ok = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_playlist)->buttons)->data); + gtk_widget_ref (playlist_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_ok", playlist_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_ok); + GTK_WIDGET_SET_FLAGS (playlist_ok, GTK_CAN_DEFAULT); + + gnome_dialog_append_button (GNOME_DIALOG (intf_playlist), GNOME_STOCK_BUTTON_CANCEL); + playlist_cancel = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_playlist)->buttons)->data); + gtk_widget_ref (playlist_cancel); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_cancel", playlist_cancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_cancel); + GTK_WIDGET_SET_FLAGS (playlist_cancel, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (intf_playlist), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (intf_playlist), "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "event", + GTK_SIGNAL_FUNC (GtkPlaylistEvent), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "drag_data_received", + GTK_SIGNAL_FUNC (GtkPlaylistDragData), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "drag_motion", + GTK_SIGNAL_FUNC (GtkPlaylistDragMotion), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_ok), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistOk), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_cancel), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistCancel), + NULL); + + return intf_playlist; +} + +GtkWidget* +create_intf_jump (void) +{ + GtkWidget *intf_jump; + GtkWidget *jump_vbox; + GtkWidget *jump_frame; + GtkWidget *jump_box; + GtkWidget *jump_label3; + GtkObject *jump_second_spinbutton_adj; + GtkWidget *jump_second_spinbutton; + GtkWidget *jump_label1; + GtkObject *jump_minute_spinbutton_adj; + GtkWidget *jump_minute_spinbutton; + GtkWidget *jump_label2; + GtkObject *jump_hour_spinbutton_adj; + GtkWidget *jump_hour_spinbutton; + GtkWidget *jump_action; + GtkWidget *jump_ok; + GtkWidget *jump_cancel; + + intf_jump = gnome_dialog_new (NULL, NULL); + gtk_object_set_data (GTK_OBJECT (intf_jump), "intf_jump", intf_jump); + gtk_window_set_policy (GTK_WINDOW (intf_jump), FALSE, FALSE, FALSE); + + jump_vbox = GNOME_DIALOG (intf_jump)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_jump), "jump_vbox", jump_vbox); + gtk_widget_show (jump_vbox); + + jump_frame = gtk_frame_new (_("Jump to: ")); + gtk_widget_ref (jump_frame); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_frame", jump_frame, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_frame); + gtk_box_pack_start (GTK_BOX (jump_vbox), jump_frame, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (jump_frame), 5); + gtk_frame_set_label_align (GTK_FRAME (jump_frame), 0.05, 0.5); + + jump_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (jump_box); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_box", jump_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_box); + gtk_container_add (GTK_CONTAINER (jump_frame), jump_box); + gtk_container_set_border_width (GTK_CONTAINER (jump_box), 5); + + jump_label3 = gtk_label_new (_("s.")); + gtk_widget_ref (jump_label3); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_label3", jump_label3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_label3); + gtk_box_pack_end (GTK_BOX (jump_box), jump_label3, FALSE, FALSE, 0); + + jump_second_spinbutton_adj = gtk_adjustment_new (0, 0, 100, 1, 10, 10); + jump_second_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_second_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_second_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_second_spinbutton", jump_second_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_second_spinbutton); + gtk_box_pack_end (GTK_BOX (jump_box), jump_second_spinbutton, FALSE, FALSE, 5); + + jump_label1 = gtk_label_new (_("m:")); + gtk_widget_ref (jump_label1); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_label1", jump_label1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_label1); + gtk_box_pack_end (GTK_BOX (jump_box), jump_label1, FALSE, FALSE, 5); + + jump_minute_spinbutton_adj = gtk_adjustment_new (0, 0, 59, 1, 10, 10); + jump_minute_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_minute_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_minute_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_minute_spinbutton", jump_minute_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_minute_spinbutton); + gtk_box_pack_end (GTK_BOX (jump_box), jump_minute_spinbutton, FALSE, FALSE, 5); + + jump_label2 = gtk_label_new (_("h:")); + gtk_widget_ref (jump_label2); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_label2", jump_label2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_label2); + gtk_box_pack_end (GTK_BOX (jump_box), jump_label2, FALSE, FALSE, 5); + + jump_hour_spinbutton_adj = gtk_adjustment_new (0, 0, 10, 1, 10, 10); + jump_hour_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_hour_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_hour_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_hour_spinbutton", jump_hour_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_hour_spinbutton); + gtk_box_pack_end (GTK_BOX (jump_box), jump_hour_spinbutton, FALSE, FALSE, 5); + + jump_action = GNOME_DIALOG (intf_jump)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_jump), "jump_action", jump_action); + gtk_widget_show (jump_action); + gtk_button_box_set_layout (GTK_BUTTON_BOX (jump_action), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (jump_action), 8); + + gnome_dialog_append_button (GNOME_DIALOG (intf_jump), GNOME_STOCK_BUTTON_OK); + jump_ok = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_jump)->buttons)->data); + gtk_widget_ref (jump_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_ok", jump_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_ok); + GTK_WIDGET_SET_FLAGS (jump_ok, GTK_CAN_DEFAULT); + + gnome_dialog_append_button (GNOME_DIALOG (intf_jump), GNOME_STOCK_BUTTON_CANCEL); + jump_cancel = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_jump)->buttons)->data); + gtk_widget_ref (jump_cancel); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_cancel", jump_cancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_cancel); + GTK_WIDGET_SET_FLAGS (jump_cancel, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (jump_ok), "clicked", + GTK_SIGNAL_FUNC (GtkJumpOk), + NULL); + gtk_signal_connect (GTK_OBJECT (jump_cancel), "clicked", + GTK_SIGNAL_FUNC (GtkJumpCancel), + NULL); + + return intf_jump; +} + +GtkWidget* +create_intf_messages (void) +{ + GtkWidget *intf_messages; + GtkWidget *dialog_vbox6; + GtkWidget *scrolledwindow1; + GtkWidget *messages_textbox; + GtkWidget *dialog_action_area6; + GtkWidget *messages_ok; + + intf_messages = gnome_dialog_new (_("Messages"), NULL); + gtk_object_set_data (GTK_OBJECT (intf_messages), "intf_messages", intf_messages); + gtk_window_set_policy (GTK_WINDOW (intf_messages), TRUE, TRUE, FALSE); + gnome_dialog_close_hides (GNOME_DIALOG (intf_messages), TRUE); + + dialog_vbox6 = GNOME_DIALOG (intf_messages)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_messages), "dialog_vbox6", dialog_vbox6); + gtk_widget_show (dialog_vbox6); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow1); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "scrolledwindow1", scrolledwindow1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (dialog_vbox6), scrolledwindow1, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + messages_textbox = gtk_text_new (NULL, NULL); + gtk_widget_ref (messages_textbox); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "messages_textbox", messages_textbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (messages_textbox); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), messages_textbox); + gtk_widget_set_usize (messages_textbox, 600, 400); + + dialog_action_area6 = GNOME_DIALOG (intf_messages)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_messages), "dialog_action_area6", dialog_action_area6); + gtk_widget_show (dialog_action_area6); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area6), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (dialog_action_area6), 8); + + gnome_dialog_append_button (GNOME_DIALOG (intf_messages), GNOME_STOCK_BUTTON_OK); + messages_ok = GTK_WIDGET (g_list_last (GNOME_DIALOG (intf_messages)->buttons)->data); + gtk_widget_ref (messages_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "messages_ok", messages_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (messages_ok); + GTK_WIDGET_SET_FLAGS (messages_ok, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (intf_messages), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (intf_messages), "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (messages_ok), "clicked", + GTK_SIGNAL_FUNC (GtkMessagesOk), + NULL); + + return intf_messages; +} + diff --git a/modules/gui/gtk/gnome_interface.h b/modules/gui/gtk/gnome_interface.h new file mode 100644 index 0000000000..a6a2317bcd --- /dev/null +++ b/modules/gui/gtk/gnome_interface.h @@ -0,0 +1,13 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_intf_window (void); +GtkWidget* create_intf_popup (void); +GtkWidget* create_intf_about (void); +GtkWidget* create_intf_open (void); +GtkWidget* create_intf_file (void); +GtkWidget* create_intf_modules (void); +GtkWidget* create_intf_playlist (void); +GtkWidget* create_intf_jump (void); +GtkWidget* create_intf_messages (void); diff --git a/modules/gui/gtk/gnome_support.c b/modules/gui/gtk/gnome_support.c new file mode 100644 index 0000000000..d59198cd7b --- /dev/null +++ b/modules/gui/gtk/gnome_support.c @@ -0,0 +1,146 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "gnome_support.h" + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget, + gboolean gnome_pixmap); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" ", +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget, + gboolean gnome_pixmap) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + if (gnome_pixmap) + { + return gnome_pixmap_new_from_xpm_d (dummy_pixmap_xpm); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename, + gboolean gnome_pixmap) +{ + GtkWidget *pixmap; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + gchar *pathname; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget, gnome_pixmap); + + pathname = gnome_pixmap_file (filename); + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return create_dummy_pixmap (widget, gnome_pixmap); + } + + if (gnome_pixmap) + { + pixmap = gnome_pixmap_new_from_file (pathname); + g_free (pathname); + return pixmap; + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, pathname); + if (gdkpixmap == NULL) + { + g_warning (_("Couldn't create pixmap from file: %s"), pathname); + g_free (pathname); + return create_dummy_pixmap (widget, gnome_pixmap); + } + g_free (pathname); + + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to create imlib images. */ +GdkImlibImage* +create_image (const gchar *filename) +{ + GdkImlibImage *image; + gchar *pathname; + + pathname = gnome_pixmap_file (filename); + if (!pathname) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return NULL; + } + + image = gdk_imlib_load_image (pathname); + g_free (pathname); + return image; +} + diff --git a/modules/gui/gtk/gnome_support.h b/modules/gui/gtk/gnome_support.h new file mode 100644 index 0000000000..d9bb0728a7 --- /dev/null +++ b/modules/gui/gtk/gnome_support.h @@ -0,0 +1,34 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#include + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename, + gboolean gnome_pixmap); + +GdkImlibImage* create_image (const gchar *filename); + diff --git a/modules/gui/gtk/gtk.c b/modules/gui/gtk/gtk.c new file mode 100644 index 0000000000..7309aa3c49 --- /dev/null +++ b/modules/gui/gtk/gtk.c @@ -0,0 +1,494 @@ +/***************************************************************************** + * gtk.c : Gtk+ plugin for vlc + ***************************************************************************** + * Copyright (C) 2000-2001 VideoLAN + * $Id: gtk.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include /* ENOMEM */ +#include /* strerror() */ +#include + +#include +#include + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "menu.h" +#include "display.h" +#include "common.h" + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static void Run ( intf_thread_t * ); +static gint Manage ( gpointer ); + +/***************************************************************************** + * Local variables (mutex-protected). + *****************************************************************************/ +static void ** pp_global_data = NULL; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define TOOLTIPS_TEXT N_("show tooltips") +#define TOOLTIPS_LONGTEXT N_("Show tooltips for configuration options.") + +#define PREFS_MAXH_TEXT N_("maximum height for the configuration windows") +#define PREFS_MAXH_LONGTEXT N_( \ + "You can set the maximum height that the configuration windows in the " \ + "preferences menu will occupy.") + +vlc_module_begin(); +#ifdef WIN32 + int i = 90; +#else + int i = getenv( "DISPLAY" ) == NULL ? 10 : 90; +#endif + pp_global_data = p_module->p_vlc->pp_global_data; + + add_category_hint( N_("Miscellaneous"), NULL ); + add_bool( "gtk-tooltips", 1, GtkHideTooltips, + TOOLTIPS_TEXT, TOOLTIPS_LONGTEXT ); + add_integer( "gtk-prefs-maxh", 480, NULL, + PREFS_MAXH_TEXT, PREFS_MAXH_LONGTEXT ); + + set_description( _("Gtk+ interface module") ); + set_capability( "interface", i ); + set_callbacks( Open, Close ); + set_program( "gvlc" ); +vlc_module_end(); + +/***************************************************************************** + * g_atexit: kludge to avoid the Gtk+ thread to segfault at exit + ***************************************************************************** + * gtk_init() makes several calls to g_atexit() which calls atexit() to + * register tidying callbacks to be called at program exit. Since the Gtk+ + * plugin is likely to be unloaded at program exit, we have to export this + * symbol to intercept the g_atexit() calls. Talk about crude hack. + *****************************************************************************/ +void g_atexit( GVoidFunc func ) +{ + intf_thread_t *p_intf; + + int i_dummy; + + if( pp_global_data == NULL ) + { + atexit( func ); + return; + } + + p_intf = (intf_thread_t *)*pp_global_data; + if( p_intf == NULL ) + { + return; + } + + for( i_dummy = 0; + i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL; + i_dummy++ ) + { + ; + } + + if( i_dummy >= MAX_ATEXIT - 1 ) + { + msg_Err( p_intf, "too many atexit() callbacks to register" ); + return; + } + + p_intf->p_sys->pf_callback[i_dummy] = func; + p_intf->p_sys->pf_callback[i_dummy + 1] = NULL; +} + +/***************************************************************************** + * Open: initialize and create window + *****************************************************************************/ +static int Open( 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 ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + p_intf->pf_run = Run; + + p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + + /* Initialize Gtk+ thread */ + p_intf->p_sys->b_playing = 0; + p_intf->p_sys->b_popup_changed = 0; + p_intf->p_sys->b_window_changed = 0; + p_intf->p_sys->b_playlist_changed = 0; + + p_intf->p_sys->p_input = NULL; + p_intf->p_sys->i_playing = -1; + p_intf->p_sys->b_slider_free = 1; + + p_intf->p_sys->pf_callback[0] = NULL; + + p_intf->p_sys->i_part = 0; + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface window + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: Gtk+ thread + ***************************************************************************** + * this part of the interface is in a separate thread so that we can call + * gtk_main() from within it without annoying the rest of the program. + * XXX: the approach may look kludgy, and probably is, but I could not find + * a better way to dynamically load a Gtk+ interface at runtime. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + /* gtk_init needs to know the command line. We don't care, so we + * give it an empty one */ + char *p_args[] = { "" }; + char **pp_args = p_args; + int i_args = 1; + int i_dummy; + + /* The data types we are allowed to receive */ + static GtkTargetEntry target_table[] = + { + { "STRING", 0, DROP_ACCEPT_STRING }, + { "text/uri-list", 0, DROP_ACCEPT_TEXT_URI_LIST }, + { "text/plain", 0, DROP_ACCEPT_TEXT_PLAIN } + }; + + /* Initialize Gtk+ */ + + /* gtk_init will register stuff with g_atexit, so we need to take + * the global lock if we want to be able to intercept the calls */ + vlc_mutex_lock( p_intf->p_vlc->p_global_lock ); + *p_intf->p_vlc->pp_global_data = p_intf; + gtk_init( &i_args, &pp_args ); + vlc_mutex_unlock( p_intf->p_vlc->p_global_lock ); + + /* Create some useful widgets that will certainly be used */ + p_intf->p_sys->p_window = create_intf_window(); + p_intf->p_sys->p_popup = create_intf_popup(); + p_intf->p_sys->p_playwin = create_intf_playlist(); + p_intf->p_sys->p_messages = create_intf_messages(); + p_intf->p_sys->p_tooltips = gtk_tooltips_new(); + + /* Set the title of the main window */ + gtk_window_set_title( GTK_WINDOW(p_intf->p_sys->p_window), + VOUT_TITLE " (Gtk+ interface)"); + + /* Accept file drops on the main window */ + gtk_drag_dest_set( GTK_WIDGET( p_intf->p_sys->p_window ), + GTK_DEST_DEFAULT_ALL, target_table, + 1, GDK_ACTION_COPY ); + + /* Accept file drops on the playlist window */ + gtk_drag_dest_set( GTK_WIDGET( lookup_widget( p_intf->p_sys->p_playwin, + "playlist_clist") ), + GTK_DEST_DEFAULT_ALL, target_table, + 1, GDK_ACTION_COPY ); + + /* Get the slider object */ + p_intf->p_sys->p_slider_frame = GTK_FRAME( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_window ), "slider_frame" ) ); + + /* Configure the log window */ + p_intf->p_sys->p_messages_text = GTK_TEXT( gtk_object_get_data( + GTK_OBJECT(p_intf->p_sys->p_messages ), "messages_textbox" ) ); + gtk_text_set_line_wrap( p_intf->p_sys->p_messages_text, TRUE); + gtk_text_set_word_wrap( p_intf->p_sys->p_messages_text, FALSE); + + /* Get the interface labels */ +#define P_LABEL( name ) GTK_LABEL( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), name ) ) + p_intf->p_sys->p_label_title = P_LABEL( "title_label" ); + p_intf->p_sys->p_label_chapter = P_LABEL( "chapter_label" ); +#undef P_LABEL + + /* Connect the date display to the slider */ +#define P_SLIDER GTK_RANGE( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_window ), "slider" ) ) + p_intf->p_sys->p_adj = gtk_range_get_adjustment( P_SLIDER ); + + gtk_signal_connect ( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed", + GTK_SIGNAL_FUNC( GtkDisplayDate ), NULL ); + p_intf->p_sys->f_adj_oldvalue = 0; +#undef P_SLIDER + + /* We don't create these ones yet because we perhaps won't need them */ + p_intf->p_sys->p_about = NULL; + p_intf->p_sys->p_modules = NULL; + p_intf->p_sys->p_open = NULL; + p_intf->p_sys->p_jump = NULL; + + /* Hide tooltips if the option is set */ + if( !config_GetInt( p_intf, "gtk-tooltips" ) ) + { + gtk_tooltips_disable( p_intf->p_sys->p_tooltips ); + } + + /* Store p_intf to keep an eye on it */ + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_popup), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_playwin ), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_messages ), + "p_intf", p_intf ); + + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_adj), + "p_intf", p_intf ); + + /* Show the control window */ + gtk_widget_show( p_intf->p_sys->p_window ); + + /* Sleep to avoid using all CPU - since some interfaces needs to access + * keyboard events, a 100ms delay is a good compromise */ + i_dummy = gtk_timeout_add( INTF_IDLE_SLEEP / 1000, Manage, p_intf ); + + /* Enter Gtk mode */ + gtk_main(); + + /* Remove the timeout */ + gtk_timeout_remove( i_dummy ); + + /* Destroy the Tooltips structure */ + gtk_object_destroy( GTK_OBJECT(p_intf->p_sys->p_tooltips) ); + + /* Launch stored callbacks */ + for( i_dummy = 0; + i_dummy < MAX_ATEXIT && p_intf->p_sys->pf_callback[i_dummy] != NULL; + i_dummy++ ) + { + p_intf->p_sys->pf_callback[i_dummy](); + } +} + +/* following functions are local */ + +/***************************************************************************** + * Manage: manage main thread messages + ***************************************************************************** + * In this function, called approx. 10 times a second, we check what the + * main program wanted to tell us. + *****************************************************************************/ +static gint Manage( gpointer p_data ) +{ +#define p_intf ((intf_thread_t *)p_data) + int i_start, i_stop; + + vlc_mutex_lock( &p_intf->change_lock ); + + /* If the "display popup" flag has changed */ + if( p_intf->b_menu_change ) + { + if( !GTK_IS_WIDGET( p_intf->p_sys->p_popup ) ) + { + p_intf->p_sys->p_popup = create_intf_popup(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_popup ), + "p_intf", p_intf ); + } + gtk_menu_popup( GTK_MENU( p_intf->p_sys->p_popup ), + NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME ); + p_intf->b_menu_change = 0; + } + + /* Update the log window */ + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + i_stop = *p_intf->p_sys->p_sub->pi_stop; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + + if( p_intf->p_sys->p_sub->i_start != i_stop ) + { + static GdkColor white = { 0, 0xffff, 0xffff, 0xffff }; + static GdkColor gray = { 0, 0xaaaa, 0xaaaa, 0xaaaa }; + static GdkColor yellow = { 0, 0xffff, 0xffff, 0x6666 }; + static GdkColor red = { 0, 0xffff, 0x6666, 0x6666 }; + + static const char * ppsz_type[4] = { ": ", " error: ", " warning: ", + " debug: " }; + static GdkColor * pp_color[4] = { &white, &red, &yellow, &gray }; + + for( i_start = p_intf->p_sys->p_sub->i_start; + i_start != i_stop; + i_start = (i_start+1) % VLC_MSG_QSIZE ) + { + /* Append all messages to log window */ + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, p_intf->p_sys->p_sub->p_msg[i_start].psz_module, -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, ppsz_type[p_intf->p_sys->p_sub->p_msg[i_start].i_type], + -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, + pp_color[p_intf->p_sys->p_sub->p_msg[i_start].i_type], NULL, + p_intf->p_sys->p_sub->p_msg[i_start].psz_msg, -1 ); + + gtk_text_insert( p_intf->p_sys->p_messages_text, NULL, &gray, + NULL, "\n", -1 ); + } + + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + p_intf->p_sys->p_sub->i_start = i_start; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + + gtk_text_set_point( p_intf->p_sys->p_messages_text, + gtk_text_get_length( p_intf->p_sys->p_messages_text ) ); + } + + /* Update the playlist */ + GtkPlayListManage( p_data ); + + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + if( p_intf->p_sys->p_input ) + { + input_thread_t *p_input = p_intf->p_sys->p_input; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( !p_input->b_die ) + { + /* New input or stream map change */ + if( p_input->stream.b_changed ) + { + GtkModeManage( p_intf ); + GtkSetupMenus( p_intf ); + p_intf->p_sys->b_playing = 1; + } + + /* Manage the slider */ + if( p_input->stream.b_seekable && p_intf->p_sys->b_playing ) + { + float newvalue = p_intf->p_sys->p_adj->value; + +#define p_area p_input->stream.p_selected_area + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( newvalue == p_intf->p_sys->f_adj_oldvalue ) + { + /* Update the value */ + p_intf->p_sys->p_adj->value = + p_intf->p_sys->f_adj_oldvalue = + ( 100. * p_area->i_tell ) / p_area->i_size; + + gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), + "value_changed" ); + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else if( p_intf->p_sys->b_slider_free ) + { + off_t i_seek = ( newvalue * p_area->i_size ) / 100; + + /* release the lock to be able to seek */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); + input_Seek( p_input, i_seek, INPUT_SEEK_SET ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* Update the old value */ + p_intf->p_sys->f_adj_oldvalue = newvalue; + } +#undef p_area + } + + if( p_intf->p_sys->i_part != + p_input->stream.p_selected_area->i_part ) + { + p_intf->p_sys->b_chapter_update = 1; + GtkSetupMenus( p_intf ); + } + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + else if( p_intf->p_sys->b_playing && !p_intf->b_die ) + { + GtkModeManage( p_intf ); + p_intf->p_sys->b_playing = 0; + } + + if( p_intf->b_die ) + { + vlc_mutex_unlock( &p_intf->change_lock ); + + /* Prepare to die, young Skywalker */ + gtk_main_quit(); + + /* Just in case */ + return( FALSE ); + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + return( TRUE ); + +#undef p_intf +} diff --git a/modules/gui/gtk/gtk.glade b/modules/gui/gtk/gtk.glade new file mode 100644 index 0000000000..2e11ce7a2b --- /dev/null +++ b/modules/gui/gtk/gtk.glade @@ -0,0 +1,3545 @@ + + + + + VideoLAN Client + vlc + + + pixmaps + C + False + True + False + False + gtk_interface.c + gtk_interface.h + gtk_callbacks.c + gtk_callbacks.h + gtk_support.c + gtk_support.h + + + + GtkWindow + intf_window + + drag_data_received + GtkWindowDrag + Tue, 09 Jul 2002 09:09:48 GMT + + + delete_event + GtkWindowDelete + Tue, 09 Jul 2002 09:09:53 GMT + + VideoLAN Client + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + True + + + GtkVBox + GnomeDock:contents + window_vbox + False + 0 + + + GtkHandleBox + menubar_handlebox + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + 0 + False + True + + + + GtkMenuBar + menubar + GTK_SHADOW_OUT + + + GtkMenuItem + menubar_file + + False + + + GtkMenu + menubar_file_menu + + + GtkMenuItem + menubar_open + Open a File + + 0 + GDK_F3 + activate + + + activate + GtkFileOpenShow + Mon, 14 May 2001 21:27:36 GMT + + + False + + + + GtkMenuItem + menubar_disc + Open a DVD or VCD + + 0 + GDK_F4 + activate + + + activate + GtkDiscOpenShow + Mon, 14 May 2001 21:27:47 GMT + + + False + + + + GtkMenuItem + menubar_network + Select a Network Stream + + 0 + GDK_F5 + activate + + + activate + GtkNetworkOpenShow + Mon, 14 May 2001 21:28:06 GMT + + + False + + + + GtkMenuItem + separator4 + False + + + + GtkMenuItem + menubar_eject + Eject disc + + activate + GtkDiscEject + Fri, 21 Dec 2001 12:51:34 GMT + + + False + + + + GtkMenuItem + separator14 + False + + + + GtkMenuItem + menubar_close + Close the window + + GDK_CONTROL_MASK + GDK_W + activate + + + activate + GtkClose + Mon, 15 Jul 2002 08:55:26 GMT + + + False + + + + GtkMenuItem + menubar_exit + Exit the program + + GDK_CONTROL_MASK + GDK_Q + activate + + + activate + GtkExit + Mon, 14 May 2001 21:28:20 GMT + + + False + + + + + + GtkMenuItem + menubar_view + + False + + + GtkMenu + menubar_view_menu + + + GtkMenuItem + menubar_interface_hide + Hide the main interface window + + activate + GtkWindowToggle + Mon, 14 May 2001 21:32:49 GMT + + + False + + + + GtkMenuItem + menubar_fullscreen + + activate + GtkFullscreen + Mon, 14 May 2001 21:29:21 GMT + + + False + + + + GtkMenuItem + separator13 + False + + + + GtkMenuItem + menubar_program + False + Choose the program + + False + + + + GtkMenuItem + menubar_title + False + Navigate through the stream + + False + + + + GtkMenuItem + menubar_chapter + False + + False + + + + GtkMenuItem + separator11 + False + + + + GtkMenuItem + menubar_playlist + Open the playlist window + + activate + GtkPlaylistShow + Mon, 14 May 2001 21:29:34 GMT + + + False + + + + GtkMenuItem + menubar_modules + False + Open the module manager + + activate + GtkModulesShow + Mon, 14 May 2001 21:29:44 GMT + + + False + + + + GtkMenuItem + menubar_messages + Open the messages window + + activate + GtkMessagesShow + Tue, 19 Feb 2002 02:03:47 GMT + + + False + + + + + + GtkMenuItem + menubar_settings + + False + + + GtkMenu + menubar_settings_menu + + + GtkMenuItem + menubar_audio + False + Select audio channel + + False + + + + GtkMenuItem + menubar_subpictures + False + Select subtitles channel + + False + + + + GtkMenuItem + separator8 + False + + + + GtkMenuItem + menubar_preferences + Configure the application + + activate + GtkPreferencesShow + Mon, 14 May 2001 21:30:02 GMT + + + False + + + + + + GtkMenuItem + menubar_help + + False + + + GtkMenu + menubar_help_menu + + + GtkMenuItem + menubar_about + About this application + + activate + GtkAboutShow + Mon, 14 May 2001 21:30:15 GMT + + + False + + + + + + + + GtkHandleBox + toolbar_handlebox + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + 0 + False + True + + + + GtkToolbar + toolbar + 1 + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + 16 + GTK_TOOLBAR_SPACE_LINE + GTK_RELIEF_NONE + True + + + GtkButton + Toolbar:button + toolbar_open + Open a File + + clicked + GtkFileOpenShow + Mon, 08 Jul 2002 16:14:58 GMT + + + + + + GtkButton + Toolbar:button + toolbar_disc + Open a DVD or VCD + + clicked + GtkDiscOpenShow + Sun, 13 May 2001 15:10:30 GMT + + + + + + GtkButton + Toolbar:button + toolbar_network + Select a Network Stream + + clicked + GtkNetworkOpenShow + Sun, 13 May 2001 15:10:37 GMT + + + + + + GtkButton + Toolbar:button + toolbar_sat + Open a Satellite Card + + clicked + GtkSatOpenShow + Sun, 24 Mar 2002 15:08:57 GMT + + + + + + GtkButton + Toolbar:button + toolbar_back + False + Go Backward + + clicked + GtkControlBack + Sun, 13 May 2001 15:10:47 GMT + + + + True + + + + + GtkButton + Toolbar:button + toolbar_stop + Stop Stream + + clicked + GtkControlStop + Sun, 13 May 2001 15:10:57 GMT + + + + + + GtkButton + Toolbar:button + toolbar_eject + + clicked + GtkDiscEject + Fri, 21 Dec 2001 15:33:26 GMT + + + + + + GtkButton + Toolbar:button + toolbar_play + Play Stream + + clicked + GtkControlPlay + Sun, 13 May 2001 15:11:06 GMT + + + + + + GtkButton + Toolbar:button + toolbar_pause + False + Pause Stream + + clicked + GtkControlPause + Sun, 13 May 2001 15:11:13 GMT + + + + + + GtkButton + Toolbar:button + toolbar_slow + False + Play Slower + + clicked + GtkControlSlow + Sun, 13 May 2001 15:11:20 GMT + + + + True + + + + + GtkButton + Toolbar:button + toolbar_fast + False + Play Faster + + clicked + GtkControlFast + Sun, 13 May 2001 15:11:31 GMT + + + + + + GtkButton + Toolbar:button + toolbar_playlist + Open Playlist + + clicked + GtkPlaylistShow + Sun, 13 May 2001 15:11:38 GMT + + + + + + GtkButton + Toolbar:button + toolbar_prev + Previous File + + clicked + GtkPlaylistPrev + Sun, 13 May 2001 15:11:45 GMT + + + + + + GtkButton + Toolbar:button + toolbar_next + Next File + + clicked + GtkPlaylistNext + Sun, 13 May 2001 15:11:58 GMT + + + + + + + + GtkFrame + slider_frame + False + + 0.05 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHScale + slider + 500 + 15 + True + + button_release_event + GtkSliderRelease + Sun, 13 May 2001 14:40:22 GMT + + + button_press_event + GtkSliderPress + Sun, 13 May 2001 14:40:38 GMT + + False + GTK_POS_TOP + 3 + GTK_UPDATE_CONTINUOUS + 0 + 0 + 100 + 1 + 6.25 + 0 + + + + + GtkHBox + file_box + 500 + 24 + False + 0 + + 0 + True + True + + + + GtkLabel + label_status + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + + GtkHBox + dvd_box + 500 + 24 + False + False + 0 + + 0 + True + True + + + + GtkLabel + dvd_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + False + + + + + GtkHBox + title_box + False + 0 + + 0 + True + True + + + + GtkLabel + title + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + + + + + GtkLabel + title_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + + + + + GtkButton + title_prev_button + True + + clicked + GtkTitlePrev + Sun, 13 May 2001 14:41:41 GMT + + + GTK_RELIEF_NONE + + 5 + False + False + + + + + GtkButton + title_next_button + True + + clicked + GtkTitleNext + Sun, 13 May 2001 14:42:00 GMT + + + GTK_RELIEF_NONE + + 5 + False + False + + + + + + GtkVSeparator + dvd_separator + + 0 + True + True + + + + + GtkHBox + chapter_box + False + 0 + + 0 + True + True + + + + GtkLabel + chapter + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + + + + + GtkLabel + chapter_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + + + + + GtkButton + chapter_prev_button + True + + clicked + GtkChapterPrev + Sun, 13 May 2001 14:42:25 GMT + + + GTK_RELIEF_NONE + + 5 + False + False + + + + + GtkButton + chapter_next_button + True + + clicked + GtkChapterNext + Sun, 13 May 2001 14:42:42 GMT + + + GTK_RELIEF_NONE + + 5 + False + False + + + + + + + GtkHBox + network_box + 500 + 24 + False + False + 0 + + 0 + True + True + + + + GtkLabel + network_address_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + GtkHBox + network_channel_box + False + 0 + + 0 + True + False + + + + GtkLabel + channel_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + + + + + GtkSpinButton + network_channel_spinbutton + True + + activate + GtkNetworkJoin + Wed, 30 May 2001 02:48:10 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 100 + 1 + 10 + 10 + + 0 + False + True + + + + + GtkButton + network_channel_go_button + True + + clicked + GtkChannelGo + Wed, 30 May 2001 02:49:18 GMT + + + GTK_RELIEF_NONE + + 0 + False + False + + + + + + + GtkStatusbar + intf_statusbar + + 0 + False + False + + + + + + + GtkMenu + intf_popup + + + GtkMenuItem + popup_play + + activate + GtkControlPlay + Tue, 15 May 2001 13:53:43 GMT + + + False + + + + GtkMenuItem + popup_pause + False + + activate + GtkControlPause + Tue, 15 May 2001 13:53:37 GMT + + + False + + + + GtkMenuItem + popup_stop + + activate + GtkControlStop + Tue, 15 May 2001 13:53:29 GMT + + + False + + + + GtkMenuItem + popup_back + False + + activate + GtkControlBack + Tue, 15 May 2001 13:53:21 GMT + + + False + + + + GtkMenuItem + popup_slow + False + + activate + GtkControlSlow + Tue, 15 May 2001 13:53:15 GMT + + + False + + + + GtkMenuItem + popup_fast + False + + activate + GtkControlFast + Tue, 15 May 2001 13:53:07 GMT + + + False + + + + GtkMenuItem + separator6 + False + + + + GtkMenuItem + popup_interface_toggle + + activate + GtkWindowToggle + Tue, 15 May 2001 13:53:00 GMT + + + False + + + + GtkMenuItem + popup_fullscreen + + activate + GtkFullscreen + Tue, 15 May 2001 13:52:38 GMT + + + False + + + + GtkMenuItem + separator5 + False + + + + GtkMenuItem + popup_next + + activate + GtkPlaylistNext + Tue, 15 May 2001 13:52:31 GMT + + + False + + + + GtkMenuItem + popup_prev + + activate + GtkPlaylistPrev + Tue, 15 May 2001 13:52:23 GMT + + + False + + + + GtkMenuItem + popup_jump + + activate + GtkJumpShow + Tue, 15 May 2001 13:52:13 GMT + + + False + + + + GtkMenuItem + popup_program + False + + False + + + + GtkMenuItem + popup_navigation + False + + False + + + + GtkMenuItem + popup_audio + False + + False + + + + GtkMenuItem + popup_subpictures + False + + False + + + + GtkMenuItem + popup_open + + False + + + GtkMenu + popup_open_menu + + + GtkMenuItem + popup_file + Open a File + + activate + GtkFileOpenShow + Mon, 14 May 2001 21:33:55 GMT + + + False + + + + GtkMenuItem + popup_disc + Open a DVD or VCD + + activate + GtkDiscOpenShow + Mon, 14 May 2001 21:34:09 GMT + + + False + + + + GtkMenuItem + popup_network + Select a Network Stream + + activate + GtkNetworkOpenShow + Mon, 14 May 2001 21:34:23 GMT + + + False + + + + GtkMenuItem + separator12 + False + + + + GtkMenuItem + popup_about + + activate + GtkAboutShow + Mon, 14 May 2001 21:34:54 GMT + + + False + + + + + + GtkMenuItem + popup_playlist + + activate + GtkPlaylistShow + Tue, 15 May 2001 13:51:55 GMT + + + False + + + + GtkMenuItem + popup_preferences + + activate + GtkPreferencesShow + Tue, 15 May 2001 13:51:46 GMT + + + False + + + + GtkMenuItem + separator9 + False + + + + GtkMenuItem + popup_exit + + activate + GtkExit + Tue, 15 May 2001 13:52:03 GMT + + + False + + + + + GtkDialog + intf_about + 5 + About + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + False + False + False + + + GtkVBox + Dialog:vbox + dialog-vbox1 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area + 10 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + about_ok + True + True + True + + clicked + GtkAboutOk + Sun, 13 May 2001 14:47:20 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + True + + + + + + GtkVBox + vbox3 + False + 0 + + 0 + True + True + + + + GtkLabel + label14 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 10 + + 0 + True + True + + + + + GtkLabel + label18 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0.5 + 0 + 5 + + 0 + False + False + + + + + GtkFrame + frame1 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + False + False + + + + GtkLabel + label16 + + GTK_JUSTIFY_LEFT + False + 0.5 + 0 + 5 + 5 + + + + + GtkLabel + label17 + + GTK_JUSTIFY_LEFT + True + 0.5 + 0.5 + 0 + 5 + + 0 + False + False + + + + + + + + GtkDialog + intf_open + 5 + Open Target + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + False + True + False + + + GtkVBox + Dialog:vbox + dialog-vbox7 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area6 + 5 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkHBox + hbox18 + True + 5 + + 0 + True + True + + + + GtkHBox + hbox19 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + open_ok + True + + clicked + GtkOpenOk + Mon, 08 Jul 2002 14:52:19 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + True + + + + + GtkButton + open_cancel + True + + 0 + GDK_Escape + clicked + + + clicked + GtkOpenCancel + Mon, 08 Jul 2002 14:52:36 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + True + + + + + + + + GtkVBox + open_vbox + False + 5 + + 0 + True + True + + + + GtkFrame + frame10 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + False + True + + + + GtkHBox + hbox21 + 5 + False + 5 + + + GtkHBox + hbox22 + False + 0 + + 0 + False + True + + + + GtkLabel + label34 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + + GtkCombo + combo2 + False + True + False + True + False + + + 0 + True + True + + + + GtkEntry + GtkCombo:entry + entry_open + True + True + True + 0 + + + + + + + + GtkLabel + label36 + + GTK_JUSTIFY_LEFT + False + 0 + 1 + 0 + 0 + + 0 + True + True + + + + + GtkNotebook + open_notebook + True + + switch_page + GtkOpenNotebookChanged + True + Tue, 09 Jul 2002 14:01:19 GMT + + True + True + GTK_POS_TOP + False + 2 + 2 + False + + 0 + True + True + + + + GtkHBox + hbox20 + 5 + False + 5 + + + GtkCombo + combo1 + False + True + False + True + False + + + 0 + False + True + + + + GtkEntry + GtkCombo:entry + entry_file + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:22:33 GMT + + True + True + 0 + + + + + + GtkVBox + vbox13 + True + 0 + + 0 + False + False + + + + Placeholder + + + + GtkButton + open_browse + True + + clicked + GtkFileShow + Wed, 10 Jul 2002 11:37:05 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + False + + + + + Placeholder + + + + + + GtkLabel + Notebook:tab + open_file + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table5 + 5 + 4 + 2 + False + 5 + 5 + + + GtkLabel + label21 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label20 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + disc_chapter + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:45:38 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 + 1 + 65536 + 1 + 10 + 10 + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label35 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkHBox + hbox24 + False + 0 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + True + + + + GtkRadioButton + disc_dvd + True + + toggled + GtkDiscOpenDvd + Sun, 13 May 2001 14:48:29 GMT + + + False + True + disc + + 0 + False + False + + + + + GtkRadioButton + disc_vcd + True + + toggled + GtkDiscOpenVcd + Sun, 13 May 2001 14:48:39 GMT + + + False + True + disc + + 0 + False + False + + + + + + GtkLabel + label19 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + disc_title + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:45:04 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1 + 1 + 65536 + 1 + 10 + 10 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkEntry + disc_name + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:46:05 GMT + + True + True + 0 + /dev/dvd + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + + GtkLabel + Notebook:tab + open_disc + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table4 + 5 + 4 + 6 + False + 5 + 5 + + + GtkRadioButton + network_udp + True + + toggled + GtkNetworkOpenUDP + Thu, 16 May 2002 00:47:18 GMT + + + False + True + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_multicast + True + + toggled + GtkNetworkOpenMulticast + Thu, 16 May 2002 00:47:05 GMT + + + False + True + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_channel + True + + toggled + GtkNetworkOpenChannel + Thu, 16 May 2002 01:44:15 GMT + + + False + True + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkRadioButton + network_http + True + + toggled + GtkNetworkOpenHTTP + Thu, 16 May 2002 00:47:42 GMT + + + False + True + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_udp_port_label + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_multicast_address_label + False + + GTK_JUSTIFY_RIGHT + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_channel_address_label + False + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_http_url_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCombo + network_multicast_address_combo + False + False + True + False + True + False + + + 2 + 4 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + network_multicast_address + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:06 GMT + + True + True + 0 + + + + + + GtkCombo + network_channel_address_combo + False + False + True + False + True + False + + + 2 + 4 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + network_channel_address + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:16 GMT + + True + True + 0 + + + + + + GtkLabel + network_multicast_port_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 4 + 5 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + network_channel_port_label + False + + GTK_JUSTIFY_CENTER + False + 1 + 0.5 + 0 + 0 + + 4 + 5 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + network_multicast_port + 75 + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:36 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1234 + 0 + 65535 + 1 + 10 + 10 + + 5 + 6 + 1 + 2 + 0 + 0 + True + False + False + False + True + False + + + + + GtkSpinButton + network_channel_port + 75 + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:45 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 6010 + 0 + 65535 + 1 + 10 + 10 + + 5 + 6 + 2 + 3 + 0 + 0 + True + False + False + False + True + False + + + + + GtkEntry + network_http_url + False + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:57:26 GMT + + True + True + 0 + + + 2 + 6 + 3 + 4 + 0 + 0 + True + False + False + False + True + False + + + + + GtkSpinButton + network_udp_port + 1 + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:56:55 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 1234 + 0 + 65535 + 1 + 10 + 10 + + 2 + 3 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + + GtkLabel + Notebook:tab + open_net + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkTable + table3 + 5 + 4 + 2 + False + 5 + 5 + + + GtkLabel + label24 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label25 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label26 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False + + + + + GtkSpinButton + sat_freq + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:00 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 11954 + 10000 + 12999 + 1 + 10 + 10 + + 1 + 2 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + label27 + + GTK_JUSTIFY_CENTER + False + 0 + 0.5 + 0 + 0 + + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + + GtkHBox + hbox23 + False + 0 + + 1 + 2 + 2 + 3 + 0 + 0 + False + False + False + False + True + True + + + + GtkRadioButton + sat_pol_vert + True + + toggled + GtkSatOpenToggle + Tue, 09 Jul 2002 15:16:25 GMT + + + False + True + pol + + 0 + False + False + + + + + GtkRadioButton + sat_pol_hor + True + + toggled + GtkSatOpenToggle + Tue, 09 Jul 2002 15:16:36 GMT + + + False + True + pol + + 0 + False + False + + + + + + GtkSpinButton + sat_srate + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:09 GMT + + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 27500 + 1000 + 30000 + 1 + 10 + 10 + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkCombo + sat_fec + False + True + False + True + False + 1/2 +2/3 +3/4 +4/5 +5/6 +7/8 + + + 1 + 2 + 3 + 4 + 0 + 0 + False + False + False + False + True + False + + + + GtkEntry + GtkCombo:entry + combo-entry1 + True + + changed + GtkOpenChanged + Tue, 09 Jul 2002 13:58:26 GMT + + True + True + 0 + 3/4 + + + + + + GtkLabel + Notebook:tab + open_sat + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + + GtkFileSelection + intf_file + 10 + Select File + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + True + False + True + False + True + + + GtkButton + FileSel:ok_button + file_ok + True + True + + clicked + GtkFileOk + Wed, 10 Jul 2002 11:32:18 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + FileSel:cancel_button + file_cancel + True + True + + clicked + GtkFileCancel + Wed, 10 Jul 2002 11:32:23 GMT + + + GTK_RELIEF_NORMAL + + + + + GtkDialog + intf_jump + Jump + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + True + False + + + GtkVBox + Dialog:vbox + dialog-vbox3 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area2 + 10 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + jump_ok_button + True + + clicked + GtkJumpOk + Sun, 13 May 2001 14:53:19 GMT + + + GTK_RELIEF_NORMAL + + 0 + True + True + + + + + GtkButton + jump_cancel_button + True + + clicked + GtkJumpCancel + Sun, 13 May 2001 14:53:43 GMT + + + GTK_RELIEF_NORMAL + + 0 + True + True + + + + + + GtkFrame + jump_frame + 5 + + 0.05 + GTK_SHADOW_ETCHED_IN + + 0 + True + True + + + + GtkHBox + hbox13 + False + 0 + + + GtkLabel + jump_second_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_second_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 60 + 1 + 10 + 10 + + 0 + False + True + GTK_PACK_END + + + + + GtkLabel + jump_minute_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_minute_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 60 + 1 + 10 + 10 + + 0 + False + True + GTK_PACK_END + + + + + GtkLabel + jump_hour_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 5 + False + False + GTK_PACK_END + + + + + GtkSpinButton + jump_hour_spinbutton + True + 1 + 0 + False + GTK_UPDATE_ALWAYS + False + False + 0 + 0 + 12 + 1 + 10 + 10 + + 0 + False + True + GTK_PACK_END + + + + + + + + + GtkDialog + intf_playlist + + destroy + gtk_widget_hide + Tue, 15 May 2001 14:20:39 GMT + + + delete_event + gtk_widget_hide + Tue, 15 May 2001 14:20:22 GMT + + Playlist + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 400 + 300 + True + True + False + + + GtkVBox + Dialog:vbox + dialog-vbox4 + False + 5 + + + GtkHBox + Dialog:action_area + dialog-action_area3 + 10 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + playlist_ok_button + True + + clicked + GtkPlaylistOk + Sat, 12 May 2001 21:16:09 GMT + + + GTK_RELIEF_NORMAL + + 0 + True + True + + + + + GtkButton + playlist_cancel_button + True + + clicked + GtkPlaylistCancel + Sat, 12 May 2001 21:16:20 GMT + + + GTK_RELIEF_NORMAL + + 0 + True + True + + + + + + GtkMenuBar + playlist_menubar + GTK_SHADOW_OUT + + 0 + False + False + + + + GtkMenuItem + playlist_add + + False + + + GtkMenu + playlist_add_menu + + + GtkMenuItem + playlist_add_disc + + activate + GtkDiscOpenShow + Mon, 14 May 2001 21:59:32 GMT + + + False + + + + GtkMenuItem + playlist_add_file + + activate + GtkFileOpenShow + Mon, 14 May 2001 21:59:48 GMT + + + False + + + + GtkMenuItem + playlist_add_network + + activate + GtkNetworkOpenShow + Mon, 14 May 2001 22:00:03 GMT + + + False + + + + GtkMenuItem + playlist_add_url + + activate + GtkPlaylistAddUrl + Mon, 14 May 2001 22:00:22 GMT + + + False + + + + + + GtkMenuItem + playlist_delete + + False + + + GtkMenu + playlist_delete_menu + + + GtkMenuItem + playlist_delete_all + + activate + GtkPlaylistDeleteAll + Sat, 12 May 2001 21:13:11 GMT + + + False + + + + GtkMenuItem + playlist_delete_selected + + activate + GtkPlaylistDeleteSelected + Sat, 12 May 2001 21:12:58 GMT + + + False + + + + + + GtkMenuItem + playlist_selection + + False + + + GtkMenu + playlist_selection_menu + + + GtkMenuItem + playlist_selection_crop + + activate + GtkPlaylistCrop + Sat, 12 May 2001 21:13:47 GMT + + + False + + + + GtkMenuItem + playlist_selection_invert + + activate + GtkPlaylistInvert + Sat, 12 May 2001 21:13:55 GMT + + + False + + + + GtkMenuItem + playlist_selection_select + + activate + GtkPlaylistSelect + Sat, 12 May 2001 21:14:04 GMT + + + False + + + + + + + GtkScrolledWindow + scrolledwindow1 + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkCList + playlist_clist + 5 + True + + event + GtkPlaylistEvent + Sat, 12 May 2001 21:25:20 GMT + + + drag_data_received + GtkPlaylistDragData + Sat, 12 May 2001 21:25:53 GMT + + + drag_motion + GtkPlaylistDragMotion + Sat, 12 May 2001 21:26:23 GMT + + 2 + 257,80 + GTK_SELECTION_EXTENDED + True + GTK_SHADOW_OUT + + + GtkLabel + CList:title + label22 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + label23 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + + GtkDialog + intf_messages + + delete_event + GtkMessagesDelete + Tue, 19 Feb 2002 02:39:16 GMT + + Messages + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 600 + 400 + True + True + False + + + GtkVBox + Dialog:vbox + dialog-vbox6 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area5 + 5 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkButton + messages_ok + True + True + True + + clicked + GtkMessagesOk + Tue, 19 Feb 2002 02:07:37 GMT + + + GTK_RELIEF_NORMAL + + 0 + False + True + + + + + + GtkScrolledWindow + scrolledwindow2 + 5 + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkText + messages_textbox + True + False + + + + + + + diff --git a/modules/gui/gtk/gtk_callbacks.c b/modules/gui/gtk/gtk_callbacks.c new file mode 100644 index 0000000000..46ca900d9e --- /dev/null +++ b/modules/gui/gtk/gtk_callbacks.c @@ -0,0 +1,581 @@ +/***************************************************************************** + * gtk_callbacks.c : Callbacks for the Gtk+ plugin. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: gtk_callbacks.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * Julien BLACHE + * + * 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 /* off_t */ +#include + +#include +#include +#include + +#include + +#include + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "common.h" + +#include "netutils.h" + +/***************************************************************************** + * Useful function to retrieve p_intf + ****************************************************************************/ +void * __GtkGetIntf( GtkWidget * widget ) +{ + void *p_data; + + if( GTK_IS_MENU_ITEM( widget ) ) + { + /* Look for a GTK_MENU */ + while( widget->parent && !GTK_IS_MENU( widget ) ) + { + widget = widget->parent; + } + + /* Maybe this one has the data */ + p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" ); + if( p_data ) + { + return p_data; + } + + /* Otherwise, the parent widget has it */ + widget = gtk_menu_get_attach_widget( GTK_MENU( widget ) ); + } + + /* We look for the top widget */ + widget = gtk_widget_get_toplevel( GTK_WIDGET( widget ) ); + + p_data = gtk_object_get_data( GTK_OBJECT( widget ), "p_intf" ); + + return p_data; +} + +/***************************************************************************** + * Callbacks + *****************************************************************************/ + +/* + * Main interface callbacks + */ + +gboolean GtkExit( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + vlc_mutex_lock( &p_intf->change_lock ); + p_intf->p_vlc->b_die = VLC_TRUE; + vlc_mutex_unlock( &p_intf->change_lock ); + + return TRUE; +} + +void GtkClose( GtkMenuItem *menuitem, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( menuitem ); + p_intf->b_die = VLC_TRUE; +} + +gboolean GtkWindowDelete( GtkWidget *widget, + GdkEvent *event, + gpointer user_data ) +{ + GtkExit( GTK_WIDGET( widget ), user_data ); + + return TRUE; +} + + +gboolean GtkWindowToggle( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + if( GTK_WIDGET_VISIBLE(p_intf->p_sys->p_window) ) + { + gtk_widget_hide( p_intf->p_sys->p_window); + } + else + { + gtk_widget_show( p_intf->p_sys->p_window ); + } + + return TRUE; +} + +gboolean GtkFullscreen( GtkWidget *widget, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + vout_thread_t *p_vout; + + p_vout = vlc_object_find( p_intf->p_sys->p_input, + VLC_OBJECT_VOUT, FIND_CHILD ); + if( p_vout == NULL ) + { + return FALSE; + } + + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_object_release( p_vout ); + return TRUE; +} + +void GtkWindowDrag( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + GtkDropDataReceived( p_intf, data, info, PLAYLIST_END ); +} + + +/**************************************************************************** + * Slider management + ****************************************************************************/ + +gboolean GtkSliderRelease( GtkWidget *widget, + GdkEventButton *event, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + vlc_mutex_lock( &p_intf->change_lock ); + p_intf->p_sys->b_slider_free = 1; + vlc_mutex_unlock( &p_intf->change_lock ); + + return FALSE; +} + + +gboolean GtkSliderPress( GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + vlc_mutex_lock( &p_intf->change_lock ); + p_intf->p_sys->b_slider_free = 0; + vlc_mutex_unlock( &p_intf->change_lock ); + + return FALSE; +} + + +/**************************************************************************** + * DVD specific items + ****************************************************************************/ + +void GtkTitlePrev( GtkButton * button, gpointer user_data ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + int i_id; + + p_intf = GtkGetIntf( button ); + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1; + + if( i_id >= 0 ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_title_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + + +void GtkTitleNext( GtkButton * button, gpointer user_data ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + int i_id; + + p_intf = GtkGetIntf( button ); + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1; + + if( i_id < p_intf->p_sys->p_input->stream.i_area_nb ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_title_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + + +void GtkChapterPrev( GtkButton * button, gpointer user_data ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + + p_intf = GtkGetIntf( button ); + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if( p_area->i_part > 0 ) + { + p_area->i_part--; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_chapter_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + + +void GtkChapterNext( GtkButton * button, gpointer user_data ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + + p_intf = GtkGetIntf( button ); + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if( p_area->i_part < p_area->i_part_nb ) + { + p_area->i_part++; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_chapter_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +/**************************************************************************** + * Network specific items + ****************************************************************************/ +void GtkNetworkJoin( GtkEditable * editable, gpointer user_data ) +{ + int i_channel; + + i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( editable ) ); +// msg_Dbg( "intf info: joining channel %d", i_channel ); + +// network_ChannelJoin( i_channel ); +} + +void GtkChannelGo( GtkButton * button, gpointer user_data ) +{ + GtkWidget * window; + GtkWidget * spin; + int i_channel; + + intf_thread_t *p_intf = GtkGetIntf( button ); + + window = gtk_widget_get_toplevel( GTK_WIDGET (button) ); + spin = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( window ), + "network_channel_spinbutton" ) ); + + i_channel = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin ) ); + msg_Dbg( p_intf, "joining channel %d", i_channel ); + + vlc_mutex_lock( &p_intf->change_lock ); + network_ChannelJoin( p_intf, i_channel ); + vlc_mutex_unlock( &p_intf->change_lock ); + +// input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); +} + + +/**************************************************************************** + * About box + ****************************************************************************/ + +gboolean GtkAboutShow( GtkWidget *widget, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + if( !GTK_IS_WIDGET( p_intf->p_sys->p_about ) ) + { + p_intf->p_sys->p_about = create_intf_about(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_about ), + "p_intf", p_intf ); + } + gtk_widget_show( p_intf->p_sys->p_about ); + gdk_window_raise( p_intf->p_sys->p_about->window ); + + return TRUE; +} + +void GtkAboutOk( GtkButton * button, gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + + gtk_widget_hide( p_intf->p_sys->p_about ); +} + + +/**************************************************************************** + * Jump box + ****************************************************************************/ + +gboolean GtkJumpShow( GtkWidget *widget, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + if( !GTK_IS_WIDGET( p_intf->p_sys->p_jump ) ) + { + p_intf->p_sys->p_jump = create_intf_jump(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_jump ), + "p_intf", p_intf ); + } + + gtk_widget_show( p_intf->p_sys->p_jump ); + gdk_window_raise( p_intf->p_sys->p_jump->window ); + + return FALSE; +} + + +void GtkJumpOk( GtkButton *button, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + int i_hours, i_minutes, i_seconds; + + if( p_intf->p_sys->p_input == NULL ) + { + return; + } + +#define GET_VALUE( name ) \ + gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->p_jump ), name ) ) ) + i_hours = GET_VALUE( "jump_hour_spinbutton" ); + i_minutes = GET_VALUE( "jump_minute_spinbutton" ); + i_seconds = GET_VALUE( "jump_second_spinbutton" ); +#undef GET_VALUE + + input_Seek( p_intf->p_sys->p_input, + i_seconds + 60 * i_minutes + 3600 * i_hours, + INPUT_SEEK_SECONDS | INPUT_SEEK_SET ); + + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + + +void GtkJumpCancel( GtkButton *button, + gpointer user_data) +{ + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + +/**************************************************************************** + * Callbacks for disc ejection + ****************************************************************************/ +gboolean GtkDiscEject ( GtkWidget *widget, gpointer user_data ) +{ + char *psz_device = NULL; + char *psz_parser; + char *psz_current; + + intf_thread_t *p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + + if( p_playlist->i_index < 0 ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + return FALSE; + } + + psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name; + + /* + * Get the active input + * Determine whether we can eject a media, ie it's a VCD or DVD + * If it's neither a VCD nor a DVD, then return + */ + + /* + * Don't really know if I must lock the stuff here, we're using it read-only + */ + + if( psz_current != NULL ) + { + if( !strncmp(psz_current, "dvd:", 4) ) + { + switch( psz_current[4] ) + { + case '\0': + case '@': + psz_device = config_GetPsz( p_intf, "dvd" ); + break; + default: + /* Omit the first 4 characters */ + psz_device = strdup( psz_current + 4 ); + break; + } + } + else if( !strncmp(psz_current, "vcd:", 4) ) + { + switch( psz_current[4] ) + { + case '\0': + case '@': + psz_device = config_GetPsz( p_intf, "vcd" ); + break; + default: + /* Omit the first 4 characters */ + psz_device = strdup( psz_current + 4 ); + break; + } + } + else + { + psz_device = strdup( psz_current ); + } + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + + if( psz_device == NULL ) + { + return TRUE; + } + + /* Remove what we have after @ */ + psz_parser = psz_device; + for( psz_parser = psz_device ; *psz_parser ; psz_parser++ ) + { + if( *psz_parser == '@' ) + { + *psz_parser = '\0'; + break; + } + } + + /* If there's a stream playing, we aren't allowed to eject ! */ + if( p_intf->p_sys->p_input == NULL ) + { + msg_Dbg( p_intf, "ejecting %s", psz_device ); + + intf_Eject( p_intf, psz_device ); + } + + free(psz_device); + + return TRUE; +} + +/**************************************************************************** + * Messages window + ****************************************************************************/ + +gboolean GtkMessagesShow( GtkWidget *widget, + gpointer user_data) +{ + static GdkColor black = { 0, 0x0000, 0x0000, 0x0000 }; + static GdkColormap *colormap; + intf_thread_t *p_intf = GtkGetIntf( widget ); + + gtk_widget_show( p_intf->p_sys->p_messages ); + colormap = gdk_colormap_get_system (); + gdk_color_alloc( colormap, &black ); + gdk_window_set_background( p_intf->p_sys->p_messages_text->text_area, + &black ); + + gdk_window_raise( p_intf->p_sys->p_messages->window ); + + gtk_text_set_point( p_intf->p_sys->p_messages_text, + gtk_text_get_length( p_intf->p_sys->p_messages_text ) ); + + return TRUE; +} + + +void +GtkMessagesOk (GtkButton *button, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + gtk_widget_hide( p_intf->p_sys->p_messages ); +} + + +gboolean +GtkMessagesDelete (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + gtk_widget_hide( p_intf->p_sys->p_messages ); + return TRUE; +} + + +void +GtkOpenNotebookChanged (GtkNotebook *notebook, + GtkNotebookPage *page, + gint page_num, + gpointer user_data) +{ + GtkOpenChanged( GTK_WIDGET( notebook ), user_data ); +} + diff --git a/modules/gui/gtk/gtk_callbacks.h b/modules/gui/gtk/gtk_callbacks.h new file mode 100644 index 0000000000..605c0efc97 --- /dev/null +++ b/modules/gui/gtk/gtk_callbacks.h @@ -0,0 +1,151 @@ +/***************************************************************************** + * gtk_callbacks.h : Callbacks for the gtk plugin. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: gtk_callbacks.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 + +#include "config.h" + +#include "control.h" +#include "menu.h" +#include "open.h" +#include "modules.h" +#include "playlist.h" +#include "preferences.h" + +/* General glade callbacks */ + +/***************************************************************************** + * main window callbacks: specific prototypes are in headers listed before + *****************************************************************************/ + +gboolean GtkExit ( GtkWidget *, gpointer ); +gboolean GtkWindowToggle ( GtkWidget *, gpointer ); +gboolean GtkFullscreen ( GtkWidget *, gpointer ); +gboolean GtkSliderRelease ( GtkWidget *, GdkEventButton *, gpointer ); +gboolean GtkSliderPress ( GtkWidget *, GdkEventButton *, gpointer ); +gboolean GtkWindowDelete ( GtkWidget * widget, GdkEvent *, gpointer ); +gboolean GtkJumpShow ( GtkWidget *, gpointer ); +gboolean GtkAboutShow ( GtkWidget *, gpointer ); +gboolean GtkMessagesShow ( GtkWidget *, gpointer ); +void GtkTitlePrev ( GtkButton * button, gpointer ); +void GtkTitleNext ( GtkButton * button, gpointer ); +void GtkChapterPrev ( GtkButton *, gpointer ); +void GtkChapterNext ( GtkButton * button, gpointer ); +void GtkAboutOk ( GtkButton *, gpointer ); +void GtkWindowDrag ( GtkWidget *, GdkDragContext *, + gint, gint, GtkSelectionData *, + guint , guint, gpointer ); +void GtkJumpOk ( GtkButton * button, gpointer ); +void GtkJumpCancel ( GtkButton * button, gpointer user_data ); + +void GtkNetworkJoin ( GtkEditable *, gpointer ); +void GtkChannelGo ( GtkButton *, gpointer ); + +void GtkNetworkOpenChannel ( GtkToggleButton *, gpointer ); + +gboolean +GtkDiscEject (GtkWidget *widget, + gpointer user_data); + +void +GtkMessagesOk (GtkButton *button, + gpointer user_data); + +gboolean +GtkMessagesDelete (GtkWidget *widget, + GdkEvent *event, + gpointer user_data); + +gboolean +GtkSatOpenShow (GtkWidget *widget, + gpointer user_data); + +void +GtkSatOpenOk (GtkButton *button, + gpointer user_data); + +void +GtkSatOpenCancel (GtkButton *button, + gpointer user_data); + +void +GtkNetworkOpenUDP (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkNetworkOpenMulticast (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkNetworkOpenCS (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkNetworkOpenHTTP (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkNetworkOpenChannel (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkOpenOk (GtkButton *button, + gpointer user_data); + +void +GtkOpenCancel (GtkButton *button, + gpointer user_data); + +void +GtkOpenChanged (GtkWidget *button, + gpointer user_data); + +void +GtkOpenNotebookChanged (GtkNotebook *notebook, + GtkNotebookPage *page, + gint page_num, + gpointer user_data); + +void +GtkSatOpenToggle (GtkToggleButton *togglebutton, + gpointer user_data); + +void +GtkFileShow (GtkButton *button, + gpointer user_data); + +void +GtkFileOk (GtkButton *button, + gpointer user_data); + +void +GtkFileCancel (GtkButton *button, + gpointer user_data); + +void +GtkClose (GtkMenuItem *menuitem, + gpointer user_data); diff --git a/modules/gui/gtk/gtk_interface.c b/modules/gui/gtk/gtk_interface.c new file mode 100644 index 0000000000..09c162fe7d --- /dev/null +++ b/modules/gui/gtk/gtk_interface.c @@ -0,0 +1,2658 @@ +/* This file was created automatically by glade and fixed by bootstrap.sh */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +GtkWidget* +create_intf_window (void) +{ + GtkWidget *intf_window; + GtkWidget *window_vbox; + GtkWidget *menubar_handlebox; + GtkWidget *menubar; + guint tmp_key; + GtkWidget *menubar_file; + GtkWidget *menubar_file_menu; + GtkAccelGroup *menubar_file_menu_accels; + GtkWidget *menubar_open; + GtkWidget *menubar_disc; + GtkWidget *menubar_network; + GtkWidget *separator4; + GtkWidget *menubar_eject; + GtkWidget *separator14; + GtkWidget *menubar_close; + GtkWidget *menubar_exit; + GtkWidget *menubar_view; + GtkWidget *menubar_view_menu; + GtkAccelGroup *menubar_view_menu_accels; + GtkWidget *menubar_interface_hide; + GtkWidget *menubar_fullscreen; + GtkWidget *separator13; + GtkWidget *menubar_program; + GtkWidget *menubar_title; + GtkWidget *menubar_chapter; + GtkWidget *separator11; + GtkWidget *menubar_playlist; + GtkWidget *menubar_modules; + GtkWidget *menubar_messages; + GtkWidget *menubar_settings; + GtkWidget *menubar_settings_menu; + GtkAccelGroup *menubar_settings_menu_accels; + GtkWidget *menubar_audio; + GtkWidget *menubar_subpictures; + GtkWidget *separator8; + GtkWidget *menubar_preferences; + GtkWidget *menubar_help; + GtkWidget *menubar_help_menu; + GtkAccelGroup *menubar_help_menu_accels; + GtkWidget *menubar_about; + GtkWidget *toolbar_handlebox; + GtkWidget *toolbar; + GtkWidget *toolbar_open; + GtkWidget *toolbar_disc; + GtkWidget *toolbar_network; + GtkWidget *toolbar_sat; + GtkWidget *toolbar_back; + GtkWidget *toolbar_stop; + GtkWidget *toolbar_eject; + GtkWidget *toolbar_play; + GtkWidget *toolbar_pause; + GtkWidget *toolbar_slow; + GtkWidget *toolbar_fast; + GtkWidget *toolbar_playlist; + GtkWidget *toolbar_prev; + GtkWidget *toolbar_next; + GtkWidget *slider_frame; + GtkWidget *slider; + GtkWidget *file_box; + GtkWidget *label_status; + GtkWidget *dvd_box; + GtkWidget *dvd_label; + GtkWidget *title_box; + GtkWidget *title; + GtkWidget *title_label; + GtkWidget *title_prev_button; + GtkWidget *title_next_button; + GtkWidget *dvd_separator; + GtkWidget *chapter_box; + GtkWidget *chapter; + GtkWidget *chapter_label; + GtkWidget *chapter_prev_button; + GtkWidget *chapter_next_button; + GtkWidget *network_box; + GtkWidget *network_address_label; + GtkWidget *network_channel_box; + GtkWidget *channel_label; + GtkObject *network_channel_spinbutton_adj; + GtkWidget *network_channel_spinbutton; + GtkWidget *network_channel_go_button; + GtkWidget *intf_statusbar; + GtkAccelGroup *accel_group; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + accel_group = gtk_accel_group_new (); + + intf_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_object_set_data (GTK_OBJECT (intf_window), "intf_window", intf_window); + gtk_window_set_title (GTK_WINDOW (intf_window), _("VideoLAN Client")); + gtk_window_set_policy (GTK_WINDOW (intf_window), TRUE, TRUE, TRUE); + + window_vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (window_vbox); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "window_vbox", window_vbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (window_vbox); + gtk_container_add (GTK_CONTAINER (intf_window), window_vbox); + + menubar_handlebox = gtk_handle_box_new (); + gtk_widget_ref (menubar_handlebox); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_handlebox", menubar_handlebox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_handlebox); + gtk_box_pack_start (GTK_BOX (window_vbox), menubar_handlebox, FALSE, TRUE, 0); + + menubar = gtk_menu_bar_new (); + gtk_widget_ref (menubar); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar", menubar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar); + gtk_container_add (GTK_CONTAINER (menubar_handlebox), menubar); + + menubar_file = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_file)->child), + _("_File")); + gtk_widget_add_accelerator (menubar_file, "activate_item", accel_group, + tmp_key, GDK_MOD1_MASK, (GtkAccelFlags) 0); + gtk_widget_ref (menubar_file); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_file", menubar_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_file); + gtk_container_add (GTK_CONTAINER (menubar), menubar_file); + + menubar_file_menu = gtk_menu_new (); + gtk_widget_ref (menubar_file_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_file_menu", menubar_file_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menubar_file), menubar_file_menu); + menubar_file_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (menubar_file_menu)); + + menubar_open = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_open)->child), + _("_Open File...")); + gtk_widget_add_accelerator (menubar_open, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_open); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_open", menubar_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_open); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_open); + gtk_tooltips_set_tip (tooltips, menubar_open, _("Open a File"), NULL); + gtk_widget_add_accelerator (menubar_open, "activate", accel_group, + GDK_F3, 0, + GTK_ACCEL_VISIBLE); + + menubar_disc = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_disc)->child), + _("Open _Disc...")); + gtk_widget_add_accelerator (menubar_disc, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_disc", menubar_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_disc); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_disc); + gtk_tooltips_set_tip (tooltips, menubar_disc, _("Open a DVD or VCD"), NULL); + gtk_widget_add_accelerator (menubar_disc, "activate", accel_group, + GDK_F4, 0, + GTK_ACCEL_VISIBLE); + + menubar_network = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_network)->child), + _("_Network Stream...")); + gtk_widget_add_accelerator (menubar_network, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_network); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_network", menubar_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_network); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_network); + gtk_tooltips_set_tip (tooltips, menubar_network, _("Select a Network Stream"), NULL); + gtk_widget_add_accelerator (menubar_network, "activate", accel_group, + GDK_F5, 0, + GTK_ACCEL_VISIBLE); + + separator4 = gtk_menu_item_new (); + gtk_widget_ref (separator4); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator4", separator4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator4); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), separator4); + gtk_widget_set_sensitive (separator4, FALSE); + + menubar_eject = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_eject)->child), + _("_Eject Disc")); + gtk_widget_add_accelerator (menubar_eject, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_eject); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_eject", menubar_eject, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_eject); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_eject); + gtk_tooltips_set_tip (tooltips, menubar_eject, _("Eject disc"), NULL); + + separator14 = gtk_menu_item_new (); + gtk_widget_ref (separator14); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator14", separator14, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator14); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), separator14); + gtk_widget_set_sensitive (separator14, FALSE); + + menubar_close = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_close)->child), + _("_Close")); + gtk_widget_add_accelerator (menubar_close, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_close); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_close", menubar_close, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_close); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_close); + gtk_tooltips_set_tip (tooltips, menubar_close, _("Close the window"), NULL); + gtk_widget_add_accelerator (menubar_close, "activate", accel_group, + GDK_W, GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE); + + menubar_exit = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_exit)->child), + _("E_xit")); + gtk_widget_add_accelerator (menubar_exit, "activate_item", menubar_file_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_exit); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_exit", menubar_exit, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_exit); + gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_exit); + gtk_tooltips_set_tip (tooltips, menubar_exit, _("Exit the program"), NULL); + gtk_widget_add_accelerator (menubar_exit, "activate", accel_group, + GDK_Q, GDK_CONTROL_MASK, + GTK_ACCEL_VISIBLE); + + menubar_view = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_view)->child), + _("_View")); + gtk_widget_add_accelerator (menubar_view, "activate_item", accel_group, + tmp_key, GDK_MOD1_MASK, (GtkAccelFlags) 0); + gtk_widget_ref (menubar_view); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_view", menubar_view, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_view); + gtk_container_add (GTK_CONTAINER (menubar), menubar_view); + + menubar_view_menu = gtk_menu_new (); + gtk_widget_ref (menubar_view_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_view_menu", menubar_view_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menubar_view), menubar_view_menu); + menubar_view_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (menubar_view_menu)); + + menubar_interface_hide = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_interface_hide)->child), + _("_Hide interface")); + gtk_widget_add_accelerator (menubar_interface_hide, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_interface_hide); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_interface_hide", menubar_interface_hide, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_interface_hide); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_interface_hide); + gtk_tooltips_set_tip (tooltips, menubar_interface_hide, _("Hide the main interface window"), NULL); + + menubar_fullscreen = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_fullscreen)->child), + _("_Fullscreen")); + gtk_widget_add_accelerator (menubar_fullscreen, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_fullscreen); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_fullscreen", menubar_fullscreen, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_fullscreen); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_fullscreen); + + separator13 = gtk_menu_item_new (); + gtk_widget_ref (separator13); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator13", separator13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator13); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), separator13); + gtk_widget_set_sensitive (separator13, FALSE); + + menubar_program = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_program)->child), + _("Progr_am")); + gtk_widget_add_accelerator (menubar_program, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_program); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_program", menubar_program, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_program); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_program); + gtk_widget_set_sensitive (menubar_program, FALSE); + gtk_tooltips_set_tip (tooltips, menubar_program, _("Choose the program"), NULL); + + menubar_title = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_title)->child), + _("_Title")); + gtk_widget_add_accelerator (menubar_title, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_title); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_title", menubar_title, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_title); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_title); + gtk_widget_set_sensitive (menubar_title, FALSE); + gtk_tooltips_set_tip (tooltips, menubar_title, _("Navigate through the stream"), NULL); + + menubar_chapter = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_chapter)->child), + _("_Chapter")); + gtk_widget_add_accelerator (menubar_chapter, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_chapter); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_chapter", menubar_chapter, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_chapter); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_chapter); + gtk_widget_set_sensitive (menubar_chapter, FALSE); + + separator11 = gtk_menu_item_new (); + gtk_widget_ref (separator11); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator11", separator11, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator11); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), separator11); + gtk_widget_set_sensitive (separator11, FALSE); + + menubar_playlist = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_playlist)->child), + _("_Playlist...")); + gtk_widget_add_accelerator (menubar_playlist, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_playlist); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_playlist", menubar_playlist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_playlist); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_playlist); + gtk_tooltips_set_tip (tooltips, menubar_playlist, _("Open the playlist window"), NULL); + + menubar_modules = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_modules)->child), + _("_Modules...")); + gtk_widget_add_accelerator (menubar_modules, "activate_item", menubar_view_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_modules); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_modules", menubar_modules, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_modules); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_modules); + gtk_widget_set_sensitive (menubar_modules, FALSE); + gtk_tooltips_set_tip (tooltips, menubar_modules, _("Open the module manager"), NULL); + + menubar_messages = gtk_menu_item_new_with_label (_("Messages...")); + gtk_widget_ref (menubar_messages); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_messages", menubar_messages, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_messages); + gtk_container_add (GTK_CONTAINER (menubar_view_menu), menubar_messages); + gtk_tooltips_set_tip (tooltips, menubar_messages, _("Open the messages window"), NULL); + + menubar_settings = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_settings)->child), + _("_Settings")); + gtk_widget_add_accelerator (menubar_settings, "activate_item", accel_group, + tmp_key, GDK_MOD1_MASK, (GtkAccelFlags) 0); + gtk_widget_ref (menubar_settings); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_settings", menubar_settings, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_settings); + gtk_container_add (GTK_CONTAINER (menubar), menubar_settings); + + menubar_settings_menu = gtk_menu_new (); + gtk_widget_ref (menubar_settings_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_settings_menu", menubar_settings_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menubar_settings), menubar_settings_menu); + menubar_settings_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (menubar_settings_menu)); + + menubar_audio = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_audio)->child), + _("A_udio")); + gtk_widget_add_accelerator (menubar_audio, "activate_item", menubar_settings_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_audio); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_audio", menubar_audio, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_audio); + gtk_container_add (GTK_CONTAINER (menubar_settings_menu), menubar_audio); + gtk_widget_set_sensitive (menubar_audio, FALSE); + gtk_tooltips_set_tip (tooltips, menubar_audio, _("Select audio channel"), NULL); + + menubar_subpictures = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_subpictures)->child), + _("_Subtitles")); + gtk_widget_add_accelerator (menubar_subpictures, "activate_item", menubar_settings_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_subpictures); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_subpictures", menubar_subpictures, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_subpictures); + gtk_container_add (GTK_CONTAINER (menubar_settings_menu), menubar_subpictures); + gtk_widget_set_sensitive (menubar_subpictures, FALSE); + gtk_tooltips_set_tip (tooltips, menubar_subpictures, _("Select subtitles channel"), NULL); + + separator8 = gtk_menu_item_new (); + gtk_widget_ref (separator8); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator8", separator8, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator8); + gtk_container_add (GTK_CONTAINER (menubar_settings_menu), separator8); + gtk_widget_set_sensitive (separator8, FALSE); + + menubar_preferences = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_preferences)->child), + _("_Preferences...")); + gtk_widget_add_accelerator (menubar_preferences, "activate_item", menubar_settings_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_preferences); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_preferences", menubar_preferences, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_preferences); + gtk_container_add (GTK_CONTAINER (menubar_settings_menu), menubar_preferences); + gtk_tooltips_set_tip (tooltips, menubar_preferences, _("Configure the application"), NULL); + + menubar_help = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_help)->child), + _("_Help")); + gtk_widget_add_accelerator (menubar_help, "activate_item", accel_group, + tmp_key, GDK_MOD1_MASK, (GtkAccelFlags) 0); + gtk_widget_ref (menubar_help); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_help", menubar_help, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_help); + gtk_container_add (GTK_CONTAINER (menubar), menubar_help); + + menubar_help_menu = gtk_menu_new (); + gtk_widget_ref (menubar_help_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_help_menu", menubar_help_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menubar_help), menubar_help_menu); + menubar_help_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (menubar_help_menu)); + + menubar_about = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_about)->child), + _("_About...")); + gtk_widget_add_accelerator (menubar_about, "activate_item", menubar_help_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (menubar_about); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_about", menubar_about, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (menubar_about); + gtk_container_add (GTK_CONTAINER (menubar_help_menu), menubar_about); + gtk_tooltips_set_tip (tooltips, menubar_about, _("About this application"), NULL); + + toolbar_handlebox = gtk_handle_box_new (); + gtk_widget_ref (toolbar_handlebox); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_handlebox", toolbar_handlebox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_handlebox); + gtk_box_pack_start (GTK_BOX (window_vbox), toolbar_handlebox, FALSE, TRUE, 0); + + toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH); + gtk_widget_ref (toolbar); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar", toolbar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar); + gtk_container_add (GTK_CONTAINER (toolbar_handlebox), toolbar); + gtk_container_set_border_width (GTK_CONTAINER (toolbar), 1); + gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 16); + gtk_toolbar_set_space_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_SPACE_LINE); + gtk_toolbar_set_button_relief (GTK_TOOLBAR (toolbar), GTK_RELIEF_NONE); + + toolbar_open = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("File"), + _("Open a File"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_open); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_open", toolbar_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_open); + + toolbar_disc = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Disc"), + _("Open a DVD or VCD"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_disc", toolbar_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_disc); + + toolbar_network = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Net"), + _("Select a Network Stream"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_network); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_network", toolbar_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_network); + + toolbar_sat = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Sat"), + _("Open a Satellite Card"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_sat); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_sat", toolbar_sat, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_sat); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + toolbar_back = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Back"), + _("Go Backward"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_back); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_back", toolbar_back, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_back); + gtk_widget_set_sensitive (toolbar_back, FALSE); + + toolbar_stop = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Stop"), + _("Stop Stream"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_stop); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_stop", toolbar_stop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_stop); + + toolbar_eject = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Eject"), + NULL, NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_eject); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_eject", toolbar_eject, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_eject); + + toolbar_play = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Play"), + _("Play Stream"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_play); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_play", toolbar_play, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_play); + + toolbar_pause = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Pause"), + _("Pause Stream"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_pause); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_pause", toolbar_pause, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_pause); + gtk_widget_set_sensitive (toolbar_pause, FALSE); + + gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); + + toolbar_slow = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Slow"), + _("Play Slower"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_slow); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_slow", toolbar_slow, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_slow); + gtk_widget_set_sensitive (toolbar_slow, FALSE); + + toolbar_fast = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Fast"), + _("Play Faster"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_fast); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_fast", toolbar_fast, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_fast); + gtk_widget_set_sensitive (toolbar_fast, FALSE); + + toolbar_playlist = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Playlist"), + _("Open Playlist"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_playlist); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_playlist", toolbar_playlist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_playlist); + + toolbar_prev = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Prev"), + _("Previous File"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_prev); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_prev", toolbar_prev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_prev); + + toolbar_next = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar), + GTK_TOOLBAR_CHILD_BUTTON, + NULL, + _("Next"), + _("Next File"), NULL, + NULL, NULL, NULL); + gtk_widget_ref (toolbar_next); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_next", toolbar_next, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (toolbar_next); + + slider_frame = gtk_frame_new ("-:--:--"); + gtk_widget_ref (slider_frame); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "slider_frame", slider_frame, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (window_vbox), slider_frame, TRUE, TRUE, 0); + gtk_frame_set_label_align (GTK_FRAME (slider_frame), 0.05, 0.5); + + slider = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 1, 6.25, 0))); + gtk_widget_ref (slider); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "slider", slider, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (slider); + gtk_container_add (GTK_CONTAINER (slider_frame), slider); + gtk_widget_set_usize (slider, 500, 15); + gtk_scale_set_draw_value (GTK_SCALE (slider), FALSE); + gtk_scale_set_digits (GTK_SCALE (slider), 3); + + file_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (file_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "file_box", file_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (file_box); + gtk_box_pack_start (GTK_BOX (window_vbox), file_box, TRUE, TRUE, 0); + gtk_widget_set_usize (file_box, 500, 24); + + label_status = gtk_label_new (""); + gtk_widget_ref (label_status); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "label_status", label_status, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label_status); + gtk_box_pack_start (GTK_BOX (file_box), label_status, TRUE, TRUE, 0); + + dvd_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (dvd_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dvd_box", dvd_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (window_vbox), dvd_box, TRUE, TRUE, 0); + gtk_widget_set_usize (dvd_box, 500, 24); + + dvd_label = gtk_label_new (_("Disc")); + gtk_widget_ref (dvd_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dvd_label", dvd_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (dvd_label); + gtk_box_pack_start (GTK_BOX (dvd_box), dvd_label, TRUE, FALSE, 0); + + title_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (title_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_box", title_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_box); + gtk_box_pack_start (GTK_BOX (dvd_box), title_box, TRUE, TRUE, 0); + + title = gtk_label_new (_("Title:")); + gtk_widget_ref (title); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title", title, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title); + gtk_box_pack_start (GTK_BOX (title_box), title, FALSE, FALSE, 5); + + title_label = gtk_label_new ("--"); + gtk_widget_ref (title_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_label", title_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_label); + gtk_box_pack_start (GTK_BOX (title_box), title_label, FALSE, FALSE, 5); + + title_prev_button = gtk_button_new_with_label (_("Prev")); + gtk_widget_ref (title_prev_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_prev_button", title_prev_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_prev_button); + gtk_box_pack_start (GTK_BOX (title_box), title_prev_button, FALSE, FALSE, 5); + gtk_button_set_relief (GTK_BUTTON (title_prev_button), GTK_RELIEF_NONE); + + title_next_button = gtk_button_new_with_label (_("Next")); + gtk_widget_ref (title_next_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "title_next_button", title_next_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (title_next_button); + gtk_box_pack_start (GTK_BOX (title_box), title_next_button, FALSE, FALSE, 5); + gtk_button_set_relief (GTK_BUTTON (title_next_button), GTK_RELIEF_NONE); + + dvd_separator = gtk_vseparator_new (); + gtk_widget_ref (dvd_separator); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "dvd_separator", dvd_separator, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (dvd_separator); + gtk_box_pack_start (GTK_BOX (dvd_box), dvd_separator, TRUE, TRUE, 0); + + chapter_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (chapter_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter_box", chapter_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter_box); + gtk_box_pack_start (GTK_BOX (dvd_box), chapter_box, TRUE, TRUE, 0); + + chapter = gtk_label_new (_("Chapter:")); + gtk_widget_ref (chapter); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter", chapter, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter); + gtk_box_pack_start (GTK_BOX (chapter_box), chapter, FALSE, FALSE, 5); + + chapter_label = gtk_label_new ("---"); + gtk_widget_ref (chapter_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter_label", chapter_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter_label); + gtk_box_pack_start (GTK_BOX (chapter_box), chapter_label, FALSE, FALSE, 5); + + chapter_prev_button = gtk_button_new_with_label (_("Prev")); + gtk_widget_ref (chapter_prev_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter_prev_button", chapter_prev_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter_prev_button); + gtk_box_pack_start (GTK_BOX (chapter_box), chapter_prev_button, FALSE, FALSE, 5); + gtk_button_set_relief (GTK_BUTTON (chapter_prev_button), GTK_RELIEF_NONE); + + chapter_next_button = gtk_button_new_with_label (_("Next")); + gtk_widget_ref (chapter_next_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "chapter_next_button", chapter_next_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (chapter_next_button); + gtk_box_pack_start (GTK_BOX (chapter_box), chapter_next_button, FALSE, FALSE, 5); + gtk_button_set_relief (GTK_BUTTON (chapter_next_button), GTK_RELIEF_NONE); + + network_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (network_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_box", network_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_box_pack_start (GTK_BOX (window_vbox), network_box, TRUE, TRUE, 0); + gtk_widget_set_usize (network_box, 500, 24); + + network_address_label = gtk_label_new (_("No server")); + gtk_widget_ref (network_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_address_label", network_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_address_label); + gtk_box_pack_start (GTK_BOX (network_box), network_address_label, TRUE, TRUE, 0); + + network_channel_box = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (network_channel_box); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_box", network_channel_box, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_box); + gtk_box_pack_start (GTK_BOX (network_box), network_channel_box, TRUE, FALSE, 0); + + channel_label = gtk_label_new (_("Channel:")); + gtk_widget_ref (channel_label); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "channel_label", channel_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (channel_label); + gtk_box_pack_start (GTK_BOX (network_channel_box), channel_label, FALSE, FALSE, 5); + + network_channel_spinbutton_adj = gtk_adjustment_new (0, 0, 100, 1, 10, 10); + network_channel_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (network_channel_spinbutton_adj), 1, 0); + gtk_widget_ref (network_channel_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_spinbutton", network_channel_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_spinbutton); + gtk_box_pack_start (GTK_BOX (network_channel_box), network_channel_spinbutton, FALSE, TRUE, 0); + + network_channel_go_button = gtk_button_new_with_label (_("Go!")); + gtk_widget_ref (network_channel_go_button); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "network_channel_go_button", network_channel_go_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_go_button); + gtk_box_pack_start (GTK_BOX (network_channel_box), network_channel_go_button, FALSE, FALSE, 0); + gtk_button_set_relief (GTK_BUTTON (network_channel_go_button), GTK_RELIEF_NONE); + + intf_statusbar = gtk_statusbar_new (); + gtk_widget_ref (intf_statusbar); + gtk_object_set_data_full (GTK_OBJECT (intf_window), "intf_statusbar", intf_statusbar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (intf_statusbar); + gtk_box_pack_start (GTK_BOX (window_vbox), intf_statusbar, FALSE, FALSE, 0); + + gtk_signal_connect (GTK_OBJECT (intf_window), "drag_data_received", + GTK_SIGNAL_FUNC (GtkWindowDrag), + NULL); + gtk_signal_connect (GTK_OBJECT (intf_window), "delete_event", + GTK_SIGNAL_FUNC (GtkWindowDelete), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_open), "activate", + GTK_SIGNAL_FUNC (GtkFileOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_disc), "activate", + GTK_SIGNAL_FUNC (GtkDiscOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_network), "activate", + GTK_SIGNAL_FUNC (GtkNetworkOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_eject), "activate", + GTK_SIGNAL_FUNC (GtkDiscEject), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_close), "activate", + GTK_SIGNAL_FUNC (GtkClose), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_exit), "activate", + GTK_SIGNAL_FUNC (GtkExit), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_interface_hide), "activate", + GTK_SIGNAL_FUNC (GtkWindowToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_fullscreen), "activate", + GTK_SIGNAL_FUNC (GtkFullscreen), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_playlist), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_modules), "activate", + GTK_SIGNAL_FUNC (GtkModulesShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_messages), "activate", + GTK_SIGNAL_FUNC (GtkMessagesShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_preferences), "activate", + GTK_SIGNAL_FUNC (GtkPreferencesShow), + NULL); + gtk_signal_connect (GTK_OBJECT (menubar_about), "activate", + GTK_SIGNAL_FUNC (GtkAboutShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_open), "clicked", + GTK_SIGNAL_FUNC (GtkFileOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_disc), "clicked", + GTK_SIGNAL_FUNC (GtkDiscOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_network), "clicked", + GTK_SIGNAL_FUNC (GtkNetworkOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_sat), "clicked", + GTK_SIGNAL_FUNC (GtkSatOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_back), "clicked", + GTK_SIGNAL_FUNC (GtkControlBack), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_stop), "clicked", + GTK_SIGNAL_FUNC (GtkControlStop), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_eject), "clicked", + GTK_SIGNAL_FUNC (GtkDiscEject), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_play), "clicked", + GTK_SIGNAL_FUNC (GtkControlPlay), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_pause), "clicked", + GTK_SIGNAL_FUNC (GtkControlPause), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_slow), "clicked", + GTK_SIGNAL_FUNC (GtkControlSlow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_fast), "clicked", + GTK_SIGNAL_FUNC (GtkControlFast), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_playlist), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistShow), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_prev), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistPrev), + NULL); + gtk_signal_connect (GTK_OBJECT (toolbar_next), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistNext), + NULL); + gtk_signal_connect (GTK_OBJECT (slider), "button_release_event", + GTK_SIGNAL_FUNC (GtkSliderRelease), + NULL); + gtk_signal_connect (GTK_OBJECT (slider), "button_press_event", + GTK_SIGNAL_FUNC (GtkSliderPress), + NULL); + gtk_signal_connect (GTK_OBJECT (title_prev_button), "clicked", + GTK_SIGNAL_FUNC (GtkTitlePrev), + NULL); + gtk_signal_connect (GTK_OBJECT (title_next_button), "clicked", + GTK_SIGNAL_FUNC (GtkTitleNext), + NULL); + gtk_signal_connect (GTK_OBJECT (chapter_prev_button), "clicked", + GTK_SIGNAL_FUNC (GtkChapterPrev), + NULL); + gtk_signal_connect (GTK_OBJECT (chapter_next_button), "clicked", + GTK_SIGNAL_FUNC (GtkChapterNext), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_spinbutton), "activate", + GTK_SIGNAL_FUNC (GtkNetworkJoin), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_go_button), "clicked", + GTK_SIGNAL_FUNC (GtkChannelGo), + NULL); + + gtk_object_set_data (GTK_OBJECT (intf_window), "tooltips", tooltips); + + gtk_window_add_accel_group (GTK_WINDOW (intf_window), accel_group); + + return intf_window; +} + +GtkWidget* +create_intf_popup (void) +{ + GtkWidget *intf_popup; + GtkAccelGroup *intf_popup_accels; + guint tmp_key; + GtkWidget *popup_play; + GtkWidget *popup_pause; + GtkWidget *popup_stop; + GtkWidget *popup_back; + GtkWidget *popup_slow; + GtkWidget *popup_fast; + GtkWidget *separator6; + GtkWidget *popup_interface_toggle; + GtkWidget *popup_fullscreen; + GtkWidget *separator5; + GtkWidget *popup_next; + GtkWidget *popup_prev; + GtkWidget *popup_jump; + GtkWidget *popup_program; + GtkWidget *popup_navigation; + GtkWidget *popup_audio; + GtkWidget *popup_subpictures; + GtkWidget *popup_open; + GtkWidget *popup_open_menu; + GtkAccelGroup *popup_open_menu_accels; + GtkWidget *popup_file; + GtkWidget *popup_disc; + GtkWidget *popup_network; + GtkWidget *separator12; + GtkWidget *popup_about; + GtkWidget *popup_playlist; + GtkWidget *popup_preferences; + GtkWidget *separator9; + GtkWidget *popup_exit; + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new (); + + intf_popup = gtk_menu_new (); + gtk_object_set_data (GTK_OBJECT (intf_popup), "intf_popup", intf_popup); + intf_popup_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (intf_popup)); + + popup_play = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_play)->child), + _("_Play")); + gtk_widget_add_accelerator (popup_play, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_play); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_play", popup_play, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_play); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_play); + + popup_pause = gtk_menu_item_new_with_label (_("Pause")); + gtk_widget_ref (popup_pause); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_pause", popup_pause, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_pause); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_pause); + gtk_widget_set_sensitive (popup_pause, FALSE); + + popup_stop = gtk_menu_item_new_with_label (_("Stop")); + gtk_widget_ref (popup_stop); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_stop", popup_stop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_stop); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_stop); + + popup_back = gtk_menu_item_new_with_label (_("Back")); + gtk_widget_ref (popup_back); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_back", popup_back, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_back); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_back); + gtk_widget_set_sensitive (popup_back, FALSE); + + popup_slow = gtk_menu_item_new_with_label (_("Slow")); + gtk_widget_ref (popup_slow); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_slow", popup_slow, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_slow); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_slow); + gtk_widget_set_sensitive (popup_slow, FALSE); + + popup_fast = gtk_menu_item_new_with_label (_("Fast")); + gtk_widget_ref (popup_fast); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_fast", popup_fast, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_fast); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_fast); + gtk_widget_set_sensitive (popup_fast, FALSE); + + separator6 = gtk_menu_item_new (); + gtk_widget_ref (separator6); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator6", separator6, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator6); + gtk_container_add (GTK_CONTAINER (intf_popup), separator6); + gtk_widget_set_sensitive (separator6, FALSE); + + popup_interface_toggle = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_interface_toggle)->child), + _("Toggle _Interface")); + gtk_widget_add_accelerator (popup_interface_toggle, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_interface_toggle); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_interface_toggle", popup_interface_toggle, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_interface_toggle); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_interface_toggle); + + popup_fullscreen = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_fullscreen)->child), + _("_Fullscreen")); + gtk_widget_add_accelerator (popup_fullscreen, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_fullscreen); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_fullscreen", popup_fullscreen, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_fullscreen); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_fullscreen); + + separator5 = gtk_menu_item_new (); + gtk_widget_ref (separator5); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator5", separator5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator5); + gtk_container_add (GTK_CONTAINER (intf_popup), separator5); + gtk_widget_set_sensitive (separator5, FALSE); + + popup_next = gtk_menu_item_new_with_label (_("Next")); + gtk_widget_ref (popup_next); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_next", popup_next, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_next); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_next); + + popup_prev = gtk_menu_item_new_with_label (_("Prev")); + gtk_widget_ref (popup_prev); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_prev", popup_prev, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_prev); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_prev); + + popup_jump = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_jump)->child), + _("_Jump...")); + gtk_widget_add_accelerator (popup_jump, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_jump); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_jump", popup_jump, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_jump); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_jump); + + popup_program = gtk_menu_item_new_with_label (_("Program")); + gtk_widget_ref (popup_program); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_program", popup_program, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_program); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_program); + gtk_widget_set_sensitive (popup_program, FALSE); + + popup_navigation = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_navigation)->child), + _("_Navigation")); + gtk_widget_add_accelerator (popup_navigation, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_navigation); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_navigation", popup_navigation, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_navigation); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_navigation); + gtk_widget_set_sensitive (popup_navigation, FALSE); + + popup_audio = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_audio)->child), + _("_Audio")); + gtk_widget_add_accelerator (popup_audio, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_audio); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_audio", popup_audio, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_audio); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_audio); + gtk_widget_set_sensitive (popup_audio, FALSE); + + popup_subpictures = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_subpictures)->child), + _("_Subtitles")); + gtk_widget_add_accelerator (popup_subpictures, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_subpictures); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_subpictures", popup_subpictures, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_subpictures); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_subpictures); + gtk_widget_set_sensitive (popup_subpictures, FALSE); + + popup_open = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_open)->child), + _("_File")); + gtk_widget_add_accelerator (popup_open, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_open); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_open", popup_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_open); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_open); + + popup_open_menu = gtk_menu_new (); + gtk_widget_ref (popup_open_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_open_menu", popup_open_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (popup_open), popup_open_menu); + popup_open_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (popup_open_menu)); + + popup_file = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_file)->child), + _("_Open File...")); + gtk_widget_add_accelerator (popup_file, "activate_item", popup_open_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_file); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_file", popup_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_file); + gtk_container_add (GTK_CONTAINER (popup_open_menu), popup_file); + gtk_tooltips_set_tip (tooltips, popup_file, _("Open a File"), NULL); + + popup_disc = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_disc)->child), + _("Open _Disc...")); + gtk_widget_add_accelerator (popup_disc, "activate_item", popup_open_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_disc", popup_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_disc); + gtk_container_add (GTK_CONTAINER (popup_open_menu), popup_disc); + gtk_tooltips_set_tip (tooltips, popup_disc, _("Open a DVD or VCD"), NULL); + + popup_network = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_network)->child), + _("_Network Stream...")); + gtk_widget_add_accelerator (popup_network, "activate_item", popup_open_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_network); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_network", popup_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_network); + gtk_container_add (GTK_CONTAINER (popup_open_menu), popup_network); + gtk_tooltips_set_tip (tooltips, popup_network, _("Select a Network Stream"), NULL); + + separator12 = gtk_menu_item_new (); + gtk_widget_ref (separator12); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator12", separator12, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator12); + gtk_container_add (GTK_CONTAINER (popup_open_menu), separator12); + gtk_widget_set_sensitive (separator12, FALSE); + + popup_about = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_about)->child), + _("_About...")); + gtk_widget_add_accelerator (popup_about, "activate_item", popup_open_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_about); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_about", popup_about, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_about); + gtk_container_add (GTK_CONTAINER (popup_open_menu), popup_about); + + popup_playlist = gtk_menu_item_new_with_label (_("Playlist...")); + gtk_widget_ref (popup_playlist); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_playlist", popup_playlist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_playlist); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_playlist); + + popup_preferences = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_preferences)->child), + _("_Preferences...")); + gtk_widget_add_accelerator (popup_preferences, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_preferences); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_preferences", popup_preferences, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_preferences); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_preferences); + + separator9 = gtk_menu_item_new (); + gtk_widget_ref (separator9); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "separator9", separator9, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (separator9); + gtk_container_add (GTK_CONTAINER (intf_popup), separator9); + gtk_widget_set_sensitive (separator9, FALSE); + + popup_exit = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (popup_exit)->child), + _("E_xit")); + gtk_widget_add_accelerator (popup_exit, "activate_item", intf_popup_accels, + tmp_key, 0, 0); + gtk_widget_ref (popup_exit); + gtk_object_set_data_full (GTK_OBJECT (intf_popup), "popup_exit", popup_exit, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (popup_exit); + gtk_container_add (GTK_CONTAINER (intf_popup), popup_exit); + + gtk_signal_connect (GTK_OBJECT (popup_play), "activate", + GTK_SIGNAL_FUNC (GtkControlPlay), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_pause), "activate", + GTK_SIGNAL_FUNC (GtkControlPause), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_stop), "activate", + GTK_SIGNAL_FUNC (GtkControlStop), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_back), "activate", + GTK_SIGNAL_FUNC (GtkControlBack), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_slow), "activate", + GTK_SIGNAL_FUNC (GtkControlSlow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_fast), "activate", + GTK_SIGNAL_FUNC (GtkControlFast), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_interface_toggle), "activate", + GTK_SIGNAL_FUNC (GtkWindowToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_fullscreen), "activate", + GTK_SIGNAL_FUNC (GtkFullscreen), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_next), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistNext), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_prev), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistPrev), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_jump), "activate", + GTK_SIGNAL_FUNC (GtkJumpShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_file), "activate", + GTK_SIGNAL_FUNC (GtkFileOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_disc), "activate", + GTK_SIGNAL_FUNC (GtkDiscOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_network), "activate", + GTK_SIGNAL_FUNC (GtkNetworkOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_about), "activate", + GTK_SIGNAL_FUNC (GtkAboutShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_playlist), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_preferences), "activate", + GTK_SIGNAL_FUNC (GtkPreferencesShow), + NULL); + gtk_signal_connect (GTK_OBJECT (popup_exit), "activate", + GTK_SIGNAL_FUNC (GtkExit), + NULL); + + gtk_object_set_data (GTK_OBJECT (intf_popup), "tooltips", tooltips); + + return intf_popup; +} + +GtkWidget* +create_intf_about (void) +{ + GtkWidget *intf_about; + GtkWidget *dialog_vbox1; + GtkWidget *vbox3; + GtkWidget *label14; + GtkWidget *label18; + GtkWidget *frame1; + GtkWidget *label16; + GtkWidget *label17; + GtkWidget *dialog_action_area; + GtkWidget *about_ok; + + intf_about = gtk_dialog_new (); + gtk_object_set_data (GTK_OBJECT (intf_about), "intf_about", intf_about); + gtk_container_set_border_width (GTK_CONTAINER (intf_about), 5); + gtk_window_set_title (GTK_WINDOW (intf_about), _("About")); + gtk_window_set_position (GTK_WINDOW (intf_about), GTK_WIN_POS_CENTER); + gtk_window_set_policy (GTK_WINDOW (intf_about), FALSE, FALSE, FALSE); + + dialog_vbox1 = GTK_DIALOG (intf_about)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_about), "dialog_vbox1", dialog_vbox1); + gtk_widget_show (dialog_vbox1); + + vbox3 = gtk_vbox_new (FALSE, 0); + gtk_widget_ref (vbox3); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "vbox3", vbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox3); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox3, TRUE, TRUE, 0); + + label14 = gtk_label_new (_("VideoLAN Client")); + gtk_widget_ref (label14); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "label14", label14, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label14); + gtk_box_pack_start (GTK_BOX (vbox3), label14, TRUE, TRUE, 0); + gtk_misc_set_padding (GTK_MISC (label14), 0, 10); + + label18 = gtk_label_new (_("(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team")); + gtk_widget_ref (label18); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "label18", label18, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label18); + gtk_box_pack_start (GTK_BOX (vbox3), label18, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label18), GTK_JUSTIFY_LEFT); + gtk_misc_set_padding (GTK_MISC (label18), 0, 5); + + frame1 = gtk_frame_new (_("Authors")); + gtk_widget_ref (frame1); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "frame1", frame1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame1); + gtk_box_pack_start (GTK_BOX (vbox3), frame1, FALSE, FALSE, 0); + + label16 = gtk_label_new (_("the VideoLAN team \nhttp://www.videolan.org/")); + gtk_widget_ref (label16); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "label16", label16, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label16); + gtk_container_add (GTK_CONTAINER (frame1), label16); + gtk_label_set_justify (GTK_LABEL (label16), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label16), 0.5, 0); + gtk_misc_set_padding (GTK_MISC (label16), 5, 5); + + label17 = gtk_label_new (_("This is the VideoLAN client, a DVD and MPEG player. It can play MPEG and MPEG 2 files from a file or from a network source.")); + gtk_widget_ref (label17); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "label17", label17, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label17); + gtk_box_pack_start (GTK_BOX (vbox3), label17, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (label17), GTK_JUSTIFY_LEFT); + gtk_label_set_line_wrap (GTK_LABEL (label17), TRUE); + gtk_misc_set_padding (GTK_MISC (label17), 0, 5); + + dialog_action_area = GTK_DIALOG (intf_about)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_about), "dialog_action_area", dialog_action_area); + gtk_widget_show (dialog_action_area); + gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area), 10); + + about_ok = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (about_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_about), "about_ok", about_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (about_ok); + gtk_box_pack_start (GTK_BOX (dialog_action_area), about_ok, FALSE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (about_ok, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (about_ok), "clicked", + GTK_SIGNAL_FUNC (GtkAboutOk), + NULL); + + gtk_widget_grab_default (about_ok); + return intf_about; +} + +GtkWidget* +create_intf_open (void) +{ + GtkWidget *intf_open; + GtkWidget *dialog_vbox7; + GtkWidget *open_vbox; + GtkWidget *frame10; + GtkWidget *hbox21; + GtkWidget *hbox22; + GtkWidget *label34; + GtkWidget *combo2; + GtkWidget *entry_open; + GtkWidget *label36; + GtkWidget *open_notebook; + GtkWidget *hbox20; + GtkWidget *combo1; + GtkWidget *entry_file; + GtkWidget *vbox13; + GtkWidget *open_browse; + GtkWidget *open_file; + GtkWidget *table5; + GtkWidget *label21; + GtkWidget *label20; + GtkObject *disc_chapter_adj; + GtkWidget *disc_chapter; + GtkWidget *label35; + GtkWidget *hbox24; + GSList *disc_group = NULL; + GtkWidget *disc_dvd; + GtkWidget *disc_vcd; + GtkWidget *label19; + GtkObject *disc_title_adj; + GtkWidget *disc_title; + GtkWidget *disc_name; + GtkWidget *open_disc; + GtkWidget *table4; + GSList *table4_group = NULL; + GtkWidget *network_udp; + GtkWidget *network_multicast; + GtkWidget *network_channel; + GtkWidget *network_http; + GtkWidget *network_udp_port_label; + GtkWidget *network_multicast_address_label; + GtkWidget *network_channel_address_label; + GtkWidget *network_http_url_label; + GtkWidget *network_multicast_address_combo; + GtkWidget *network_multicast_address; + GtkWidget *network_channel_address_combo; + GtkWidget *network_channel_address; + GtkWidget *network_multicast_port_label; + GtkWidget *network_channel_port_label; + GtkObject *network_multicast_port_adj; + GtkWidget *network_multicast_port; + GtkObject *network_channel_port_adj; + GtkWidget *network_channel_port; + GtkWidget *network_http_url; + GtkObject *network_udp_port_adj; + GtkWidget *network_udp_port; + GtkWidget *open_net; + GtkWidget *table3; + GtkWidget *label24; + GtkWidget *label25; + GtkWidget *label26; + GtkObject *sat_freq_adj; + GtkWidget *sat_freq; + GtkWidget *label27; + GtkWidget *hbox23; + GSList *pol_group = NULL; + GtkWidget *sat_pol_vert; + GtkWidget *sat_pol_hor; + GtkObject *sat_srate_adj; + GtkWidget *sat_srate; + GtkWidget *sat_fec; + GList *sat_fec_items = NULL; + GtkWidget *combo_entry1; + GtkWidget *open_sat; + GtkWidget *dialog_action_area6; + GtkWidget *hbox18; + GtkWidget *hbox19; + GtkWidget *open_ok; + GtkWidget *open_cancel; + GtkAccelGroup *accel_group; + + accel_group = gtk_accel_group_new (); + + intf_open = gtk_dialog_new (); + gtk_object_set_data (GTK_OBJECT (intf_open), "intf_open", intf_open); + gtk_container_set_border_width (GTK_CONTAINER (intf_open), 5); + gtk_window_set_title (GTK_WINDOW (intf_open), _("Open Target")); + + dialog_vbox7 = GTK_DIALOG (intf_open)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_open), "dialog_vbox7", dialog_vbox7); + gtk_widget_show (dialog_vbox7); + + open_vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (open_vbox); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_vbox", open_vbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_vbox); + gtk_box_pack_start (GTK_BOX (dialog_vbox7), open_vbox, TRUE, TRUE, 0); + + frame10 = gtk_frame_new (_("Media Resource Locator (MRL)")); + gtk_widget_ref (frame10); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "frame10", frame10, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (frame10); + gtk_box_pack_start (GTK_BOX (open_vbox), frame10, FALSE, TRUE, 0); + + hbox21 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox21); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox21", hbox21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox21); + gtk_container_add (GTK_CONTAINER (frame10), hbox21); + gtk_container_set_border_width (GTK_CONTAINER (hbox21), 5); + + hbox22 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox22); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox22", hbox22, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox22); + gtk_box_pack_start (GTK_BOX (hbox21), hbox22, FALSE, TRUE, 0); + + label34 = gtk_label_new (_("Open Target:")); + gtk_widget_ref (label34); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label34", label34, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label34); + gtk_box_pack_start (GTK_BOX (hbox22), label34, FALSE, FALSE, 0); + + combo2 = gtk_combo_new (); + gtk_widget_ref (combo2); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo2", combo2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo2); + gtk_box_pack_start (GTK_BOX (hbox21), combo2, TRUE, TRUE, 0); + + entry_open = GTK_COMBO (combo2)->entry; + gtk_widget_ref (entry_open); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "entry_open", entry_open, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry_open); + + label36 = gtk_label_new (_("Alternatively, you can build an MRL using one of the following predefined targets:")); + gtk_widget_ref (label36); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label36", label36, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label36); + gtk_box_pack_start (GTK_BOX (open_vbox), label36, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label36), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment (GTK_MISC (label36), 0, 1); + + open_notebook = gtk_notebook_new (); + gtk_widget_ref (open_notebook); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_notebook", open_notebook, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_notebook); + gtk_box_pack_start (GTK_BOX (open_vbox), open_notebook, TRUE, TRUE, 0); + + hbox20 = gtk_hbox_new (FALSE, 5); + gtk_widget_ref (hbox20); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox20", hbox20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox20); + gtk_container_add (GTK_CONTAINER (open_notebook), hbox20); + gtk_container_set_border_width (GTK_CONTAINER (hbox20), 5); + + combo1 = gtk_combo_new (); + gtk_widget_ref (combo1); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo1", combo1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo1); + gtk_box_pack_start (GTK_BOX (hbox20), combo1, FALSE, TRUE, 0); + + entry_file = GTK_COMBO (combo1)->entry; + gtk_widget_ref (entry_file); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "entry_file", entry_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (entry_file); + + vbox13 = gtk_vbox_new (TRUE, 0); + gtk_widget_ref (vbox13); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "vbox13", vbox13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox13); + gtk_box_pack_start (GTK_BOX (hbox20), vbox13, FALSE, FALSE, 0); + + open_browse = gtk_button_new_with_label (_("Browse...")); + gtk_widget_ref (open_browse); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_browse", open_browse, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_browse); + gtk_box_pack_start (GTK_BOX (vbox13), open_browse, FALSE, FALSE, 0); + + open_file = gtk_label_new (_("File")); + gtk_widget_ref (open_file); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_file", open_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_file); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 0), open_file); + + table5 = gtk_table_new (4, 2, FALSE); + gtk_widget_ref (table5); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table5", table5, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table5); + gtk_container_add (GTK_CONTAINER (open_notebook), table5); + gtk_container_set_border_width (GTK_CONTAINER (table5), 5); + gtk_table_set_row_spacings (GTK_TABLE (table5), 5); + gtk_table_set_col_spacings (GTK_TABLE (table5), 5); + + label21 = gtk_label_new (_("Title")); + gtk_widget_ref (label21); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label21", label21, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label21); + gtk_table_attach (GTK_TABLE (table5), label21, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label21), 0, 0.5); + + label20 = gtk_label_new (_("Chapter")); + gtk_widget_ref (label20); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label20", label20, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label20); + gtk_table_attach (GTK_TABLE (table5), label20, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label20), 0, 0.5); + + disc_chapter_adj = gtk_adjustment_new (1, 1, 65536, 1, 10, 10); + disc_chapter = gtk_spin_button_new (GTK_ADJUSTMENT (disc_chapter_adj), 1, 0); + gtk_widget_ref (disc_chapter); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_chapter", disc_chapter, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_chapter); + gtk_table_attach (GTK_TABLE (table5), disc_chapter, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label35 = gtk_label_new (_("Disc type")); + gtk_widget_ref (label35); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label35", label35, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label35); + gtk_table_attach (GTK_TABLE (table5), label35, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label35), 0, 0.5); + + hbox24 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox24); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox24", hbox24, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox24); + gtk_table_attach (GTK_TABLE (table5), hbox24, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + disc_dvd = gtk_radio_button_new_with_label (disc_group, _("DVD")); + disc_group = gtk_radio_button_group (GTK_RADIO_BUTTON (disc_dvd)); + gtk_widget_ref (disc_dvd); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_dvd", disc_dvd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_dvd); + gtk_box_pack_start (GTK_BOX (hbox24), disc_dvd, FALSE, FALSE, 0); + + disc_vcd = gtk_radio_button_new_with_label (disc_group, _("VCD")); + disc_group = gtk_radio_button_group (GTK_RADIO_BUTTON (disc_vcd)); + gtk_widget_ref (disc_vcd); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_vcd", disc_vcd, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_vcd); + gtk_box_pack_start (GTK_BOX (hbox24), disc_vcd, FALSE, FALSE, 0); + + label19 = gtk_label_new (_("Device name")); + gtk_widget_ref (label19); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label19", label19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label19); + gtk_table_attach (GTK_TABLE (table5), label19, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + disc_title_adj = gtk_adjustment_new (1, 1, 65536, 1, 10, 10); + disc_title = gtk_spin_button_new (GTK_ADJUSTMENT (disc_title_adj), 1, 0); + gtk_widget_ref (disc_title); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_title", disc_title, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_title); + gtk_table_attach (GTK_TABLE (table5), disc_title, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + disc_name = gtk_entry_new (); + gtk_widget_ref (disc_name); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "disc_name", disc_name, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (disc_name); + gtk_table_attach (GTK_TABLE (table5), disc_name, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_entry_set_text (GTK_ENTRY (disc_name), "/dev/dvd"); + + open_disc = gtk_label_new (_("Disc")); + gtk_widget_ref (open_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_disc", open_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_disc); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 1), open_disc); + + table4 = gtk_table_new (4, 6, FALSE); + gtk_widget_ref (table4); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table4", table4, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table4); + gtk_container_add (GTK_CONTAINER (open_notebook), table4); + gtk_container_set_border_width (GTK_CONTAINER (table4), 5); + gtk_table_set_row_spacings (GTK_TABLE (table4), 5); + gtk_table_set_col_spacings (GTK_TABLE (table4), 5); + + network_udp = gtk_radio_button_new_with_label (table4_group, _("UDP")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_udp)); + gtk_widget_ref (network_udp); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp", network_udp, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp); + gtk_table_attach (GTK_TABLE (table4), network_udp, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_multicast = gtk_radio_button_new_with_label (table4_group, _("UDP Multicast")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_multicast)); + gtk_widget_ref (network_multicast); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast", network_multicast, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast); + gtk_table_attach (GTK_TABLE (table4), network_multicast, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_channel = gtk_radio_button_new_with_label (table4_group, _("Channel server ")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_channel)); + gtk_widget_ref (network_channel); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel", network_channel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel); + gtk_table_attach (GTK_TABLE (table4), network_channel, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_http = gtk_radio_button_new_with_label (table4_group, _("HTTP")); + table4_group = gtk_radio_button_group (GTK_RADIO_BUTTON (network_http)); + gtk_widget_ref (network_http); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http", network_http, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http); + gtk_table_attach (GTK_TABLE (table4), network_http, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + network_udp_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_udp_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp_port_label", network_udp_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp_port_label); + gtk_table_attach (GTK_TABLE (table4), network_udp_port_label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (network_udp_port_label), 1, 0.5); + + network_multicast_address_label = gtk_label_new (_("Address")); + gtk_widget_ref (network_multicast_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address_label", network_multicast_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address_label); + gtk_table_attach (GTK_TABLE (table4), network_multicast_address_label, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_address_label, FALSE); + gtk_label_set_justify (GTK_LABEL (network_multicast_address_label), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (network_multicast_address_label), 1, 0.5); + + network_channel_address_label = gtk_label_new (_("Address")); + gtk_widget_ref (network_channel_address_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address_label", network_channel_address_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address_label); + gtk_table_attach (GTK_TABLE (table4), network_channel_address_label, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_address_label, FALSE); + + network_http_url_label = gtk_label_new (_("URL")); + gtk_widget_ref (network_http_url_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http_url_label", network_http_url_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http_url_label); + gtk_table_attach (GTK_TABLE (table4), network_http_url_label, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_http_url_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_http_url_label), 1, 0.5); + + network_multicast_address_combo = gtk_combo_new (); + gtk_widget_ref (network_multicast_address_combo); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address_combo", network_multicast_address_combo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address_combo); + gtk_table_attach (GTK_TABLE (table4), network_multicast_address_combo, 2, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_address_combo, FALSE); + + network_multicast_address = GTK_COMBO (network_multicast_address_combo)->entry; + gtk_widget_ref (network_multicast_address); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_address", network_multicast_address, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_address); + + network_channel_address_combo = gtk_combo_new (); + gtk_widget_ref (network_channel_address_combo); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address_combo", network_channel_address_combo, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address_combo); + gtk_table_attach (GTK_TABLE (table4), network_channel_address_combo, 2, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_address_combo, FALSE); + + network_channel_address = GTK_COMBO (network_channel_address_combo)->entry; + gtk_widget_ref (network_channel_address); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_address", network_channel_address, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_address); + + network_multicast_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_multicast_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_port_label", network_multicast_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_port_label); + gtk_table_attach (GTK_TABLE (table4), network_multicast_port_label, 4, 5, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_multicast_port_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_multicast_port_label), 1, 0.5); + + network_channel_port_label = gtk_label_new (_("Port")); + gtk_widget_ref (network_channel_port_label); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_port_label", network_channel_port_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_port_label); + gtk_table_attach (GTK_TABLE (table4), network_channel_port_label, 4, 5, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_channel_port_label, FALSE); + gtk_misc_set_alignment (GTK_MISC (network_channel_port_label), 1, 0.5); + + network_multicast_port_adj = gtk_adjustment_new (1234, 0, 65535, 1, 10, 10); + network_multicast_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_multicast_port_adj), 1, 0); + gtk_widget_ref (network_multicast_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_multicast_port", network_multicast_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_multicast_port); + gtk_table_attach (GTK_TABLE (table4), network_multicast_port, 5, 6, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_multicast_port, 75, -2); + gtk_widget_set_sensitive (network_multicast_port, FALSE); + + network_channel_port_adj = gtk_adjustment_new (6010, 0, 65535, 1, 10, 10); + network_channel_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_channel_port_adj), 1, 0); + gtk_widget_ref (network_channel_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_channel_port", network_channel_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_channel_port); + gtk_table_attach (GTK_TABLE (table4), network_channel_port, 5, 6, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_channel_port, 75, -2); + gtk_widget_set_sensitive (network_channel_port, FALSE); + + network_http_url = gtk_entry_new (); + gtk_widget_ref (network_http_url); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_http_url", network_http_url, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_http_url); + gtk_table_attach (GTK_TABLE (table4), network_http_url, 2, 6, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_sensitive (network_http_url, FALSE); + + network_udp_port_adj = gtk_adjustment_new (1234, 0, 65535, 1, 10, 10); + network_udp_port = gtk_spin_button_new (GTK_ADJUSTMENT (network_udp_port_adj), 1, 0); + gtk_widget_ref (network_udp_port); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "network_udp_port", network_udp_port, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (network_udp_port); + gtk_table_attach (GTK_TABLE (table4), network_udp_port, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_set_usize (network_udp_port, 1, -2); + + open_net = gtk_label_new (_("Network")); + gtk_widget_ref (open_net); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_net", open_net, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_net); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 2), open_net); + + table3 = gtk_table_new (4, 2, FALSE); + gtk_widget_ref (table3); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "table3", table3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (table3); + gtk_container_add (GTK_CONTAINER (open_notebook), table3); + gtk_container_set_border_width (GTK_CONTAINER (table3), 5); + gtk_table_set_row_spacings (GTK_TABLE (table3), 5); + gtk_table_set_col_spacings (GTK_TABLE (table3), 5); + + label24 = gtk_label_new (_("Symbol Rate")); + gtk_widget_ref (label24); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label24", label24, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label24); + gtk_table_attach (GTK_TABLE (table3), label24, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label24), 0, 0.5); + + label25 = gtk_label_new (_("Frequency")); + gtk_widget_ref (label25); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label25", label25, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label25); + gtk_table_attach (GTK_TABLE (table3), label25, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label25), 0, 0.5); + + label26 = gtk_label_new (_("Polarization")); + gtk_widget_ref (label26); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label26", label26, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label26); + gtk_table_attach (GTK_TABLE (table3), label26, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label26), 0, 0.5); + + sat_freq_adj = gtk_adjustment_new (11954, 10000, 12999, 1, 10, 10); + sat_freq = gtk_spin_button_new (GTK_ADJUSTMENT (sat_freq_adj), 1, 0); + gtk_widget_ref (sat_freq); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_freq", sat_freq, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_freq); + gtk_table_attach (GTK_TABLE (table3), sat_freq, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label27 = gtk_label_new (_("FEC")); + gtk_widget_ref (label27); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "label27", label27, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label27); + gtk_table_attach (GTK_TABLE (table3), label27, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label27), 0, 0.5); + + hbox23 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox23); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox23", hbox23, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox23); + gtk_table_attach (GTK_TABLE (table3), hbox23, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + sat_pol_vert = gtk_radio_button_new_with_label (pol_group, _("Vertical")); + pol_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sat_pol_vert)); + gtk_widget_ref (sat_pol_vert); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_pol_vert", sat_pol_vert, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_pol_vert); + gtk_box_pack_start (GTK_BOX (hbox23), sat_pol_vert, FALSE, FALSE, 0); + + sat_pol_hor = gtk_radio_button_new_with_label (pol_group, _("Horizontal")); + pol_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sat_pol_hor)); + gtk_widget_ref (sat_pol_hor); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_pol_hor", sat_pol_hor, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_pol_hor); + gtk_box_pack_start (GTK_BOX (hbox23), sat_pol_hor, FALSE, FALSE, 0); + + sat_srate_adj = gtk_adjustment_new (27500, 1000, 30000, 1, 10, 10); + sat_srate = gtk_spin_button_new (GTK_ADJUSTMENT (sat_srate_adj), 1, 0); + gtk_widget_ref (sat_srate); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_srate", sat_srate, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_srate); + gtk_table_attach (GTK_TABLE (table3), sat_srate, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + sat_fec = gtk_combo_new (); + gtk_widget_ref (sat_fec); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "sat_fec", sat_fec, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (sat_fec); + gtk_table_attach (GTK_TABLE (table3), sat_fec, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "1/2"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "2/3"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "3/4"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "4/5"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "5/6"); + sat_fec_items = g_list_append (sat_fec_items, (gpointer) "7/8"); + gtk_combo_set_popdown_strings (GTK_COMBO (sat_fec), sat_fec_items); + g_list_free (sat_fec_items); + + combo_entry1 = GTK_COMBO (sat_fec)->entry; + gtk_widget_ref (combo_entry1); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "combo_entry1", combo_entry1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (combo_entry1); + gtk_entry_set_text (GTK_ENTRY (combo_entry1), "3/4"); + + open_sat = gtk_label_new (_("Satellite")); + gtk_widget_ref (open_sat); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_sat", open_sat, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_sat); + gtk_notebook_set_tab_label (GTK_NOTEBOOK (open_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (open_notebook), 3), open_sat); + + dialog_action_area6 = GTK_DIALOG (intf_open)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_open), "dialog_action_area6", dialog_action_area6); + gtk_widget_show (dialog_action_area6); + gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area6), 5); + + hbox18 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox18); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox18", hbox18, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox18); + gtk_box_pack_start (GTK_BOX (dialog_action_area6), hbox18, TRUE, TRUE, 0); + + hbox19 = gtk_hbox_new (TRUE, 5); + gtk_widget_ref (hbox19); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "hbox19", hbox19, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox19); + gtk_box_pack_end (GTK_BOX (hbox18), hbox19, FALSE, TRUE, 0); + + open_ok = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (open_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_ok", open_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_ok); + gtk_box_pack_start (GTK_BOX (hbox19), open_ok, FALSE, TRUE, 0); + + open_cancel = gtk_button_new_with_label (_("Cancel")); + gtk_widget_ref (open_cancel); + gtk_object_set_data_full (GTK_OBJECT (intf_open), "open_cancel", open_cancel, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (open_cancel); + gtk_box_pack_start (GTK_BOX (hbox19), open_cancel, FALSE, TRUE, 0); + gtk_widget_add_accelerator (open_cancel, "clicked", accel_group, + GDK_Escape, 0, + GTK_ACCEL_VISIBLE); + + gtk_signal_connect_after (GTK_OBJECT (open_notebook), "switch_page", + GTK_SIGNAL_FUNC (GtkOpenNotebookChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (entry_file), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (open_browse), "clicked", + GTK_SIGNAL_FUNC (GtkFileShow), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_chapter), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_dvd), "toggled", + GTK_SIGNAL_FUNC (GtkDiscOpenDvd), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_vcd), "toggled", + GTK_SIGNAL_FUNC (GtkDiscOpenVcd), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_title), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (disc_name), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_udp), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenUDP), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenMulticast), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenChannel), + NULL); + gtk_signal_connect (GTK_OBJECT (network_http), "toggled", + GTK_SIGNAL_FUNC (GtkNetworkOpenHTTP), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast_address), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_address), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_multicast_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_channel_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_http_url), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (network_udp_port), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_freq), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_pol_vert), "toggled", + GTK_SIGNAL_FUNC (GtkSatOpenToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_pol_hor), "toggled", + GTK_SIGNAL_FUNC (GtkSatOpenToggle), + NULL); + gtk_signal_connect (GTK_OBJECT (sat_srate), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (combo_entry1), "changed", + GTK_SIGNAL_FUNC (GtkOpenChanged), + NULL); + gtk_signal_connect (GTK_OBJECT (open_ok), "clicked", + GTK_SIGNAL_FUNC (GtkOpenOk), + NULL); + gtk_signal_connect (GTK_OBJECT (open_cancel), "clicked", + GTK_SIGNAL_FUNC (GtkOpenCancel), + NULL); + + gtk_window_add_accel_group (GTK_WINDOW (intf_open), accel_group); + + return intf_open; +} + +GtkWidget* +create_intf_file (void) +{ + GtkWidget *intf_file; + GtkWidget *file_ok; + GtkWidget *file_cancel; + + intf_file = gtk_file_selection_new (_("Select File")); + gtk_object_set_data (GTK_OBJECT (intf_file), "intf_file", intf_file); + gtk_container_set_border_width (GTK_CONTAINER (intf_file), 10); + gtk_window_set_modal (GTK_WINDOW (intf_file), TRUE); + + file_ok = GTK_FILE_SELECTION (intf_file)->ok_button; + gtk_object_set_data (GTK_OBJECT (intf_file), "file_ok", file_ok); + gtk_widget_show (file_ok); + GTK_WIDGET_SET_FLAGS (file_ok, GTK_CAN_DEFAULT); + + file_cancel = GTK_FILE_SELECTION (intf_file)->cancel_button; + gtk_object_set_data (GTK_OBJECT (intf_file), "file_cancel", file_cancel); + gtk_widget_show (file_cancel); + GTK_WIDGET_SET_FLAGS (file_cancel, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (file_ok), "clicked", + GTK_SIGNAL_FUNC (GtkFileOk), + NULL); + gtk_signal_connect (GTK_OBJECT (file_cancel), "clicked", + GTK_SIGNAL_FUNC (GtkFileCancel), + NULL); + + return intf_file; +} + +GtkWidget* +create_intf_jump (void) +{ + GtkWidget *intf_jump; + GtkWidget *dialog_vbox3; + GtkWidget *jump_frame; + GtkWidget *hbox13; + GtkWidget *jump_second_label; + GtkObject *jump_second_spinbutton_adj; + GtkWidget *jump_second_spinbutton; + GtkWidget *jump_minute_label; + GtkObject *jump_minute_spinbutton_adj; + GtkWidget *jump_minute_spinbutton; + GtkWidget *jump_hour_label; + GtkObject *jump_hour_spinbutton_adj; + GtkWidget *jump_hour_spinbutton; + GtkWidget *dialog_action_area2; + GtkWidget *jump_ok_button; + GtkWidget *jump_cancel_button; + + intf_jump = gtk_dialog_new (); + gtk_object_set_data (GTK_OBJECT (intf_jump), "intf_jump", intf_jump); + gtk_window_set_title (GTK_WINDOW (intf_jump), _("Jump")); + gtk_window_set_policy (GTK_WINDOW (intf_jump), TRUE, TRUE, FALSE); + + dialog_vbox3 = GTK_DIALOG (intf_jump)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_jump), "dialog_vbox3", dialog_vbox3); + gtk_widget_show (dialog_vbox3); + + jump_frame = gtk_frame_new (_("Go to:")); + gtk_widget_ref (jump_frame); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_frame", jump_frame, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_frame); + gtk_box_pack_start (GTK_BOX (dialog_vbox3), jump_frame, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (jump_frame), 5); + gtk_frame_set_label_align (GTK_FRAME (jump_frame), 0.05, 0.5); + + hbox13 = gtk_hbox_new (FALSE, 0); + gtk_widget_ref (hbox13); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "hbox13", hbox13, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbox13); + gtk_container_add (GTK_CONTAINER (jump_frame), hbox13); + + jump_second_label = gtk_label_new (_("s.")); + gtk_widget_ref (jump_second_label); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_second_label", jump_second_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_second_label); + gtk_box_pack_end (GTK_BOX (hbox13), jump_second_label, FALSE, FALSE, 5); + + jump_second_spinbutton_adj = gtk_adjustment_new (0, 0, 60, 1, 10, 10); + jump_second_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_second_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_second_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_second_spinbutton", jump_second_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_second_spinbutton); + gtk_box_pack_end (GTK_BOX (hbox13), jump_second_spinbutton, FALSE, TRUE, 0); + + jump_minute_label = gtk_label_new (_("m:")); + gtk_widget_ref (jump_minute_label); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_minute_label", jump_minute_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_minute_label); + gtk_box_pack_end (GTK_BOX (hbox13), jump_minute_label, FALSE, FALSE, 5); + + jump_minute_spinbutton_adj = gtk_adjustment_new (0, 0, 60, 1, 10, 10); + jump_minute_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_minute_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_minute_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_minute_spinbutton", jump_minute_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_minute_spinbutton); + gtk_box_pack_end (GTK_BOX (hbox13), jump_minute_spinbutton, FALSE, TRUE, 0); + + jump_hour_label = gtk_label_new (_("h:")); + gtk_widget_ref (jump_hour_label); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_hour_label", jump_hour_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_hour_label); + gtk_box_pack_end (GTK_BOX (hbox13), jump_hour_label, FALSE, FALSE, 5); + + jump_hour_spinbutton_adj = gtk_adjustment_new (0, 0, 12, 1, 10, 10); + jump_hour_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (jump_hour_spinbutton_adj), 1, 0); + gtk_widget_ref (jump_hour_spinbutton); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_hour_spinbutton", jump_hour_spinbutton, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_hour_spinbutton); + gtk_box_pack_end (GTK_BOX (hbox13), jump_hour_spinbutton, FALSE, TRUE, 0); + + dialog_action_area2 = GTK_DIALOG (intf_jump)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_jump), "dialog_action_area2", dialog_action_area2); + gtk_widget_show (dialog_action_area2); + gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area2), 10); + + jump_ok_button = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (jump_ok_button); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_ok_button", jump_ok_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_ok_button); + gtk_box_pack_start (GTK_BOX (dialog_action_area2), jump_ok_button, TRUE, TRUE, 0); + + jump_cancel_button = gtk_button_new_with_label (_("Cancel")); + gtk_widget_ref (jump_cancel_button); + gtk_object_set_data_full (GTK_OBJECT (intf_jump), "jump_cancel_button", jump_cancel_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (jump_cancel_button); + gtk_box_pack_start (GTK_BOX (dialog_action_area2), jump_cancel_button, TRUE, TRUE, 0); + + gtk_signal_connect (GTK_OBJECT (jump_ok_button), "clicked", + GTK_SIGNAL_FUNC (GtkJumpOk), + NULL); + gtk_signal_connect (GTK_OBJECT (jump_cancel_button), "clicked", + GTK_SIGNAL_FUNC (GtkJumpCancel), + NULL); + + return intf_jump; +} + +GtkWidget* +create_intf_playlist (void) +{ + GtkWidget *intf_playlist; + GtkWidget *dialog_vbox4; + GtkWidget *playlist_menubar; + GtkWidget *playlist_add; + GtkWidget *playlist_add_menu; + GtkAccelGroup *playlist_add_menu_accels; + GtkWidget *playlist_add_disc; + GtkWidget *playlist_add_file; + GtkWidget *playlist_add_network; + GtkWidget *playlist_add_url; + GtkWidget *playlist_delete; + GtkWidget *playlist_delete_menu; + GtkAccelGroup *playlist_delete_menu_accels; + GtkWidget *playlist_delete_all; + GtkWidget *playlist_delete_selected; + GtkWidget *playlist_selection; + GtkWidget *playlist_selection_menu; + GtkAccelGroup *playlist_selection_menu_accels; + guint tmp_key; + GtkWidget *playlist_selection_crop; + GtkWidget *playlist_selection_invert; + GtkWidget *playlist_selection_select; + GtkWidget *scrolledwindow1; + GtkWidget *playlist_clist; + GtkWidget *label22; + GtkWidget *label23; + GtkWidget *dialog_action_area3; + GtkWidget *playlist_ok_button; + GtkWidget *playlist_cancel_button; + + intf_playlist = gtk_dialog_new (); + gtk_object_set_data (GTK_OBJECT (intf_playlist), "intf_playlist", intf_playlist); + gtk_window_set_title (GTK_WINDOW (intf_playlist), _("Playlist")); + gtk_window_set_default_size (GTK_WINDOW (intf_playlist), 400, 300); + gtk_window_set_policy (GTK_WINDOW (intf_playlist), TRUE, TRUE, FALSE); + + dialog_vbox4 = GTK_DIALOG (intf_playlist)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_playlist), "dialog_vbox4", dialog_vbox4); + gtk_widget_show (dialog_vbox4); + + playlist_menubar = gtk_menu_bar_new (); + gtk_widget_ref (playlist_menubar); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_menubar", playlist_menubar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_menubar); + gtk_box_pack_start (GTK_BOX (dialog_vbox4), playlist_menubar, FALSE, FALSE, 0); + + playlist_add = gtk_menu_item_new_with_label (_("Add")); + gtk_widget_ref (playlist_add); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add", playlist_add, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_add); + gtk_container_add (GTK_CONTAINER (playlist_menubar), playlist_add); + + playlist_add_menu = gtk_menu_new (); + gtk_widget_ref (playlist_add_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_menu", playlist_add_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (playlist_add), playlist_add_menu); + playlist_add_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (playlist_add_menu)); + + playlist_add_disc = gtk_menu_item_new_with_label (_("Disc")); + gtk_widget_ref (playlist_add_disc); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_disc", playlist_add_disc, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_add_disc); + gtk_container_add (GTK_CONTAINER (playlist_add_menu), playlist_add_disc); + + playlist_add_file = gtk_menu_item_new_with_label (_("File")); + gtk_widget_ref (playlist_add_file); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_file", playlist_add_file, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_add_file); + gtk_container_add (GTK_CONTAINER (playlist_add_menu), playlist_add_file); + + playlist_add_network = gtk_menu_item_new_with_label (_("Network")); + gtk_widget_ref (playlist_add_network); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_network", playlist_add_network, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_add_network); + gtk_container_add (GTK_CONTAINER (playlist_add_menu), playlist_add_network); + + playlist_add_url = gtk_menu_item_new_with_label (_("Url")); + gtk_widget_ref (playlist_add_url); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_add_url", playlist_add_url, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_add_url); + gtk_container_add (GTK_CONTAINER (playlist_add_menu), playlist_add_url); + + playlist_delete = gtk_menu_item_new_with_label (_("Delete")); + gtk_widget_ref (playlist_delete); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete", playlist_delete, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_delete); + gtk_container_add (GTK_CONTAINER (playlist_menubar), playlist_delete); + + playlist_delete_menu = gtk_menu_new (); + gtk_widget_ref (playlist_delete_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete_menu", playlist_delete_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (playlist_delete), playlist_delete_menu); + playlist_delete_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (playlist_delete_menu)); + + playlist_delete_all = gtk_menu_item_new_with_label (_("All")); + gtk_widget_ref (playlist_delete_all); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete_all", playlist_delete_all, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_delete_all); + gtk_container_add (GTK_CONTAINER (playlist_delete_menu), playlist_delete_all); + + playlist_delete_selected = gtk_menu_item_new_with_label (_("Selected")); + gtk_widget_ref (playlist_delete_selected); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_delete_selected", playlist_delete_selected, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_delete_selected); + gtk_container_add (GTK_CONTAINER (playlist_delete_menu), playlist_delete_selected); + + playlist_selection = gtk_menu_item_new_with_label (_("Selection")); + gtk_widget_ref (playlist_selection); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection", playlist_selection, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_selection); + gtk_container_add (GTK_CONTAINER (playlist_menubar), playlist_selection); + + playlist_selection_menu = gtk_menu_new (); + gtk_widget_ref (playlist_selection_menu); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_menu", playlist_selection_menu, + (GtkDestroyNotify) gtk_widget_unref); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (playlist_selection), playlist_selection_menu); + playlist_selection_menu_accels = gtk_menu_ensure_uline_accel_group (GTK_MENU (playlist_selection_menu)); + + playlist_selection_crop = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (playlist_selection_crop)->child), + _("_Crop")); + gtk_widget_add_accelerator (playlist_selection_crop, "activate_item", playlist_selection_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (playlist_selection_crop); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_crop", playlist_selection_crop, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_selection_crop); + gtk_container_add (GTK_CONTAINER (playlist_selection_menu), playlist_selection_crop); + + playlist_selection_invert = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (playlist_selection_invert)->child), + _("_Invert")); + gtk_widget_add_accelerator (playlist_selection_invert, "activate_item", playlist_selection_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (playlist_selection_invert); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_invert", playlist_selection_invert, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_selection_invert); + gtk_container_add (GTK_CONTAINER (playlist_selection_menu), playlist_selection_invert); + + playlist_selection_select = gtk_menu_item_new_with_label (""); + tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (playlist_selection_select)->child), + _("_Select")); + gtk_widget_add_accelerator (playlist_selection_select, "activate_item", playlist_selection_menu_accels, + tmp_key, 0, 0); + gtk_widget_ref (playlist_selection_select); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_selection_select", playlist_selection_select, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_selection_select); + gtk_container_add (GTK_CONTAINER (playlist_selection_menu), playlist_selection_select); + + scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow1); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "scrolledwindow1", scrolledwindow1, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow1); + gtk_box_pack_start (GTK_BOX (dialog_vbox4), scrolledwindow1, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + playlist_clist = gtk_clist_new (2); + gtk_widget_ref (playlist_clist); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_clist", playlist_clist, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_clist); + gtk_container_add (GTK_CONTAINER (scrolledwindow1), playlist_clist); + gtk_container_set_border_width (GTK_CONTAINER (playlist_clist), 5); + gtk_clist_set_column_width (GTK_CLIST (playlist_clist), 0, 257); + gtk_clist_set_column_width (GTK_CLIST (playlist_clist), 1, 80); + gtk_clist_set_selection_mode (GTK_CLIST (playlist_clist), GTK_SELECTION_EXTENDED); + gtk_clist_column_titles_show (GTK_CLIST (playlist_clist)); + gtk_clist_set_shadow_type (GTK_CLIST (playlist_clist), GTK_SHADOW_OUT); + + label22 = gtk_label_new (_("File")); + gtk_widget_ref (label22); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "label22", label22, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label22); + gtk_clist_set_column_widget (GTK_CLIST (playlist_clist), 0, label22); + + label23 = gtk_label_new (_("Duration")); + gtk_widget_ref (label23); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "label23", label23, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (label23); + gtk_clist_set_column_widget (GTK_CLIST (playlist_clist), 1, label23); + + dialog_action_area3 = GTK_DIALOG (intf_playlist)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_playlist), "dialog_action_area3", dialog_action_area3); + gtk_widget_show (dialog_action_area3); + gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area3), 10); + + playlist_ok_button = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (playlist_ok_button); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_ok_button", playlist_ok_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_ok_button); + gtk_box_pack_start (GTK_BOX (dialog_action_area3), playlist_ok_button, TRUE, TRUE, 0); + + playlist_cancel_button = gtk_button_new_with_label (_("Cancel")); + gtk_widget_ref (playlist_cancel_button); + gtk_object_set_data_full (GTK_OBJECT (intf_playlist), "playlist_cancel_button", playlist_cancel_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (playlist_cancel_button); + gtk_box_pack_start (GTK_BOX (dialog_action_area3), playlist_cancel_button, TRUE, TRUE, 0); + + gtk_signal_connect (GTK_OBJECT (intf_playlist), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (intf_playlist), "delete_event", + GTK_SIGNAL_FUNC (gtk_widget_hide), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_add_disc), "activate", + GTK_SIGNAL_FUNC (GtkDiscOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_add_file), "activate", + GTK_SIGNAL_FUNC (GtkFileOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_add_network), "activate", + GTK_SIGNAL_FUNC (GtkNetworkOpenShow), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_add_url), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistAddUrl), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_delete_all), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistDeleteAll), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_delete_selected), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistDeleteSelected), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_selection_crop), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistCrop), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_selection_invert), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistInvert), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_selection_select), "activate", + GTK_SIGNAL_FUNC (GtkPlaylistSelect), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "event", + GTK_SIGNAL_FUNC (GtkPlaylistEvent), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "drag_data_received", + GTK_SIGNAL_FUNC (GtkPlaylistDragData), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_clist), "drag_motion", + GTK_SIGNAL_FUNC (GtkPlaylistDragMotion), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_ok_button), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistOk), + NULL); + gtk_signal_connect (GTK_OBJECT (playlist_cancel_button), "clicked", + GTK_SIGNAL_FUNC (GtkPlaylistCancel), + NULL); + + return intf_playlist; +} + +GtkWidget* +create_intf_messages (void) +{ + GtkWidget *intf_messages; + GtkWidget *dialog_vbox6; + GtkWidget *scrolledwindow2; + GtkWidget *messages_textbox; + GtkWidget *dialog_action_area5; + GtkWidget *messages_ok; + + intf_messages = gtk_dialog_new (); + gtk_object_set_data (GTK_OBJECT (intf_messages), "intf_messages", intf_messages); + gtk_window_set_title (GTK_WINDOW (intf_messages), _("Messages")); + gtk_window_set_default_size (GTK_WINDOW (intf_messages), 600, 400); + gtk_window_set_policy (GTK_WINDOW (intf_messages), TRUE, TRUE, FALSE); + + dialog_vbox6 = GTK_DIALOG (intf_messages)->vbox; + gtk_object_set_data (GTK_OBJECT (intf_messages), "dialog_vbox6", dialog_vbox6); + gtk_widget_show (dialog_vbox6); + + scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_ref (scrolledwindow2); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "scrolledwindow2", scrolledwindow2, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (scrolledwindow2); + gtk_box_pack_start (GTK_BOX (dialog_vbox6), scrolledwindow2, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow2), 5); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + + messages_textbox = gtk_text_new (NULL, NULL); + gtk_widget_ref (messages_textbox); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "messages_textbox", messages_textbox, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (messages_textbox); + gtk_container_add (GTK_CONTAINER (scrolledwindow2), messages_textbox); + + dialog_action_area5 = GTK_DIALOG (intf_messages)->action_area; + gtk_object_set_data (GTK_OBJECT (intf_messages), "dialog_action_area5", dialog_action_area5); + gtk_widget_show (dialog_action_area5); + gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area5), 5); + + messages_ok = gtk_button_new_with_label (_("OK")); + gtk_widget_ref (messages_ok); + gtk_object_set_data_full (GTK_OBJECT (intf_messages), "messages_ok", messages_ok, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (messages_ok); + gtk_box_pack_start (GTK_BOX (dialog_action_area5), messages_ok, FALSE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (messages_ok, GTK_CAN_DEFAULT); + + gtk_signal_connect (GTK_OBJECT (intf_messages), "delete_event", + GTK_SIGNAL_FUNC (GtkMessagesDelete), + NULL); + gtk_signal_connect (GTK_OBJECT (messages_ok), "clicked", + GTK_SIGNAL_FUNC (GtkMessagesOk), + NULL); + + gtk_widget_grab_default (messages_ok); + return intf_messages; +} + diff --git a/modules/gui/gtk/gtk_interface.h b/modules/gui/gtk/gtk_interface.h new file mode 100644 index 0000000000..8dcbf9b6d4 --- /dev/null +++ b/modules/gui/gtk/gtk_interface.h @@ -0,0 +1,12 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +GtkWidget* create_intf_window (void); +GtkWidget* create_intf_popup (void); +GtkWidget* create_intf_about (void); +GtkWidget* create_intf_open (void); +GtkWidget* create_intf_file (void); +GtkWidget* create_intf_jump (void); +GtkWidget* create_intf_playlist (void); +GtkWidget* create_intf_messages (void); diff --git a/modules/gui/gtk/gtk_support.c b/modules/gui/gtk/gtk_support.c new file mode 100644 index 0000000000..987d9a93e5 --- /dev/null +++ b/modules/gui/gtk/gtk_support.c @@ -0,0 +1,162 @@ +/* + * DO NOT EDIT THIS FILE - it is generated by Glade. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include "gtk_support.h" + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* check_file_exists (const gchar *directory, + const gchar *filename); + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* create_dummy_pixmap (GtkWidget *widget); + +GtkWidget* +lookup_widget (GtkWidget *widget, + const gchar *widget_name) +{ + GtkWidget *parent, *found_widget; + + for (;;) + { + if (GTK_IS_MENU (widget)) + parent = gtk_menu_get_attach_widget (GTK_MENU (widget)); + else + parent = widget->parent; + if (parent == NULL) + break; + widget = parent; + } + + found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget), + widget_name); + if (!found_widget) + g_warning ("Widget not found: %s", widget_name); + return found_widget; +} + +/* This is a dummy pixmap we use when a pixmap can't be found. */ +static char *dummy_pixmap_xpm[] = { +/* columns rows colors chars-per-pixel */ +"1 1 1 1", +" c None", +/* pixels */ +" " +}; + +/* This is an internally used function to create pixmaps. */ +static GtkWidget* +create_dummy_pixmap (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &mask, + NULL, dummy_pixmap_xpm); + if (gdkpixmap == NULL) + g_error ("Couldn't create replacement pixmap."); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +static GList *pixmaps_directories = NULL; + +/* Use this function to set the directory containing installed pixmaps. */ +void +add_pixmap_directory (const gchar *directory) +{ + pixmaps_directories = g_list_prepend (pixmaps_directories, + g_strdup (directory)); +} + +/* This is an internally used function to create pixmaps. */ +GtkWidget* +create_pixmap (GtkWidget *widget, + const gchar *filename) +{ + gchar *found_filename = NULL; + GdkColormap *colormap; + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + GList *elem; + + if (!filename || !filename[0]) + return create_dummy_pixmap (widget); + + /* We first try any pixmaps directories set by the application. */ + elem = pixmaps_directories; + while (elem) + { + found_filename = check_file_exists ((gchar*)elem->data, filename); + if (found_filename) + break; + elem = elem->next; + } + + /* If we haven't found the pixmap, try the source directory. */ + if (!found_filename) + { + found_filename = check_file_exists ("pixmaps", filename); + } + + if (!found_filename) + { + g_warning (_("Couldn't find pixmap file: %s"), filename); + return create_dummy_pixmap (widget); + } + + colormap = gtk_widget_get_colormap (widget); + gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask, + NULL, found_filename); + if (gdkpixmap == NULL) + { + g_warning (_("Error loading pixmap file: %s"), found_filename); + g_free (found_filename); + return create_dummy_pixmap (widget); + } + g_free (found_filename); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + gdk_pixmap_unref (gdkpixmap); + gdk_bitmap_unref (mask); + return pixmap; +} + +/* This is an internally used function to check if a pixmap file exists. */ +static gchar* +check_file_exists (const gchar *directory, + const gchar *filename) +{ + gchar *full_filename; + struct stat s; + gint status; + + full_filename = (gchar*) g_malloc (strlen (directory) + 1 + + strlen (filename) + 1); + strcpy (full_filename, directory); + strcat (full_filename, G_DIR_SEPARATOR_S); + strcat (full_filename, filename); + + status = stat (full_filename, &s); + if (status == 0 && S_ISREG (s.st_mode)) + return full_filename; + g_free (full_filename); + return NULL; +} + diff --git a/modules/gui/gtk/gtk_support.h b/modules/gui/gtk/gtk_support.h new file mode 100644 index 0000000000..9439da3598 --- /dev/null +++ b/modules/gui/gtk/gtk_support.h @@ -0,0 +1,61 @@ +/* + * This file was created automatically by glade and fixed by bootstrap.sh + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* + * Standard gettext macros. + */ +#if defined( ENABLE_NLS ) && defined ( HAVE_GETTEXT ) +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + + +/* + * Public Functions. + */ + +/* + * This function returns a widget in a component created by Glade. + * Call it with the toplevel widget in the component (i.e. a window/dialog), + * or alternatively any widget in the component, and the name of the widget + * you want returned. + */ +GtkWidget* lookup_widget (GtkWidget *widget, + const gchar *widget_name); + +/* get_widget() is deprecated. Use lookup_widget instead. */ +#define get_widget lookup_widget + +/* Use this function to set the directory containing installed pixmaps. */ +void add_pixmap_directory (const gchar *directory); + + +/* + * Private Functions. + */ + +/* This is used to create the pixmaps in the interface. */ +GtkWidget* create_pixmap (GtkWidget *widget, + const gchar *filename); + diff --git a/modules/gui/gtk/menu.c b/modules/gui/gtk/menu.c new file mode 100644 index 0000000000..9b8ec74e4f --- /dev/null +++ b/modules/gui/gtk/menu.c @@ -0,0 +1,1015 @@ +/***************************************************************************** + * menu.c : functions to handle menu items. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: menu.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * Johan Bilien + * + * 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 /* off_t */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "playlist.h" +#include "common.h" + +/* + * Local Prototypes + */ +static gint GtkLanguageMenus( gpointer , GtkWidget *, es_descriptor_t *, gint, + void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) ); + +void GtkMenubarAudioToggle ( GtkCheckMenuItem *, gpointer ); +void GtkPopupAudioToggle ( GtkCheckMenuItem *, gpointer ); +void GtkMenubarSubtitleToggle( GtkCheckMenuItem *, gpointer ); +void GtkPopupSubtitleToggle ( GtkCheckMenuItem *, gpointer ); +static gint GtkTitleMenu( gpointer, GtkWidget *, + void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) ); +static gint GtkRadioMenu( intf_thread_t *, GtkWidget *, GSList *, + char *, int, int, int, + void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) ); + +gint GtkSetupMenus( intf_thread_t * p_intf ); + +/**************************************************************************** + * Gtk*Toggle: callbacks to toggle the value of a checkmenuitem + **************************************************************************** + * We need separate functions for menubar and popup here since we can't use + * user_data to transmit intf_* and we need to refresh the other menu. + ****************************************************************************/ + +#define GTKLANGTOGGLE( window, menu, type, callback, b_update ) \ + intf_thread_t * p_intf; \ + GtkWidget * p_menu; \ + es_descriptor_t * p_es; \ + \ + p_intf = GtkGetIntf( menuitem ); \ + \ + if( !p_intf->p_sys->b_update ) \ + { \ + p_menu = GTK_WIDGET( gtk_object_get_data( \ + GTK_OBJECT( p_intf->p_sys->window ), (menu) ) ); \ + p_es = (es_descriptor_t*)user_data; \ + \ + input_ToggleES( p_intf->p_sys->p_input, \ + p_es, menuitem->active ); \ + \ + p_intf->p_sys->b_update = menuitem->active; \ + \ + if( p_intf->p_sys->b_update ) \ + { \ + GtkLanguageMenus( p_intf, p_menu, p_es, type, callback ); \ + } \ + \ + p_intf->p_sys->b_update = 0; \ + } + +/* + * Audio + */ + +void GtkMenubarAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKLANGTOGGLE( p_popup, "popup_audio", AUDIO_ES, + GtkPopupAudioToggle, b_audio_update ); +} + +void GtkPopupAudioToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKLANGTOGGLE( p_window, "menubar_audio", AUDIO_ES, + GtkMenubarAudioToggle, b_audio_update ); +} + +/* + * Subtitles + */ + +void GtkMenubarSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKLANGTOGGLE( p_popup, "popup_subpictures", SPU_ES, + GtkPopupSubtitleToggle, b_spu_update ); +} + +void GtkPopupSubtitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKLANGTOGGLE( p_window, "menubar_subpictures", SPU_ES, + GtkMenubarSubtitleToggle, b_spu_update ); +} + +#undef GTKLANGTOGGLE + +/* + * Navigation + */ + +void GtkPopupNavigationToggle( GtkCheckMenuItem * menuitem, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( menuitem ); + + if( menuitem->active && + !p_intf->p_sys->b_title_update && + !p_intf->p_sys->b_chapter_update ) + { + input_area_t *p_area; + + gint i_title = DATA2TITLE( user_data ); + gint i_chapter = DATA2CHAPTER( user_data ); + + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if( p_area != p_intf->p_sys->p_input->stream.pp_areas[i_title] ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_title]; + p_intf->p_sys->b_title_update = 1; + } + + p_area->i_part = i_chapter; + + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + p_intf->p_sys->b_chapter_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +/* + * Program + */ +#define GTKPROGRAMTOGGLE( ) \ + intf_thread_t * p_intf = GtkGetIntf( menuitem ); \ + \ + if( menuitem->active && !p_intf->p_sys->b_program_update ) \ + { \ + u16 i_program_id = (ptrdiff_t)user_data; \ + \ + input_ChangeProgram( p_intf->p_sys->p_input, i_program_id ); \ + \ + p_intf->p_sys->b_program_update = 1; \ + \ + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); \ + GtkSetupMenus( p_intf ); \ + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); \ + \ + p_intf->p_sys->b_program_update = 0; \ + \ + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); \ + } + +void GtkMenubarProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKPROGRAMTOGGLE( ); +} + +void GtkPopupProgramToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + GTKPROGRAMTOGGLE( ); +} + +/* + * Title + */ + +void GtkMenubarTitleToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( menuitem ); + + if( menuitem->active && !p_intf->p_sys->b_title_update ) + { + gint i_title = (gint)((long)user_data); + input_ChangeArea( p_intf->p_sys->p_input, + p_intf->p_sys->p_input->stream.pp_areas[i_title] ); + + p_intf->p_sys->b_title_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkSetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + p_intf->p_sys->b_title_update = 0; + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + } +} + +/* + * Chapter + */ + +void GtkMenubarChapterToggle( GtkCheckMenuItem * menuitem, gpointer user_data ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + gint i_chapter; + GtkWidget * p_popup_menu; + + p_intf = GtkGetIntf( menuitem ); + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + i_chapter = (gint)((long)user_data); + + if( menuitem->active && !p_intf->p_sys->b_chapter_update ) + { + p_area->i_part = i_chapter; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + p_intf->p_sys->b_chapter_update = 1; + p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_popup ), "popup_navigation" ) ); + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + p_intf->p_sys->b_chapter_update = 0; + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + + +/**************************************************************************** + * Functions to generate menus + ****************************************************************************/ + +/***************************************************************************** + * GtkRadioMenu: update interactive menus of the interface + ***************************************************************************** + * Sets up menus with information from input + * Warning: since this function is designed to be called by management + * function, the interface lock has to be taken + *****************************************************************************/ +static gint GtkRadioMenu( intf_thread_t * p_intf, + GtkWidget * p_root, GSList * p_menu_group, + char * psz_item_name, + int i_start, int i_end, int i_selected, + void( *pf_toggle )( GtkCheckMenuItem *, gpointer ) ) +{ + char psz_name[ GTK_MENU_LABEL_SIZE ]; + GtkWidget * p_menu; + GtkWidget * p_submenu; + GtkWidget * p_item_group; + GtkWidget * p_item; + GtkWidget * p_item_selected; + GSList * p_group; + gint i_item; + + /* temporary hack to avoid blank menu when an open menu is removed */ + if( GTK_MENU_ITEM(p_root)->submenu != NULL ) + { + gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) ); + } + /* removes previous menu */ + gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) ); + gtk_widget_set_sensitive( p_root, FALSE ); + + p_item_group = NULL; + p_submenu = NULL; + p_item_selected = NULL; + p_group = p_menu_group; + + p_menu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf ); + + for( i_item = i_start ; i_item <= i_end ; i_item++ ) + { + /* we group chapters in packets of ten for small screens */ + if( ( i_item % 10 == i_start ) && ( i_end > 20 ) ) + { + if( i_item != i_start ) + { + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), + p_submenu ); + gtk_menu_append( GTK_MENU( p_menu ), p_item_group ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, + "%ss %d to %d", psz_item_name, i_item, i_item + 9 ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + p_item_group = gtk_menu_item_new_with_label( psz_name ); + gtk_widget_show( p_item_group ); + p_submenu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_submenu ), "p_intf", p_intf ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, "%s %d", + psz_item_name, i_item ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + + p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name ); + p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) ); + + if( i_selected == i_item ) + { + p_item_selected = p_item; + } + + gtk_widget_show( p_item ); + + /* setup signal hanling */ + gtk_signal_connect( GTK_OBJECT( p_item ), + "toggled", + GTK_SIGNAL_FUNC( pf_toggle ), + (gpointer)((long)(i_item)) ); + + if( i_end > 20 ) + { + gtk_menu_append( GTK_MENU( p_submenu ), p_item ); + } + else + { + gtk_menu_append( GTK_MENU( p_menu ), p_item ); + } + } + + if( i_end > 20 ) + { + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_item_group ), p_submenu ); + gtk_menu_append( GTK_MENU( p_menu ), p_item_group ); + } + + /* link the new menu to the title menu item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu ); + + /* toggle currently selected chapter + * We have to release the lock since input_ToggleES needs it */ + if( p_item_selected != NULL ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_selected ), + TRUE ); + } + + /* be sure that menu is sensitive, if there are several items */ + if( i_end > i_start ) + { + gtk_widget_set_sensitive( p_root, TRUE ); + } + + return TRUE; +} + +/***************************************************************************** + * GtkProgramMenu: update the programs menu of the interface + ***************************************************************************** + * Builds the program menu according to what have been found in the PAT + * by the input. Usefull for multi-programs streams such as DVB ones. + *****************************************************************************/ +static gint GtkProgramMenu( gpointer p_data, + GtkWidget * p_root, + pgrm_descriptor_t * p_pgrm, + void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) ) +{ + intf_thread_t * p_intf; + GtkWidget * p_menu; + GtkWidget * p_item; + GtkWidget * p_item_active; + GSList * p_group; + char psz_name[ GTK_MENU_LABEL_SIZE ]; + gint i; + + /* cast */ + p_intf = (intf_thread_t *)p_data; + + /* temporary hack to avoid blank menu when an open menu is removed */ + if( GTK_MENU_ITEM(p_root)->submenu != NULL ) + { + gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) ); + } + /* removes previous menu */ + gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) ); + gtk_widget_set_sensitive( p_root, FALSE ); + + p_group = NULL; + + /* menu container */ + p_menu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf ); + + p_item_active = NULL; + + /* create a set of program buttons and append them to the container */ + for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_pgrm_number ; i++ ) + { + snprintf( psz_name, GTK_MENU_LABEL_SIZE, "id %d", + p_intf->p_sys->p_input->stream.pp_programs[i]->i_number ); + psz_name[GTK_MENU_LABEL_SIZE-1] = '\0'; + + p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name ); + p_group = + gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) ); + + if( p_pgrm == p_intf->p_sys->p_input->stream.pp_programs[i] ) + { + /* don't lose p_item when we append into menu */ + p_item_active = p_item; + } + + gtk_widget_show( p_item ); + + /* setup signal hanling */ + gtk_signal_connect( GTK_OBJECT( p_item ), "toggled", + GTK_SIGNAL_FUNC( pf_toggle ), + (gpointer)(ptrdiff_t)( p_intf->p_sys->p_input-> + stream.pp_programs[i]->i_number ) ); + + gtk_menu_append( GTK_MENU( p_menu ), p_item ); + } + + /* link the new menu to the menubar item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu ); + + /* activation will call signals so we can only do it + * when submenu is attached to menu - to get intf_window + * We have to release the lock since input_ToggleES needs it */ + if( p_item_active != NULL ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ), + TRUE ); + } + + /* be sure that menu is sensitive if more than 1 program */ + if( p_intf->p_sys->p_input->stream.i_pgrm_number > 1 ) + { + gtk_widget_set_sensitive( p_root, TRUE ); + } + + return TRUE; +} + +/***************************************************************************** + * GtkLanguageMenus: update interactive menus of the interface + ***************************************************************************** + * Sets up menus with information from input: + * -languages + * -sub-pictures + * Warning: since this function is designed to be called by management + * function, the interface lock has to be taken + *****************************************************************************/ +static gint GtkLanguageMenus( gpointer p_data, + GtkWidget * p_root, + es_descriptor_t * p_es, + gint i_cat, + void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) ) +{ + intf_thread_t * p_intf; + GtkWidget * p_menu; + GtkWidget * p_separator; + GtkWidget * p_item; + GtkWidget * p_item_active; + GSList * p_group; + char psz_name[ GTK_MENU_LABEL_SIZE ]; + gint i_item; + gint i; + + p_intf = (intf_thread_t *)p_data; + + /* temporary hack to avoid blank menu when an open menu is removed */ + if( GTK_MENU_ITEM(p_root)->submenu != NULL ) + { + gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_root)->submenu ) ); + } + /* removes previous menu */ + gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_root ) ); + gtk_widget_set_sensitive( p_root, FALSE ); + + p_group = NULL; + + /* menu container */ + p_menu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_menu ), "p_intf", p_intf ); + + /* special case for "off" item */ + snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("None") ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + + p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name ); + p_group = gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) ); + + gtk_widget_show( p_item ); + + /* signal hanling for off */ + gtk_signal_connect( GTK_OBJECT( p_item ), "toggled", + GTK_SIGNAL_FUNC ( pf_toggle ), NULL ); + + gtk_menu_append( GTK_MENU( p_menu ), p_item ); + + p_separator = gtk_menu_item_new(); + gtk_widget_set_sensitive( p_separator, FALSE ); + gtk_widget_show( p_separator ); + gtk_menu_append( GTK_MENU( p_menu ), p_separator ); + + p_item_active = NULL; + i_item = 0; + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + +#define ES p_intf->p_sys->p_input->stream.pp_es[i] + /* create a set of language buttons and append them to the container */ + for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ ) + { + if( ( ES->i_cat == i_cat ) && + ( !ES->p_pgrm || + ES->p_pgrm == + p_intf->p_sys->p_input->stream.p_selected_program ) ) + { + i_item++; + strcpy( psz_name, + p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc ); + if( psz_name[0] == '\0' ) + { + snprintf( psz_name, GTK_MENU_LABEL_SIZE, + "Language %d", i_item ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + } + + p_item = gtk_radio_menu_item_new_with_label( p_group, psz_name ); + p_group = + gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_item ) ); + + if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] ) + { + /* don't lose p_item when we append into menu */ + p_item_active = p_item; + } + + gtk_widget_show( p_item ); + + /* setup signal hanling */ + gtk_signal_connect( GTK_OBJECT( p_item ), "toggled", + GTK_SIGNAL_FUNC( pf_toggle ), + (gpointer)( p_intf->p_sys->p_input->stream.pp_es[i] ) ); + + gtk_menu_append( GTK_MENU( p_menu ), p_item ); + } + } + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + /* link the new menu to the menubar item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu ); + + /* acitvation will call signals so we can only do it + * when submenu is attached to menu - to get intf_window + * We have to release the lock since input_ToggleES needs it */ + if( p_item_active != NULL ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ), + TRUE ); + } + + /* be sure that menu is sensitive if non empty */ + if( i_item > 0 ) + { + gtk_widget_set_sensitive( p_root, TRUE ); + } + + return TRUE; +} + +/***************************************************************************** + * GtkTitleMenu: sets menus for titles and chapters selection + ***************************************************************************** + * Generates two types of menus: + * -simple list of titles + * -cascaded lists of chapters for each title + *****************************************************************************/ +static gint GtkTitleMenu( gpointer p_data, + GtkWidget * p_navigation, + void(*pf_toggle )( GtkCheckMenuItem *, gpointer ) ) +{ + intf_thread_t * p_intf; + char psz_name[ GTK_MENU_LABEL_SIZE ]; + GtkWidget * p_title_menu; + GtkWidget * p_title_submenu; + GtkWidget * p_title_item; + GtkWidget * p_item_active; + GtkWidget * p_chapter_menu; + GtkWidget * p_chapter_submenu; + GtkWidget * p_title_menu_item; + GtkWidget * p_chapter_menu_item; + GtkWidget * p_item; + GSList * p_title_group; + GSList * p_chapter_group; + gint i_title; + gint i_chapter; + gint i_title_nb; + gint i_chapter_nb; + + /* cast */ + p_intf = (intf_thread_t*)p_data; + + /* temporary hack to avoid blank menu when an open menu is removed */ + if( GTK_MENU_ITEM(p_navigation)->submenu != NULL ) + { + gtk_menu_popdown( GTK_MENU( GTK_MENU_ITEM(p_navigation)->submenu ) ); + } + /* removes previous menu */ + gtk_menu_item_remove_submenu( GTK_MENU_ITEM( p_navigation ) ); + gtk_widget_set_sensitive( p_navigation, FALSE ); + + p_title_menu = gtk_menu_new(); + p_title_group = NULL; + p_title_submenu = NULL; + p_title_menu_item = NULL; + p_chapter_group = NULL; + p_chapter_submenu = NULL; + p_chapter_menu_item = NULL; + p_item_active = NULL; + i_title_nb = p_intf->p_sys->p_input->stream.i_area_nb; + + gtk_object_set_data( GTK_OBJECT( p_title_menu ), "p_intf", p_intf ); + + /* loop on titles */ + for( i_title = 0 ; i_title < i_title_nb ; i_title++ ) + { + /* we group titles in packets of ten for small screens */ + if( ( i_title % 10 == 0 ) && ( i_title_nb > 20 ) ) + { + if( i_title != 0 ) + { + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ), + p_title_submenu ); + gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, + "%d - %d", i_title, i_title + 9 ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + p_title_menu_item = gtk_menu_item_new_with_label( psz_name ); + gtk_widget_show( p_title_menu_item ); + p_title_submenu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_title_submenu ), + "p_intf", p_intf ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, _("Title %d (%d)"), i_title, + p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; +#if 0 + if( pf_toggle == on_menubar_title_toggle ) + { + p_title_item = gtk_radio_menu_item_new_with_label( p_title_group, + psz_name ); + p_title_group = + gtk_radio_menu_item_group( GTK_RADIO_MENU_ITEM( p_title_item ) ); + + if( p_intf->p_sys->p_input->stream.pp_areas[i_title] == + p_intf->p_sys->p_input->stream.p_selected_area ) + { + p_item_active = p_title_item; + } + + /* setup signal hanling */ + gtk_signal_connect( GTK_OBJECT( p_title_item ), + "toggled", + GTK_SIGNAL_FUNC( pf_toggle ), + (gpointer)(p_intf->p_sys->p_input->stream.pp_areas[i_title]) ); + + if( p_intf->p_sys->p_input->stream.i_area_nb > 1 ) + { + /* be sure that menu is sensitive */ + gtk_widget_set_sensitive( p_navigation, TRUE ); + } + } + else +#endif + { + p_title_item = gtk_menu_item_new_with_label( psz_name ); + +#if 1 + p_chapter_menu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_chapter_menu ), + "p_intf", p_intf ); + i_chapter_nb = + p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb; + + for( i_chapter = 0 ; i_chapter < i_chapter_nb ; i_chapter++ ) + { + /* we group chapters in packets of ten for small screens */ + if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) ) + { + if( i_chapter != 0 ) + { + gtk_menu_item_set_submenu( + GTK_MENU_ITEM( p_chapter_menu_item ), + p_chapter_submenu ); + gtk_menu_append( GTK_MENU( p_chapter_menu ), + p_chapter_menu_item ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, + "%d - %d", i_chapter + 1, i_chapter + 10 ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + p_chapter_menu_item = + gtk_menu_item_new_with_label( psz_name ); + gtk_widget_show( p_chapter_menu_item ); + p_chapter_submenu = gtk_menu_new(); + gtk_object_set_data( GTK_OBJECT( p_chapter_submenu ), + "p_intf", p_intf ); + } + + snprintf( psz_name, GTK_MENU_LABEL_SIZE, + _("Chapter %d"), i_chapter + 1 ); + psz_name[ GTK_MENU_LABEL_SIZE - 1 ] = '\0'; + + p_item = gtk_radio_menu_item_new_with_label( + p_chapter_group, psz_name ); + p_chapter_group = gtk_radio_menu_item_group( + GTK_RADIO_MENU_ITEM( p_item ) ); + gtk_widget_show( p_item ); + +#define p_area p_intf->p_sys->p_input->stream.pp_areas[i_title] + if( ( p_area == + p_intf->p_sys->p_input->stream.p_selected_area ) && + ( p_area->i_part == i_chapter + 1 ) ) + { + p_item_active = p_item; + } +#undef p_area + + /* setup signal hanling */ + gtk_signal_connect( GTK_OBJECT( p_item ), + "toggled", + GTK_SIGNAL_FUNC( pf_toggle ), + (gpointer)POS2DATA( i_title, i_chapter + 1) ); + + if( i_chapter_nb > 20 ) + { + gtk_menu_append( GTK_MENU( p_chapter_submenu ), p_item ); + } + else + { + gtk_menu_append( GTK_MENU( p_chapter_menu ), p_item ); + } + } + + if( i_chapter_nb > 20 ) + { + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_chapter_menu_item ), + p_chapter_submenu ); + gtk_menu_append( GTK_MENU( p_chapter_menu ), + p_chapter_menu_item ); + } + + /* link the new menu to the title menu item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_item ), + p_chapter_menu ); + + if( p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb > 1 ) + { + /* be sure that menu is sensitive */ + gtk_widget_set_sensitive( p_navigation, TRUE ); + } +#else + GtkRadioMenu( p_intf, p_title_item, p_chapter_group, _("Chapter"), + p_intf->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb, + 1, i_title * 100, + p_intf->p_sys->p_input->stream.p_selected_area->i_part + + p_intf->p_sys->p_input->stream.p_selected_area->i_id *100, + pf_toggle ); + +#endif + } + gtk_widget_show( p_title_item ); + + if( i_title_nb > 20 ) + { + gtk_menu_append( GTK_MENU( p_title_submenu ), p_title_item ); + } + else + { + gtk_menu_append( GTK_MENU( p_title_menu ), p_title_item ); + } + } + + if( i_title_nb > 20 ) + { + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_title_menu_item ), + p_title_submenu ); + gtk_menu_append( GTK_MENU( p_title_menu ), p_title_menu_item ); + } + + /* be sure that menu is sensitive */ + gtk_widget_set_sensitive( p_title_menu, TRUE ); + + /* link the new menu to the menubar item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_navigation ), p_title_menu ); + + /* Default selected chapter + * We have to release the lock since input_ToggleES needs it */ + if( p_item_active != NULL ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ), + TRUE ); + } +#if 0 + if( p_intf->p_sys->p_input->stream.i_area_nb > 1 ) + { + /* be sure that menu is sensitive */ + gtk_widget_set_sensitive( p_navigation, TRUE ); + } +#endif + + return TRUE; +} + +/***************************************************************************** + * GtkSetupMenus: function that generates title/chapter/audio/subpic + * menus with help from preceding functions + ***************************************************************************** + * Function called with the lock on stream + *****************************************************************************/ +gint GtkSetupMenus( intf_thread_t * p_intf ) +{ + es_descriptor_t * p_audio_es; + es_descriptor_t * p_spu_es; + GtkWidget * p_menubar_menu; + GtkWidget * p_popup_menu; + gint i; + + p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update; + p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + + if( p_intf->p_sys->b_program_update ) + { + pgrm_descriptor_t * p_pgrm; + + if( p_intf->p_sys->p_input->stream.p_new_program ) + { + p_pgrm = p_intf->p_sys->p_input->stream.p_new_program; + } + else + { + p_pgrm = p_intf->p_sys->p_input->stream.p_selected_program; + } + + p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "menubar_program" ) ); + GtkProgramMenu( p_intf, p_menubar_menu, p_pgrm, + GtkMenubarProgramToggle ); + + p_intf->p_sys->b_program_update = 1; + p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_popup ), "popup_program" ) ); + GtkProgramMenu( p_intf, p_popup_menu, p_pgrm, + GtkPopupProgramToggle ); + + p_intf->p_sys->b_program_update = 0; + } + + if( p_intf->p_sys->b_title_update ) + { + char psz_title[5]; + + p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "menubar_title" ) ); + GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0, + p_intf->p_sys->p_input->stream.i_area_nb - 1, + p_intf->p_sys->p_input->stream.p_selected_area->i_id, + GtkMenubarTitleToggle ); + + snprintf( psz_title, 4, "%d", + p_intf->p_sys->p_input->stream.p_selected_area->i_id ); + psz_title[ 4 ] = '\0'; + gtk_label_set_text( p_intf->p_sys->p_label_title, psz_title ); + + p_intf->p_sys->b_title_update = 0; + } + + if( p_intf->p_sys->b_chapter_update ) + { + char psz_chapter[5]; + + p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_popup ), "popup_navigation" ) ); + GtkTitleMenu( p_intf, p_popup_menu, GtkPopupNavigationToggle ); +#if 0 + GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Title"), 0, + p_intf->p_sys->p_input->stream.i_area_nb - 1, + p_intf->p_sys->p_input->stream.p_selected_area->i_id, + on_menubar_chapter_toggle ); +#endif + + p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "menubar_chapter" ) ); + + GtkRadioMenu( p_intf, p_menubar_menu, NULL, _("Chapter"), 1, + p_intf->p_sys->p_input->stream.p_selected_area->i_part_nb, + p_intf->p_sys->p_input->stream.p_selected_area->i_part, + GtkMenubarChapterToggle ); + + + snprintf( psz_chapter, 4, "%d", + p_intf->p_sys->p_input->stream.p_selected_area->i_part ); + psz_chapter[ 4 ] = '\0'; + gtk_label_set_text( p_intf->p_sys->p_label_chapter, psz_chapter ); + + p_intf->p_sys->i_part = + p_intf->p_sys->p_input->stream.p_selected_area->i_part; + + p_intf->p_sys->b_chapter_update = 0; + } + + /* look for selected ES */ + p_audio_es = NULL; + p_spu_es = NULL; + + for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_selected_es_number ; i++ ) + { + if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES ) + { + p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i]; + } + + if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES ) + { + p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i]; + } + } + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + /* audio menus */ + if( p_intf->p_sys->b_audio_update ) + { + /* find audio root menu */ + p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "menubar_audio" ) ); + + p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_popup ), "popup_audio" ) ); + + p_intf->p_sys->b_audio_update = 1; + GtkLanguageMenus( p_intf, p_menubar_menu, p_audio_es, AUDIO_ES, + GtkMenubarAudioToggle ); + p_intf->p_sys->b_audio_update = 1; + GtkLanguageMenus( p_intf, p_popup_menu, p_audio_es, AUDIO_ES, + GtkPopupAudioToggle ); + + p_intf->p_sys->b_audio_update = 0; + } + + /* sub picture menus */ + if( p_intf->p_sys->b_spu_update ) + { + /* find spu root menu */ + p_menubar_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_window ), "menubar_subpictures" ) ); + + p_popup_menu = GTK_WIDGET( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_popup ), "popup_subpictures" ) ); + + p_intf->p_sys->b_spu_update = 1; + GtkLanguageMenus( p_intf, p_menubar_menu, p_spu_es, SPU_ES, + GtkMenubarSubtitleToggle ); + p_intf->p_sys->b_spu_update = 1; + GtkLanguageMenus( p_intf, p_popup_menu, p_spu_es, SPU_ES, + GtkPopupSubtitleToggle ); + + p_intf->p_sys->b_spu_update = 0; + } + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + + return TRUE; +} + diff --git a/modules/gui/gtk/menu.h b/modules/gui/gtk/menu.h new file mode 100644 index 0000000000..2903459b51 --- /dev/null +++ b/modules/gui/gtk/menu.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * gtk_menu.h: prototypes for menu functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: menu.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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. + *****************************************************************************/ + +gint GtkSetupMenus( intf_thread_t * ); + +/***************************************************************************** + * String sizes + *****************************************************************************/ +#define GTK_MENU_LABEL_SIZE 64 + +/***************************************************************************** + * Convert user_data structures to title and chapter information + *****************************************************************************/ +#define DATA2TITLE( user_data ) ( (gint)((long)(user_data)) >> 16 ) +#define DATA2CHAPTER( user_data ) ( (gint)((long)(user_data)) & 0xffff ) +#define POS2DATA( title, chapter ) ( 0 + ( ((title) << 16) \ + | ((chapter) & 0xffff)) ) + diff --git a/modules/gui/gtk/modules.c b/modules/gui/gtk/modules.c new file mode 100644 index 0000000000..8ebadb4042 --- /dev/null +++ b/modules/gui/gtk/modules.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * gtk_modules.c : functions to build modules configuration boxes. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: modules.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 /* off_t */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "playlist.h" +#include "common.h" + +gboolean GtkModulesShow( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( widget ); + + if( !GTK_IS_WIDGET( p_intf->p_sys->p_modules ) ) + { +// p_intf->p_sys->p_modules = create_intf_modules(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_modules ), + "p_intf", p_intf ); + } + gtk_widget_show( p_intf->p_sys->p_modules ); + gdk_window_raise( p_intf->p_sys->p_modules->window ); + + return FALSE; +} + +void GtkModulesCancel( GtkButton * button, gpointer user_data ) +{ + intf_thread_t *p_intf = GtkGetIntf( button ); + + gtk_widget_hide( p_intf->p_sys->p_modules ); +} + diff --git a/modules/gui/gtk/modules.h b/modules/gui/gtk/modules.h new file mode 100644 index 0000000000..96eded90d4 --- /dev/null +++ b/modules/gui/gtk/modules.h @@ -0,0 +1,27 @@ +/***************************************************************************** + * gtk_modules.h: prototypes for modules functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: modules.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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. + *****************************************************************************/ + +gboolean GtkModulesShow ( GtkWidget *, gpointer ); +void GtkModulesCancel ( GtkButton * button, gpointer ); + diff --git a/modules/gui/gtk/open.c b/modules/gui/gtk/open.c new file mode 100644 index 0000000000..022d8f4648 --- /dev/null +++ b/modules/gui/gtk/open.c @@ -0,0 +1,535 @@ +/***************************************************************************** + * gtk_open.c : functions to handle file/disc/network open widgets. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: open.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 /* off_t */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "playlist.h" +#include "common.h" + +#include "netutils.h" + +static void GtkOpenShow( intf_thread_t *, int ); + +static void GtkFileOpenChanged ( GtkWidget *, gpointer ); +static void GtkDiscOpenChanged ( GtkWidget *, gpointer ); +static void GtkNetworkOpenChanged ( GtkWidget *, gpointer ); +static void GtkSatOpenChanged ( GtkWidget *, gpointer ); + +/***************************************************************************** + * File requester callbacks + ***************************************************************************** + * The following callbacks are related to the file requester. + *****************************************************************************/ +void GtkFileShow( GtkButton * button, gpointer user_data ) +{ + GtkWidget * p_file = create_intf_file(); + + gtk_object_set_data( GTK_OBJECT(p_file), "p_intf", GtkGetIntf( button ) ); + + gtk_widget_show( p_file ); + gdk_window_raise( p_file->window ); +} + +void GtkFileOk( GtkButton * button, gpointer user_data ) +{ + GtkWidget * p_file = gtk_widget_get_toplevel( GTK_WIDGET (button) ); + + char *psz_filename; + intf_thread_t * p_intf = GtkGetIntf( button ); + + /* add the new file to the dialog box */ + psz_filename = + gtk_file_selection_get_filename( GTK_FILE_SELECTION( p_file ) ); + gtk_entry_set_text( GTK_ENTRY( lookup_widget( p_intf->p_sys->p_open, + "entry_file" ) ), + psz_filename ); + gtk_widget_destroy( p_file ); +} + +void GtkFileCancel( GtkButton * button, gpointer user_data ) +{ + gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + +/***************************************************************************** + * Open file callbacks + ***************************************************************************** + * The following callbacks are related to the file tab. + *****************************************************************************/ +gboolean GtkFileOpenShow( GtkWidget *widget, + gpointer user_data ) +{ + GtkOpenShow( GtkGetIntf( widget ), 0 ); + + return TRUE; +} + +static void GtkFileOpenChanged( GtkWidget * button, gpointer user_data ) +{ + GString * p_target; + + p_target = g_string_new( "file://" ); + g_string_append( p_target, + gtk_entry_get_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_file" ) ) ) ); + gtk_entry_set_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_open" ) ), + p_target->str ); + g_string_free( p_target, TRUE ); +} + +/***************************************************************************** + * Open disc callbacks + ***************************************************************************** + * The following callbacks are related to the disc manager. + *****************************************************************************/ +gboolean GtkDiscOpenShow( GtkWidget *widget, + gpointer user_data) +{ + GtkOpenShow( GtkGetIntf( widget ), 1 ); + + return TRUE; +} + +void GtkDiscOpenDvd( GtkToggleButton * togglebutton, gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( togglebutton ); + char *psz_device; + + if( togglebutton->active + && (psz_device = config_GetPsz( p_intf, "dvd" )) ) + { + gtk_entry_set_text( + GTK_ENTRY( lookup_widget( GTK_WIDGET(togglebutton), + "disc_name" ) ), psz_device ); + free( psz_device ); + } +} + +void GtkDiscOpenVcd( GtkToggleButton * togglebutton, gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( togglebutton ); + char *psz_device; + + if( togglebutton->active + && (psz_device = config_GetPsz( p_intf, "vcd" )) ) + { + gtk_entry_set_text( + GTK_ENTRY( lookup_widget( GTK_WIDGET(togglebutton), + "disc_name" ) ), psz_device ); + free( psz_device ); + } +} + +static void GtkDiscOpenChanged( GtkWidget * button, gpointer user_data ) +{ + GString * p_target = g_string_new( "" ); + + if( GTK_TOGGLE_BUTTON( lookup_widget( GTK_WIDGET(button), + "disc_dvd" ) )->active ) + { + g_string_append( p_target, "dvd://" ); + } + else if( GTK_TOGGLE_BUTTON( lookup_widget( GTK_WIDGET(button), + "disc_vcd" ) )->active ) + { + g_string_append( p_target, "vcd://" ); + } + + g_string_append( p_target, + gtk_entry_get_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "disc_name" ) ) ) ); + g_string_sprintfa( p_target, "@%i,%i", + gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON( lookup_widget( + GTK_WIDGET(button), "disc_title" ) ) ), + gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON( lookup_widget( + GTK_WIDGET(button), "disc_chapter" ) ) ) ); + + gtk_entry_set_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_open" ) ), + p_target->str ); + g_string_free( p_target, TRUE ); +} + +/***************************************************************************** + * Network stream callbacks + ***************************************************************************** + * The following callbacks are related to the network stream manager. + *****************************************************************************/ +gboolean GtkNetworkOpenShow( GtkWidget *widget, + gpointer user_data ) +{ + GtkOpenShow( GtkGetIntf( widget ), 2 ); + + return TRUE; +} + +static void GtkNetworkOpenChanged( GtkWidget *button, gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + GString * p_target = g_string_new( "" ); + + unsigned int i_port; + vlc_bool_t b_channel; + + /* Manage channel server */ + b_channel = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( + lookup_widget( GTK_WIDGET(button), "network_channel" ) ) ); + config_PutInt( p_intf, "network-channel", b_channel ); + +#define SELECTED( s ) GTK_TOGGLE_BUTTON( lookup_widget( GTK_WIDGET(button), \ + (s) ) )->active + /* Check which option was chosen */ + if( SELECTED( "network_udp" ) ) + { + g_string_append( p_target, "udp://" ); + i_port = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( + lookup_widget( GTK_WIDGET(button), + "network_udp_port" ) ) ); + if( i_port != 1234 ) + { + g_string_sprintfa( p_target, "@:%i", i_port ); + } + } + else if( SELECTED( "network_multicast" ) ) + { + g_string_sprintfa( p_target, "udp://@%s", + gtk_entry_get_text( GTK_ENTRY( + lookup_widget( GTK_WIDGET(button), + "network_multicast_address" ) ) ) ); + i_port = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( + lookup_widget( GTK_WIDGET(button), + "network_multicast_port" ) ) ); + if( i_port != 1234 ) + { + g_string_sprintfa( p_target, ":%i", i_port ); + } + } + else if( SELECTED( "network_channel" ) ) + { + char * psz_channel; + unsigned int i_channel_port; + + if( p_intf->p_vlc->p_channel == NULL ) + { + network_ChannelCreate( p_intf ); + } + + psz_channel = gtk_entry_get_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "network_channel_address" ) ) ); + i_channel_port = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( + lookup_widget( GTK_WIDGET(button), "network_channel_port" ) ) ); + + config_PutPsz( p_intf, "channel-server", psz_channel ); + if( i_channel_port < 65536 ) + { + config_PutInt( p_intf, "channel-port", i_channel_port ); + } + + /* FIXME: we should use a playlist server instead */ + g_string_append( p_target, "udp://" ); + } + else if( SELECTED( "network_http" ) ) + { + g_string_sprintfa( p_target, "http://%s", + gtk_entry_get_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "network_http_url" ) ) ) ); + } + + gtk_entry_set_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_open" ) ), + p_target->str ); + g_string_free( p_target, TRUE ); +} + +void GtkNetworkOpenUDP( GtkToggleButton *togglebutton, + gpointer user_data ) +{ + GtkWidget * p_open; + + p_open = gtk_widget_get_toplevel( GTK_WIDGET (togglebutton) ); + + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_udp_port_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_udp_port" ), + gtk_toggle_button_get_active( togglebutton ) ); + + GtkNetworkOpenChanged( GTK_WIDGET( togglebutton ), user_data ); +} + +void GtkNetworkOpenMulticast( GtkToggleButton *togglebutton, + gpointer user_data ) +{ + GtkWidget * p_open; + + p_open = gtk_widget_get_toplevel( GTK_WIDGET (togglebutton) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_multicast_address_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_multicast_address_combo" ), + gtk_toggle_button_get_active( togglebutton ) ); + + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_multicast_port_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_multicast_port" ), + gtk_toggle_button_get_active( togglebutton ) ); + + GtkNetworkOpenChanged( GTK_WIDGET( togglebutton ), user_data ); +} + + +void GtkNetworkOpenChannel( GtkToggleButton *togglebutton, + gpointer user_data ) +{ + GtkWidget * p_open; + + p_open = gtk_widget_get_toplevel( GTK_WIDGET (togglebutton) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_channel_address_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_channel_address_combo" ), + gtk_toggle_button_get_active( togglebutton ) ); + + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_channel_port_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_channel_port" ), + gtk_toggle_button_get_active( togglebutton ) ); + + GtkNetworkOpenChanged( GTK_WIDGET( togglebutton ), user_data ); +} + +void GtkNetworkOpenHTTP( GtkToggleButton *togglebutton, + gpointer user_data ) +{ + GtkWidget * p_open; + + p_open = gtk_widget_get_toplevel( GTK_WIDGET (togglebutton) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_http_url_label" ), + gtk_toggle_button_get_active( togglebutton ) ); + gtk_widget_set_sensitive( gtk_object_get_data( GTK_OBJECT( p_open ), + "network_http_url" ), + gtk_toggle_button_get_active( togglebutton ) ); + + GtkNetworkOpenChanged( GTK_WIDGET( togglebutton ), user_data ); +} + +/***************************************************************************** + * Open satellite callbacks + ***************************************************************************** + * The following callbacks are related to the satellite card manager. + *****************************************************************************/ +gboolean GtkSatOpenShow( GtkWidget *widget, + gpointer user_data) +{ + GtkOpenShow( GtkGetIntf( widget ), 3 ); + + return TRUE; +} + +static void GtkSatOpenChanged( GtkWidget * button, gpointer user_data ) +{ + GString * p_target = g_string_new( "" ); + + g_string_sprintfa( p_target, "%s://%d,%d,%ld,%d", "satellite", + gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON( lookup_widget( + GTK_WIDGET(button), "sat_freq" ) ) ), + !GTK_TOGGLE_BUTTON( lookup_widget( GTK_WIDGET( button ), + "sat_pol_vert" ) )->active, + strtol( gtk_entry_get_text( GTK_ENTRY( GTK_COMBO( + lookup_widget( GTK_WIDGET( button ), "sat_fec" ) + )->entry ) ), NULL, 10 ), + gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON( lookup_widget( + GTK_WIDGET(button), "sat_srate" ) ) ) ); + + gtk_entry_set_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_open" ) ), + p_target->str ); + g_string_free( p_target, TRUE ); +} + +void +GtkSatOpenToggle (GtkToggleButton *togglebutton, + gpointer user_data) +{ + if( togglebutton->active ) + { + GtkSatOpenChanged( GTK_WIDGET( togglebutton ), user_data ); + } +} + +/****************************** + ******************************/ + +static void GtkOpenShow( intf_thread_t *p_intf, int i_page ) +{ + char *psz_var; + GtkWidget *p_notebook; + + /* If we have already created this window, do nothing */ + if( GTK_IS_WIDGET( p_intf->p_sys->p_open ) ) + { + goto setpage; + } + + p_intf->p_sys->p_open = create_intf_open(); + gtk_object_set_data( GTK_OBJECT( p_intf->p_sys->p_open ), + "p_intf", p_intf ); + + /* FileOpen stuff */ + psz_var = config_GetPsz( p_intf, "search-path" ); + if( psz_var ) + { + gtk_file_selection_set_filename( GTK_FILE_SELECTION( + p_intf->p_sys->p_open ), psz_var ); + free( psz_var ); + } + + /* Network stuff */ + gtk_spin_button_set_value( GTK_SPIN_BUTTON( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_open ), "network_udp_port" ) ), + config_GetInt( p_intf, "server-port" ) ); + + psz_var = config_GetPsz( p_intf, "channel-server" ); + if( psz_var ) + { + gtk_entry_set_text( GTK_ENTRY( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_open ), "network_channel_address" ) ), + psz_var ); + free( psz_var ); + } + + gtk_spin_button_set_value( GTK_SPIN_BUTTON( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_open ), "network_channel_port" ) ), + config_GetInt( p_intf, "channel-port" ) ); + + gtk_toggle_button_set_active( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_open ), "network_channel" ), + config_GetInt( p_intf, "network-channel" ) ); + + /* Set the right page */ +setpage: + p_notebook = lookup_widget( GTK_WIDGET( p_intf->p_sys->p_open ), + "open_notebook" ); + gtk_notebook_set_page( GTK_NOTEBOOK( p_notebook ), i_page ); + + gtk_widget_show( p_intf->p_sys->p_open ); + gdk_window_raise( p_intf->p_sys->p_open->window ); +} + +void GtkOpenOk( GtkButton * button, gpointer user_data ) +{ + /* Check what was pressed */ + intf_thread_t * p_intf = GtkGetIntf( button ); + playlist_t * p_playlist; + GtkCList * p_playlist_clist; + gchar * psz_target; + + /* Hide the dialog box */ + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); + + /* Update the playlist */ + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + psz_target = gtk_entry_get_text( GTK_ENTRY( lookup_widget( + GTK_WIDGET(button), "entry_open" ) ) ); + playlist_Add( p_playlist, (char*)psz_target, + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* catch the GTK CList */ + p_playlist_clist = GTK_CLIST( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + /* update the plugin display */ + GtkRebuildCList( p_playlist_clist, p_playlist ); + + vlc_object_release( p_playlist ); +} + +void GtkOpenCancel( GtkButton * button, gpointer user_data ) +{ + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + +void GtkOpenChanged( GtkWidget * button, gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( button ); + GtkWidget *p_notebook; + int i_page; + + p_notebook = lookup_widget( GTK_WIDGET( p_intf->p_sys->p_open ), + "open_notebook" ); + i_page = gtk_notebook_get_current_page( GTK_NOTEBOOK( p_notebook ) ); + + switch( i_page ) + { + case 0: + GtkFileOpenChanged( button, NULL ); + break; + case 1: + GtkDiscOpenChanged( button, NULL ); + break; + case 2: + GtkNetworkOpenChanged( button, NULL ); + break; + case 3: + GtkSatOpenChanged( button, NULL ); + break; + } +} + diff --git a/modules/gui/gtk/open.h b/modules/gui/gtk/open.h new file mode 100644 index 0000000000..aee469bdac --- /dev/null +++ b/modules/gui/gtk/open.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * gtk_open.h: prototypes for open functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: open.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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. + *****************************************************************************/ + +gboolean GtkFileOpenShow ( GtkWidget *, gpointer ); +void GtkFileOpenCancel ( GtkButton *, gpointer ); +void GtkFileOpenOk ( GtkButton *, gpointer ); + +gboolean GtkDiscOpenShow ( GtkWidget *, gpointer ); +void GtkDiscOpenDvd ( GtkToggleButton *, gpointer ); +void GtkDiscOpenVcd ( GtkToggleButton *, gpointer ); +void GtkDiscOpenOk ( GtkButton *, gpointer ); +void GtkDiscOpenCancel ( GtkButton *, gpointer ); + +gboolean GtkNetworkOpenShow ( GtkWidget *, gpointer ); +void GtkNetworkOpenOk ( GtkButton *, gpointer ); +void GtkNetworkOpenCancel ( GtkButton *, gpointer ); +void GtkNetworkOpenBroadcast( GtkToggleButton *, gpointer ); +void GtkNetworkOpenChannel ( GtkToggleButton *, gpointer ); + diff --git a/modules/gui/gtk/playlist.c b/modules/gui/gtk/playlist.c new file mode 100644 index 0000000000..2e422aa73c --- /dev/null +++ b/modules/gui/gtk/playlist.c @@ -0,0 +1,741 @@ +/***************************************************************************** + * gtk_playlist.c : Interface for the playlist dialog + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: playlist.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Pierre Baillet + * Stéphane Borel + * + * 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 +#include + +#include +#include + +#include /* for readdir and stat stuff */ + +#if (!defined( WIN32 ) || defined(__MINGW32__)) +/* Mingw has its own version of dirent */ +# include +#endif + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include "gtk_callbacks.h" +#include "gtk_interface.h" +#include "gtk_support.h" + +#include "playlist.h" +#include "common.h" + +/**************************************************************************** + * Local prototypes + ****************************************************************************/ +static void UrlDecode ( char * ); +static GList * GtkReadFiles ( intf_thread_t *, gchar * ); + +/**************************************************************************** + * Playlist window management + ****************************************************************************/ +gboolean GtkPlaylistShow( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + if( GTK_WIDGET_VISIBLE( p_intf->p_sys->p_playwin ) ) + { + gtk_widget_hide( p_intf->p_sys->p_playwin ); + } + else + { + GtkCList * p_clist; + + p_clist = GTK_CLIST( gtk_object_get_data( + GTK_OBJECT( p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + GtkRebuildCList( p_clist , p_playlist ); + gtk_widget_show( p_intf->p_sys->p_playwin ); + gdk_window_raise( p_intf->p_sys->p_playwin->window ); + } + + vlc_object_release( p_playlist ); + + return TRUE; +} + + +void GtkPlaylistOk( GtkButton * button, gpointer user_data ) +{ + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + + +void GtkPlaylistCancel( GtkButton * button, gpointer user_data ) +{ + gtk_widget_hide( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + + + +gboolean GtkPlaylistPrev( GtkWidget *widget, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); + + return TRUE; +} + + +gboolean GtkPlaylistNext( GtkWidget *widget, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); + + return TRUE; +} + +/**************************************************************************** + * Playlist core functions + ****************************************************************************/ +void GtkPlaylistAddUrl( GtkMenuItem * menuitem, gpointer user_data ) +{ + +} + + +void GtkPlaylistDeleteAll( GtkMenuItem * menuitem, gpointer user_data ) +{ + +} + + +void GtkPlaylistDeleteSelected( GtkMenuItem * menuitem, gpointer user_data ) +{ + /* user wants to delete a file in the queue */ + GList * p_selection; + GtkCList * p_clist; + + intf_thread_t * p_intf = GtkGetIntf( menuitem); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + /* lock the struct */ + vlc_mutex_lock( &p_intf->change_lock ); + + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + p_selection = p_clist->selection; + + if( g_list_length( p_selection ) ) + { + /* reverse-sort so that we can delete from the furthest + * to the closest item to delete... + */ + p_selection = g_list_sort( p_selection, GtkCompareItems ); + g_list_foreach( p_selection, GtkDeleteGListItem, p_playlist ); + /* rebuild the CList */ + GtkRebuildCList( p_clist, p_playlist ); + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + vlc_object_release( p_playlist ); +} + +void GtkPlaylistCrop( GtkMenuItem * menuitem, gpointer user_data ) +{ + /* Ok, this is a really small thing, but, hey, it works and + might be useful, who knows ? */ + GtkPlaylistInvert( menuitem, user_data ); + GtkPlaylistDeleteSelected( menuitem, user_data ); +} + +void GtkPlaylistInvert( GtkMenuItem * menuitem, gpointer user_data ) +{ + GtkCList * p_clist; + int * pi_selected; + int i_length; + int i_dummy; + + /* catch the thread back */ + intf_thread_t *p_intf = GtkGetIntf( menuitem ); + + /* lock the struct */ + vlc_mutex_lock( &p_intf->change_lock ); + + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + gtk_clist_freeze( p_clist ); + + /* have to copy the selection to an int * + I wasn't able to copy the g_list to another g_list + glib only does pointer copies, not real copies :( */ + + i_length = g_list_length( p_clist->selection ); + pi_selected = malloc( sizeof(int) * i_length ); + + for( i_dummy = 0 ; i_dummy < i_length ; i_dummy++ ) + { + pi_selected[i_dummy] = + GPOINTER_TO_UINT( g_list_nth_data( p_clist->selection, i_dummy ) ); + } + + gtk_clist_select_all( p_clist ); + + for( i_dummy = 0; i_dummy < i_length; i_dummy++ ) + { + gtk_clist_unselect_row( p_clist, pi_selected[i_dummy], 0 ); + } + + gtk_clist_thaw( p_clist ); + + vlc_mutex_unlock( &p_intf->change_lock ); + + free( pi_selected ); +} + +void GtkPlaylistSelect( GtkMenuItem * menuitem, gpointer user_data) +{ + +} + +gboolean GtkPlaylistEvent( GtkWidget * widget, + GdkEvent * event, + gpointer user_data) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + if( ( event->button ).type == GDK_2BUTTON_PRESS ) + { + GtkCList * p_clist; + gint i_row; + gint i_col; + + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + if( gtk_clist_get_selection_info( p_clist, (event->button).x, + (event->button).y, &i_row, &i_col ) == 1 ) + { + playlist_Goto( p_playlist, i_row ); + } + + vlc_object_release( p_playlist ); + return TRUE; + } + + vlc_object_release( p_playlist ); + return FALSE; +} + +void GtkPlaylistDragData( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *data, + guint info, + guint time, + gpointer user_data ) +{ + intf_thread_t * p_intf = GtkGetIntf( widget ); + GtkCList * p_clist; + gint i_row; + gint i_col; + + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + if( gtk_clist_get_selection_info( p_clist, x, y, &i_row, &i_col ) == 1 ) + { + /* we are dropping somewhere into the clist items */ + GtkDropDataReceived( p_intf, data, info, i_row - 1 ); + } + else + { + /* otherwise, put that at the end of the playlist */ + GtkDropDataReceived( p_intf, data, info, PLAYLIST_END ); + } +} + + +gboolean GtkPlaylistDragMotion( GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + guint time, + gpointer user_data ) +{ + GtkCList * p_clist; + gint i_row; + gint i_col; + int i_dummy; + GdkColor color; + + intf_thread_t * p_intf = GtkGetIntf( widget ); + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return FALSE; + } + + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + if( !GTK_WIDGET_TOPLEVEL(widget) ) + { + gdk_window_raise( p_intf->p_sys->p_playwin->window ); + } + + color.red = 0xffff; + color.blue = 0xffff; + color.green = 0xffff; + + gtk_clist_freeze( p_clist ); + + for( i_dummy = 0; i_dummy < p_clist->rows; i_dummy++) + { + gtk_clist_set_background( p_clist, i_dummy , &color ); + } + + color.red = 0; + color.blue = 0xf000; + color.green = 0x9000; + if( gtk_clist_get_selection_info( p_clist, x, y, &i_row, &i_col ) == 1 ) + { + gtk_clist_set_background ( p_clist, i_row - 1, &color ); + gtk_clist_set_background ( p_clist, i_row, &color ); + } + else + { + gtk_clist_set_background ( p_clist, p_clist->rows - 1, &color ); + } + + color.red = 0xffff; + color.blue = 0; + color.green = 0; + vlc_mutex_lock( &p_playlist->object_lock ); + gtk_clist_set_background( p_clist, p_playlist->i_index, &color ); + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + + gtk_clist_thaw( p_clist ); + + return TRUE; +} + +void GtkDropDataReceived( intf_thread_t * p_intf, + GtkSelectionData * p_data, guint i_info, int i_position) +{ + /* first we'll have to split against all the '\n' we have */ + gchar * p_protocol; + gchar * p_temp; + gchar * p_next; + gchar * p_string = p_data->data ; + GList * p_files = NULL; + GtkCList * p_clist; + + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + /* if this has been URLencoded, decode it + * + * Is it a good thing to do it in place ? + * probably not... + */ + if( i_info == DROP_ACCEPT_TEXT_URI_LIST ) + { + UrlDecode( p_string ); + } + + /* this cuts string into single file drops */ + /* this code was borrowed from xmms, thx guys :) */ + while( *p_string) + { + p_next = strchr( p_string, '\n' ); + if( p_next ) + { + if( *( p_next - 1 ) == '\r' ) + { + *( p_next - 1) = '\0'; + } + *p_next = '\0'; + } + + /* do we have a protocol or something ? */ + p_temp = strstr( p_string, ":" ); + if( p_temp != NULL && p_temp[0] != '\0' ) + { + char i_save; + + i_save = p_temp[0]; + p_temp[0] = '\0'; + p_protocol = strdup( p_string ); + p_temp[0] = i_save; + p_temp++; + + /* Allowed things are proto: or proto:// */ + if( p_temp[0] == '/' && p_temp[1] == '/') + { + /* eat two '/'s */ + p_temp += 2; + } + msg_Dbg( p_intf, "playlist protocol '%s', target '%s'", + p_protocol, p_temp ); + } + else + { + p_protocol = strdup( "" ); + } + + /* if it uses the file protocol we can do something, else, sorry :( + * I think this is a good choice for now, as we don't have any + * ability to read http:// or ftp:// files + * what about adding dvd:// to the list of authorized proto ? */ + + if( strcmp( p_protocol, "file:" ) == 0 ) + { + p_files = g_list_concat( p_files, + GtkReadFiles( p_intf, p_string ) ); + } + else + { + p_files = g_list_concat( p_files, + g_list_append( NULL, g_strdup( p_string ) ) ); + } + + /* free the malloc and go on... */ + free( p_protocol ); + + if( p_next == NULL ) + { + break; + } + p_string = p_next + 1; + } + + /* At this point, we have a nice big list maybe NULL */ + if( p_files != NULL ) + { + /* lock the interface */ + vlc_mutex_lock( &p_intf->change_lock ); + + msg_Dbg( p_intf, "adding %d elements", g_list_length( p_files ) ); + GtkAppendList( p_playlist, i_position, p_files ); + + /* get the CList and rebuild it. */ + p_clist = GTK_CLIST( lookup_widget( p_intf->p_sys->p_playwin, + "playlist_clist" ) ); + GtkRebuildCList( p_clist , p_playlist ); + + /* unlock the interface */ + vlc_mutex_unlock( &p_intf->change_lock ); + } + + vlc_object_release( p_playlist ); +} + + +void GtkDeleteGListItem( gpointer data, gpointer param ) +{ + int i_cur_row = (long)data; + playlist_t * p_playlist = param; + + playlist_Delete( p_playlist, i_cur_row ); +} + + +gint GtkCompareItems( gconstpointer a, gconstpointer b ) +{ + return b - a; +} + + +/* check a file (string) against supposed valid extension */ +int GtkHasValidExtension( gchar * psz_filename ) +{ + char * ppsz_ext[6] = { "mpg", "mpeg", "vob", "mp2", "ts", "ps" }; + int i_ext = 6; + int i_dummy; + + gchar * psz_ext = strrchr( psz_filename, '.' ) + sizeof( char ); + + for( i_dummy = 0 ; i_dummy < i_ext ; i_dummy++ ) + { + if( strcmp( psz_ext, ppsz_ext[i_dummy] ) == 0 ) + { + return 1; + } + } + + return 0; +} + +/* recursive function: descend into folders and build a list of + * valid filenames */ +static GList * GtkReadFiles( intf_thread_t * p_intf, gchar * psz_fsname ) +{ + struct stat statbuf; + GList * p_current = NULL; + + /* get the attributes of this file */ + stat( psz_fsname, &statbuf ); + + /* is it a regular file ? */ + if( S_ISREG( statbuf.st_mode ) ) + { + if( GtkHasValidExtension( psz_fsname ) ) + { + msg_Dbg( p_intf, "%s is a valid file, stacking on the playlist", + psz_fsname ); + return g_list_append( NULL, g_strdup( psz_fsname ) ); + } + else + { + return NULL; + } + } + /* is it a directory (should we check for symlinks ?) */ + else if( S_ISDIR( statbuf.st_mode ) ) + { + /* have to cd into this dir */ + DIR * p_current_dir = opendir( psz_fsname ); + struct dirent * p_dir_content; + + msg_Dbg( p_intf, "%s is a folder", psz_fsname ); + + if( p_current_dir == NULL ) + { + /* something went bad, get out of here ! */ + return p_current; + } + p_dir_content = readdir( p_current_dir ); + + /* while we still have entries in the directory */ + while( p_dir_content != NULL ) + { + /* if it is "." or "..", forget it */ + if( ( strcmp( p_dir_content->d_name, "." ) != 0 ) && + ( strcmp( p_dir_content->d_name, ".." ) != 0 ) ) + { + /* else build the new directory by adding + fsname "/" and the current entry name + (kludgy :() + */ + char * psz_newfs = malloc ( 2 + strlen( psz_fsname ) + + strlen( p_dir_content->d_name ) * sizeof(char) ); + strcpy( psz_newfs, psz_fsname ); + strcpy( psz_newfs + strlen( psz_fsname ) + 1, + p_dir_content->d_name ); + psz_newfs[strlen( psz_fsname )] = '/'; + + p_current = g_list_concat( p_current, + GtkReadFiles( p_intf, psz_newfs ) ); + + g_free( psz_newfs ); + } + p_dir_content = readdir( p_current_dir ); + } + return p_current; + } + return NULL; +} + +/* add items in a playlist + * when i_pos==-1 add to the end of the list... + */ +int GtkAppendList( playlist_t * p_playlist, int i_pos, GList * p_list ) +{ + guint i_dummy; + guint i_length; + + i_length = g_list_length( p_list ); + + for( i_dummy = 0; i_dummy < i_length ; i_dummy++ ) + { + playlist_Add( p_playlist, + /* ok; this is a really nasty trick to insert + the item where they are suppose to go but, hey + this works :P (btw, you are really nasty too) */ + g_list_nth_data( p_list, i_dummy ), + i_dummy == 0 ? PLAYLIST_INSERT | PLAYLIST_GO : PLAYLIST_INSERT, + i_pos == PLAYLIST_END ? PLAYLIST_END : ( i_pos + i_dummy ) ); + } + + return 0; +} + +/* statis timeouted function */ +void GtkPlayListManage( intf_thread_t * p_intf ) +{ + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + GtkCList * p_clist; + + if( p_playlist == NULL ) + { + return; + } + + /* this thing really sucks for now :( */ + + /* TODO speak more with src/playlist/playlist.c */ + if( GTK_IS_WIDGET( p_intf->p_sys->p_playwin ) ) + { + p_clist = GTK_CLIST( gtk_object_get_data( GTK_OBJECT( + p_intf->p_sys->p_playwin ), "playlist_clist" ) ); + + vlc_mutex_lock( &p_playlist->object_lock ); + + if( p_intf->p_sys->i_playing != p_playlist->i_index ) + { + GdkColor color; + + color.red = 0xffff; + color.blue = 0; + color.green = 0; + + gtk_clist_set_background( p_clist, p_playlist->i_index, &color ); + + if( p_intf->p_sys->i_playing != -1 ) + { + color.red = 0xffff; + color.blue = 0xffff; + color.green = 0xffff; + gtk_clist_set_background( p_clist, p_intf->p_sys->i_playing, + &color); + } + p_intf->p_sys->i_playing = p_playlist->i_index; + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + } + + vlc_object_release( p_playlist ); +} + +void GtkRebuildCList( GtkCList * p_clist, playlist_t * p_playlist ) +{ + int i_dummy; + gchar * ppsz_text[2]; + GdkColor red; + red.red = 65535; + red.blue = 0; + red.green = 0; + + gtk_clist_freeze( p_clist ); + gtk_clist_clear( p_clist ); + + vlc_mutex_lock( &p_playlist->object_lock ); + for( i_dummy = p_playlist->i_size ; i_dummy-- ; ) + { + ppsz_text[0] = p_playlist->pp_items[i_dummy]->psz_name; + ppsz_text[1] = "no info"; + gtk_clist_insert( p_clist, 0, ppsz_text ); + } + vlc_mutex_unlock( &p_playlist->object_lock ); + + gtk_clist_set_background( p_clist, p_playlist->i_index, &red); + gtk_clist_thaw( p_clist ); +} + +/* URL-decode a file: URL path, return NULL if it's not what we expect */ +static void UrlDecode( char *encoded_path ) +{ + char *tmp = NULL, *cur = NULL, *ext = NULL; + int realchar; + + if( !encoded_path || *encoded_path == '\0' ) + { + return; + } + + cur = encoded_path ; + + tmp = calloc(strlen(encoded_path) + 1, sizeof(char) ); + + while ( ( ext = strchr(cur, '%') ) != NULL) + { + strncat(tmp, cur, (ext - cur) / sizeof(char)); + ext++; + + if (!sscanf(ext, "%2x", &realchar)) + { + free(tmp); + return; + } + + tmp[strlen(tmp)] = (char)realchar; + + cur = ext + 2; + } + + strcat(tmp, cur); + strcpy(encoded_path,tmp); +} + diff --git a/modules/gui/gtk/playlist.h b/modules/gui/gtk/playlist.h new file mode 100644 index 0000000000..1ec460b4a5 --- /dev/null +++ b/modules/gui/gtk/playlist.h @@ -0,0 +1,52 @@ +/***************************************************************************** + * gtk_playlist.h : Playlist functions for the Gtk plugin. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: playlist.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Pierre Baillet + * Stéphane Borel + * + * 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 GtkPlaylistDeleteAll ( GtkMenuItem *, gpointer ); +void GtkPlaylistDeleteSelected( GtkMenuItem *, gpointer ); +void GtkPlaylistCrop ( GtkMenuItem *, gpointer ); +void GtkPlaylistInvert ( GtkMenuItem *, gpointer ); +void GtkPlaylistSelect ( GtkMenuItem *, gpointer ); +void GtkPlaylistOk ( GtkButton *, gpointer ); +void GtkPlaylistCancel ( GtkButton *, gpointer ); +void GtkPlaylistAddUrl ( GtkMenuItem *, gpointer ); + +gint GtkCompareItems ( gconstpointer, gconstpointer ); +int GtkHasValidExtension ( gchar * ); + +gboolean GtkPlaylistShow ( GtkWidget *, gpointer ); +gboolean GtkPlaylistPrev ( GtkWidget *, gpointer ); +gboolean GtkPlaylistNext ( GtkWidget *, gpointer ); +gboolean GtkPlaylistDragMotion( GtkWidget *, GdkDragContext *, + gint, gint, guint, gpointer ); +gboolean GtkPlaylistEvent ( GtkWidget *, GdkEvent *, gpointer ); +void GtkPlaylistDragData ( GtkWidget *, GdkDragContext *, + gint, gint, GtkSelectionData *, + guint, guint, gpointer ); +void GtkDeleteGListItem ( gpointer, gpointer ); + +void GtkDropDataReceived ( intf_thread_t *, GtkSelectionData *, guint, int ); +int GtkAppendList ( playlist_t *, int, GList * ); +void GtkRebuildCList ( GtkCList *, playlist_t * ); +void GtkPlayListManage ( intf_thread_t * ); + diff --git a/modules/gui/gtk/preferences.c b/modules/gui/gtk/preferences.c new file mode 100644 index 0000000000..11e58a892b --- /dev/null +++ b/modules/gui/gtk/preferences.c @@ -0,0 +1,947 @@ +/***************************************************************************** + * gtk_preferences.c: functions to handle the preferences dialog box. + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: preferences.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * Loïc Minier + * + * 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: Our main job is to build a nice interface from the modules config + * structure. Once this is done, we need to track each change made by the + * user to the data contained in this interface so that when/if he decides to + * apply his changes we can quickly commit them into the modules config + * structure. (for this last task we use a GHashTable to accumulate the + * changes. To commit them, we then just have to circle through it ) + * + *****************************************************************************/ +#include /* off_t */ +#include + +#include +#include + +#ifdef MODULE_NAME_IS_gnome +# include +#else +# include +#endif + +#include + +#include "gtk_support.h" + +#include "common.h" +#include "preferences.h" + +/* local functions */ +static void GtkCreateConfigDialog( char *, intf_thread_t * ); + +static void GtkConfigOk ( GtkButton *, gpointer ); +static void GtkConfigApply ( GtkButton *, gpointer ); +static void GtkConfigCancel ( GtkButton *, gpointer ); +static void GtkConfigSave ( GtkButton *, gpointer ); + +static void GtkConfigDialogDestroyed ( GtkObject *, gpointer ); + +static void GtkStringChanged ( GtkEditable *, gpointer ); +static void GtkIntChanged ( GtkEditable *, gpointer ); +static void GtkFloatChanged ( GtkEditable *, gpointer ); +static void GtkBoolChanged ( GtkToggleButton *, gpointer ); + +static void GtkFreeHashTable ( GtkObject *object ); +static void GtkFreeHashValue ( gpointer, gpointer, gpointer ); +static gboolean GtkSaveHashValue ( gpointer, gpointer, gpointer ); + +static void GtkModuleConfigure ( GtkButton *, gpointer ); +static void GtkModuleSelected ( GtkButton *, gpointer ); +static void GtkModuleHighlighted ( GtkCList *, int, int, GdkEventButton *, + gpointer ); + +/**************************************************************************** + * Callback for menuitems: display configuration interface window + ****************************************************************************/ +void GtkPreferencesShow( GtkMenuItem * menuitem, gpointer user_data ) +{ + intf_thread_t * p_intf; + + p_intf = GtkGetIntf( menuitem ); + + GtkCreateConfigDialog( "main", p_intf ); +} + +/**************************************************************************** + * GtkCreateConfigDialog: dynamically creates the configuration dialog + * box from all the configuration data provided by the selected module. + ****************************************************************************/ + +/* create a new tooltipped area */ +#define TOOLTIP( text ) \ + /* create an event box to catch some events */ \ + item_event_box = gtk_event_box_new(); \ + /* add a tooltip on mouseover */ \ + gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, \ + item_event_box, text, "" ); \ + gtk_container_set_border_width( GTK_CONTAINER(item_event_box), 4 ); + +/* draws a right aligned label in side of a widget */ +#define LABEL_AND_WIDGET( label_text, widget, tooltip ) \ + gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 ); \ + item_align = gtk_alignment_new( 1, .5, 0, 0 ); \ + item_label = gtk_label_new( label_text ); \ + gtk_container_add( GTK_CONTAINER(item_align), item_label ); \ + gtk_table_attach_defaults( GTK_TABLE(category_table), item_align, \ + 0, 1, rows - 1, rows ); \ + item_align = gtk_alignment_new( 0, .5, .5, 0 ); \ + gtk_container_add( GTK_CONTAINER(item_align), widget ); \ + TOOLTIP(tooltip) \ + gtk_container_add( GTK_CONTAINER(item_event_box), item_align ); \ + gtk_table_attach_defaults( GTK_TABLE(category_table), item_event_box, \ + 1, 2, rows - 1, rows ); + +static void GtkCreateConfigDialog( char *psz_module_name, + intf_thread_t *p_intf ) +{ + module_t *p_module, *p_module_bis; + module_config_t *p_item; + + guint rows = 0; + + GHashTable *config_hash_table; + + GtkWidget *item_event_box; + + GtkWidget *config_dialog; + GtkWidget *config_dialog_vbox; + GtkWidget *config_notebook; + + GtkWidget *category_table = NULL; + GtkWidget *category_label = NULL; + +#ifndef MODULE_NAME_IS_gnome + GtkWidget *dialog_action_area; +#endif + + GtkWidget *ok_button; + GtkWidget *apply_button; + GtkWidget *save_button; + GtkWidget *cancel_button; + + GtkWidget *item_align; + GtkWidget *item_frame; + GtkWidget *item_hbox; + GtkWidget *item_label; + GtkWidget *item_vbox; + GtkWidget *item_combo; + GtkWidget *string_entry; + GtkWidget *integer_spinbutton; + GtkWidget *float_spinbutton; + GtkObject *item_adj; + GtkWidget *bool_checkbutton; + GtkWidget *module_clist; + GtkWidget *module_config_button; + GtkWidget *module_select_button; + + gint category_max_height; + + /* Check if the dialog box is already opened because we don't want to + * duplicate identical dialog windows. */ + config_dialog = (GtkWidget *)gtk_object_get_data( + GTK_OBJECT(p_intf->p_sys->p_window), psz_module_name ); + if( config_dialog ) + { + /* Yeah it was open */ + gtk_widget_grab_focus( config_dialog ); + return; + } + + + /* Look for the selected module */ + for( p_module = p_intf->p_vlc->p_module_bank->first ; p_module != NULL ; + p_module = p_module->next ) + { + + if( psz_module_name + && !strcmp( psz_module_name, p_module->psz_object_name ) ) + { + break; + } + } + if( !p_module ) return; + + /* We found it, now we can start building its configuration interface */ + /* Create the configuration dialog box */ + +#ifdef MODULE_NAME_IS_gnome + config_dialog = gnome_dialog_new( p_module->psz_longname, NULL ); + config_dialog_vbox = GNOME_DIALOG(config_dialog)->vbox; +#else + config_dialog = gtk_dialog_new(); + gtk_window_set_title( GTK_WINDOW(config_dialog), p_module->psz_longname ); + config_dialog_vbox = GTK_DIALOG(config_dialog)->vbox; +#endif + + gtk_object_set_data( GTK_OBJECT(config_dialog), "p_intf", p_intf ); + + category_max_height = config_GetInt( p_intf, MODULE_STRING "-prefs-maxh" ); + + gtk_window_set_policy( GTK_WINDOW(config_dialog), TRUE, TRUE, FALSE ); + gtk_container_set_border_width( GTK_CONTAINER(config_dialog_vbox), 0 ); + + /* Create our config hash table and associate it with the dialog box */ + config_hash_table = g_hash_table_new( NULL, NULL ); + gtk_object_set_data( GTK_OBJECT(config_dialog), + "config_hash_table", config_hash_table ); + + /* Create notebook */ + config_notebook = gtk_notebook_new(); + gtk_notebook_set_scrollable( GTK_NOTEBOOK(config_notebook), TRUE ); + gtk_container_add( GTK_CONTAINER(config_dialog_vbox), config_notebook ); + + /* Enumerate config options and add corresponding config boxes */ + p_item = p_module->p_config; + do + { + switch( p_item->i_type ) + { + + case CONFIG_HINT_CATEGORY: + case CONFIG_HINT_END: + + /* + * Before we start building the interface for the new category, we + * must close/finish the previous one we were generating. + */ + if( category_table ) + { + GtkWidget *_scrolled_window; + GtkWidget *_viewport; + GtkWidget *_vbox; + GtkRequisition _requisition; + + /* create a vbox to deal with EXPAND/FILL issues in the + * notebook page, and pack it with the previously generated + * category_table */ + _vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER(_vbox), 4 ); + gtk_box_pack_start( GTK_BOX(_vbox), category_table, + FALSE, FALSE, 0 ); + + /* create a new scrolled window that will contain all of the + * above. */ + _scrolled_window = gtk_scrolled_window_new( NULL, NULL ); + gtk_scrolled_window_set_policy( + GTK_SCROLLED_WINDOW(_scrolled_window), GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC ); + /* add scrolled window as a notebook page */ + gtk_notebook_append_page( GTK_NOTEBOOK(config_notebook), + _scrolled_window, category_label ); + /* pack the vbox into the scrolled window */ + _viewport = gtk_viewport_new( NULL, NULL ); + gtk_viewport_set_shadow_type( GTK_VIEWPORT(_viewport), + GTK_SHADOW_NONE ); + gtk_container_add( GTK_CONTAINER(_viewport), _vbox ); + gtk_container_add( GTK_CONTAINER(_scrolled_window), + _viewport ); + + /* set the size of the scrolled window to the size of the + * child widget */ + gtk_widget_show_all( _vbox ); + gtk_widget_size_request( _vbox, &_requisition ); + if( _requisition.height > category_max_height ) + gtk_widget_set_usize( _scrolled_window, -1, + category_max_height ); + else + gtk_widget_set_usize( _scrolled_window, -1, + _requisition.height ); + + } + + /* + * Now we can start taking care of the new category + */ + + if( p_item->i_type == CONFIG_HINT_CATEGORY ) + { + /* create a new table for right-left alignment of children */ + category_table = gtk_table_new( 0, 0, FALSE ); + gtk_table_set_col_spacings( GTK_TABLE(category_table), 4 ); + rows = 0; + + /* create a new category label */ + category_label = gtk_label_new( p_item->psz_text ); + } + + break; + + case CONFIG_ITEM_MODULE: + + item_frame = gtk_frame_new( p_item->psz_text ); + + gtk_table_resize( GTK_TABLE(category_table), ++rows, 2 ); + gtk_table_attach_defaults( GTK_TABLE(category_table), item_frame, + 0, 2, rows - 1, rows ); + + item_vbox = gtk_vbox_new( FALSE, 4 ); + gtk_container_add( GTK_CONTAINER(item_frame), item_vbox ); + + /* create a new clist widget */ + { + gchar * titles[] = { _("Name"), _("Description") }; + + module_clist = gtk_clist_new_with_titles( 2, titles ); + } + gtk_object_set_data( GTK_OBJECT(module_clist), "p_intf", p_intf ); + gtk_clist_column_titles_passive( GTK_CLIST(module_clist) ); + gtk_clist_set_selection_mode( GTK_CLIST(module_clist), + GTK_SELECTION_SINGLE); + gtk_container_add( GTK_CONTAINER(item_vbox), module_clist ); + + /* build a list of available modules */ + { + gchar * entry[2]; + char * psz_capability; + + for( p_module_bis = p_intf->p_vlc->p_module_bank->first ; + p_module_bis != NULL ; + p_module_bis = p_module_bis->next ) + { +#if 0 /* FIXME */ + for( psz_capability = p_module_bis->pp_capabilities[0] ; + *psz_capability ; + psz_capability++ ) + { + if( !strcmp( psz_capability, p_item->psz_type ) ) + { + entry[0] = p_module_bis->psz_object_name; + entry[1] = p_module_bis->psz_longname; + gtk_clist_append( GTK_CLIST(module_clist), entry ); + break; + } + } +#endif + } + } + + gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist), + 0, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(module_clist), + 1, TRUE ); + + /* connect signals to the modules list */ + gtk_signal_connect( GTK_OBJECT(module_clist), "select_row", + GTK_SIGNAL_FUNC(GtkModuleHighlighted), + NULL ); + + /* hbox holding the "select" and "configure" buttons */ + item_hbox = gtk_hbox_new( FALSE, 4 ); + gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox); + + /* add configure button */ + module_config_button = + gtk_button_new_with_label( _("Configure") ); + gtk_widget_set_sensitive( module_config_button, FALSE ); + gtk_container_add( GTK_CONTAINER(item_hbox), + module_config_button ); + gtk_object_set_data( GTK_OBJECT(module_config_button), + "p_intf", p_intf ); + gtk_object_set_data( GTK_OBJECT(module_clist), + "config_button", module_config_button ); + + /* add select button */ + module_select_button = + gtk_button_new_with_label( _("Select") ); + gtk_container_add( GTK_CONTAINER(item_hbox), + module_select_button ); + /* add a tooltip on mouseover */ + gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, + module_select_button, + p_item->psz_longtext, "" ); + + /* hbox holding the "selected" label and text input */ + item_hbox = gtk_hbox_new( FALSE, 4 ); + gtk_container_add( GTK_CONTAINER(item_vbox), item_hbox); + /* add new label */ + item_label = gtk_label_new( _("Selected:") ); + gtk_container_add( GTK_CONTAINER(item_hbox), item_label ); + + /* add input box with default value */ + string_entry = gtk_entry_new(); + gtk_object_set_data( GTK_OBJECT(module_clist), + "module_entry", string_entry ); + gtk_container_add( GTK_CONTAINER(item_hbox), string_entry ); + vlc_mutex_lock( p_item->p_lock ); + gtk_entry_set_text( GTK_ENTRY(string_entry), + p_item->psz_value ? p_item->psz_value : "" ); + vlc_mutex_unlock( p_item->p_lock ); + /* add a tooltip on mouseover */ + gtk_tooltips_set_tip( p_intf->p_sys->p_tooltips, + string_entry, p_item->psz_longtext, "" ); + + /* connect signals to the buttons */ + gtk_signal_connect( GTK_OBJECT(module_config_button), "clicked", + GTK_SIGNAL_FUNC(GtkModuleConfigure), + (gpointer)module_clist ); + gtk_signal_connect( GTK_OBJECT(module_select_button), "clicked", + GTK_SIGNAL_FUNC(GtkModuleSelected), + (gpointer)module_clist ); + + /* connect signal to track changes in the text box */ + gtk_object_set_data( GTK_OBJECT(string_entry), "config_option", + p_item->psz_name ); + gtk_signal_connect( GTK_OBJECT(string_entry), "changed", + GTK_SIGNAL_FUNC(GtkStringChanged), + (gpointer)config_dialog ); + break; + + case CONFIG_ITEM_STRING: + case CONFIG_ITEM_FILE: + + if( !p_item->ppsz_list ) + { + /* add input box with default value */ + item_combo = string_entry = gtk_entry_new(); + } + else + { + /* add combo box with default value */ + GList *items = NULL; + int i; + + for( i=0; p_item->ppsz_list[i]; i++ ) + items = g_list_append( items, p_item->ppsz_list[i] ); + + item_combo = gtk_combo_new(); + string_entry = GTK_COMBO(item_combo)->entry; + gtk_combo_set_popdown_strings( GTK_COMBO(item_combo), + items ); + + } + + vlc_mutex_lock( p_item->p_lock ); + gtk_entry_set_text( GTK_ENTRY(string_entry), + p_item->psz_value ? p_item->psz_value : "" ); + vlc_mutex_unlock( p_item->p_lock ); + + /* connect signal to track changes in the text box */ + gtk_object_set_data( GTK_OBJECT(string_entry), "config_option", + p_item->psz_name ); + gtk_signal_connect( GTK_OBJECT(string_entry), "changed", + GTK_SIGNAL_FUNC(GtkStringChanged), + (gpointer)config_dialog ); + + LABEL_AND_WIDGET( p_item->psz_text, + item_combo, p_item->psz_longtext ); + break; + + case CONFIG_ITEM_INTEGER: + + /* add input box with default value */ + item_adj = gtk_adjustment_new( p_item->i_value, + -1, 99999, 1, 10, 10 ); + integer_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj), + 1, 0 ); + + /* connect signal to track changes in the spinbutton value */ + gtk_object_set_data( GTK_OBJECT(integer_spinbutton), + "config_option", p_item->psz_name ); + gtk_signal_connect( GTK_OBJECT(integer_spinbutton), "changed", + GTK_SIGNAL_FUNC(GtkIntChanged), + (gpointer)config_dialog ); + + LABEL_AND_WIDGET( p_item->psz_text, + integer_spinbutton, p_item->psz_longtext ); + break; + + case CONFIG_ITEM_FLOAT: + + /* add input box with default value */ + item_adj = gtk_adjustment_new( p_item->f_value, + 0, 99999, 0.01, 10, 10 ); + float_spinbutton = gtk_spin_button_new( GTK_ADJUSTMENT(item_adj), + 0.01, 2 ); + + /* connect signal to track changes in the spinbutton value */ + gtk_object_set_data( GTK_OBJECT(float_spinbutton), + "config_option", p_item->psz_name ); + gtk_signal_connect( GTK_OBJECT(float_spinbutton), "changed", + GTK_SIGNAL_FUNC(GtkFloatChanged), + (gpointer)config_dialog ); + + LABEL_AND_WIDGET( p_item->psz_text, + float_spinbutton, p_item->psz_longtext ); + break; + + case CONFIG_ITEM_BOOL: + + /* add check button */ + bool_checkbutton = gtk_check_button_new(); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(bool_checkbutton), + p_item->i_value ); + + /* connect signal to track changes in the button state */ + gtk_object_set_data( GTK_OBJECT(bool_checkbutton), "config_option", + p_item->psz_name ); + gtk_signal_connect( GTK_OBJECT(bool_checkbutton), "toggled", + GTK_SIGNAL_FUNC(GtkBoolChanged), + (gpointer)config_dialog ); + + LABEL_AND_WIDGET( p_item->psz_text, + bool_checkbutton, p_item->psz_longtext ); + break; + + } + + } + while( p_item->i_type != CONFIG_HINT_END && p_item++ ); + +#ifndef MODULE_NAME_IS_gnome + /* Now let's add the action buttons at the bottom of the page */ + dialog_action_area = GTK_DIALOG(config_dialog)->action_area; + gtk_container_set_border_width( GTK_CONTAINER(dialog_action_area), 4 ); + + /* add a new table for the config option */ + item_hbox = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox, + TRUE, FALSE, 0 ); + item_hbox = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_end( GTK_BOX(dialog_action_area), item_hbox, + TRUE, FALSE, 0 ); +#endif + + /* Create the OK button */ +#ifdef MODULE_NAME_IS_gnome + gnome_dialog_append_button( GNOME_DIALOG(config_dialog), + GNOME_STOCK_BUTTON_OK ); + ok_button = + GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data); + + gnome_dialog_append_button( GNOME_DIALOG(config_dialog), + GNOME_STOCK_BUTTON_APPLY ); + apply_button = + GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data); + + gnome_dialog_append_button_with_pixmap( + GNOME_DIALOG(config_dialog), _("Save"), GNOME_STOCK_PIXMAP_SAVE ); + save_button = + GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data); + + gnome_dialog_append_button( GNOME_DIALOG(config_dialog), + GNOME_STOCK_BUTTON_CANCEL ); + cancel_button = + GTK_WIDGET(g_list_last(GNOME_DIALOG(config_dialog)->buttons)->data); +#else + ok_button = gtk_button_new_with_label( _("OK") ); + gtk_box_pack_start( GTK_BOX(dialog_action_area), ok_button, + TRUE, TRUE, 0 ); + + apply_button = gtk_button_new_with_label( _("Apply") ); + gtk_box_pack_start( GTK_BOX(dialog_action_area), apply_button, + TRUE, TRUE, 0 ); + + save_button = gtk_button_new_with_label( _("Save") ); + gtk_box_pack_start( GTK_BOX(dialog_action_area), save_button, + TRUE, TRUE, 0 ); + + cancel_button = gtk_button_new_with_label( _("Cancel") ); + gtk_box_pack_start( GTK_BOX(dialog_action_area), cancel_button, + TRUE, TRUE, 0 ); +#endif + + gtk_signal_connect( GTK_OBJECT(ok_button), "clicked", + GTK_SIGNAL_FUNC(GtkConfigOk), + config_dialog ); + gtk_widget_set_sensitive( apply_button, FALSE ); + gtk_object_set_data( GTK_OBJECT(config_dialog), "apply_button", + apply_button ); + gtk_signal_connect( GTK_OBJECT(apply_button), "clicked", + GTK_SIGNAL_FUNC(GtkConfigApply), + config_dialog ); + gtk_signal_connect( GTK_OBJECT(save_button), "clicked", + GTK_SIGNAL_FUNC(GtkConfigSave), + config_dialog ); + gtk_signal_connect( GTK_OBJECT(cancel_button), "clicked", + GTK_SIGNAL_FUNC(GtkConfigCancel), + config_dialog ); + + + + /* Ok, job done successfully. Let's keep a reference to the dialog box */ + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), + psz_module_name, config_dialog ); + gtk_object_set_data( GTK_OBJECT(config_dialog), "psz_module_name", + psz_module_name ); + + /* we want this ref to be destroyed if the object is destroyed */ + gtk_signal_connect( GTK_OBJECT(config_dialog), "destroy", + GTK_SIGNAL_FUNC(GtkConfigDialogDestroyed), + (gpointer)p_intf ); + + gtk_widget_show_all( config_dialog ); +} + +#undef LABEL_AND_WIDGET +#undef TOOLTIP + +/**************************************************************************** + * GtkConfigApply: store the changes to the config inside the modules + * configuration structure and clear the hash table. + ****************************************************************************/ +void GtkConfigApply( GtkButton * button, gpointer user_data ) +{ + intf_thread_t *p_intf; + GHashTable *hash_table; + GtkWidget *apply_button; + + hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data), + "config_hash_table" ); + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data), + "p_intf" ); + g_hash_table_foreach_remove( hash_table, GtkSaveHashValue, (void*)p_intf ); + + /* change the highlight status of the Apply button */ + apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "apply_button" ); + gtk_widget_set_sensitive( apply_button, FALSE ); +} + +void GtkConfigOk( GtkButton * button, gpointer user_data ) +{ + GtkConfigApply( button, user_data ); + gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + + +void GtkConfigCancel( GtkButton * button, gpointer user_data ) +{ + gtk_widget_destroy( gtk_widget_get_toplevel( GTK_WIDGET (button) ) ); +} + +void GtkConfigSave( GtkButton * button, gpointer user_data ) +{ + intf_thread_t *p_intf; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(user_data), + "p_intf" ); + GtkConfigApply( button, user_data ); + config_SaveConfigFile( p_intf, NULL ); +} + +/**************************************************************************** + * GtkModuleHighlighted: display module description when an entry is selected + * in the clist, and activate the configure button if necessary. + ****************************************************************************/ +void GtkModuleHighlighted( GtkCList *module_clist, int row, int column, + GdkEventButton *event, gpointer user_data ) +{ + intf_thread_t *p_intf; + GtkWidget *config_button; + module_t *p_module; + char *psz_name; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(module_clist), + "p_intf" ); + + if( gtk_clist_get_text( GTK_CLIST(module_clist), row, 0, &psz_name ) ) + { + /* look for module 'psz_name' */ + for( p_module = p_intf->p_vlc->p_module_bank->first ; + p_module != NULL ; + p_module = p_module->next ) + { + if( !strcmp( p_module->psz_object_name, psz_name ) ) + { + gtk_object_set_data( GTK_OBJECT(module_clist), + "module_highlighted", p_module ); + config_button = gtk_object_get_data( GTK_OBJECT(module_clist), + "config_button" ); + if( p_module->i_config_items ) + gtk_widget_set_sensitive( config_button, TRUE ); + else + gtk_widget_set_sensitive( config_button, FALSE ); + + break; + } + } + + } +} + +/**************************************************************************** + * GtkModuleConfigure: display module configuration dialog box. + ****************************************************************************/ +void GtkModuleConfigure( GtkButton *button, gpointer user_data ) +{ + module_t *p_module; + intf_thread_t *p_intf; + + p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data), + "module_highlighted" ); + + if( !p_module ) return; + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button), + "p_intf" ); + GtkCreateConfigDialog( p_module->psz_object_name, (gpointer)p_intf ); + +} + +/**************************************************************************** + * GtkModuleSelected: select module. + ****************************************************************************/ +void GtkModuleSelected( GtkButton *button, gpointer user_data ) +{ + module_t *p_module; + GtkWidget *widget; + + p_module = (module_t *)gtk_object_get_data( GTK_OBJECT(user_data), + "module_highlighted" ); + widget = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "module_entry" ); + if( !p_module ) return; + + gtk_entry_set_text( GTK_ENTRY(widget), p_module->psz_object_name ); + +} + +/**************************************************************************** + * GtkStringChanged: signal called when the user changes a string value. + ****************************************************************************/ +static void GtkStringChanged( GtkEditable *editable, gpointer user_data ) +{ + intf_thread_t *p_intf; + module_config_t *p_config; + GHashTable *hash_table; + GtkWidget *apply_button; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable), + "p_intf" ); + hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data), + "config_hash_table" ); + /* free old p_config */ + p_config = (module_config_t *)g_hash_table_lookup( hash_table, + (gpointer)editable ); + if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf ); + + p_config = malloc( sizeof(module_config_t) ); + p_config->i_type = CONFIG_ITEM_STRING; + p_config->psz_value = gtk_editable_get_chars( editable, 0, -1 ); + p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable), + "config_option" ); + + g_hash_table_insert( hash_table, (gpointer)editable, + (gpointer)p_config ); + + /* change the highlight status of the Apply button */ + apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "apply_button" ); + gtk_widget_set_sensitive( apply_button, TRUE ); +} + +/**************************************************************************** + * GtkIntChanged: signal called when the user changes an integer value. + ****************************************************************************/ +static void GtkIntChanged( GtkEditable *editable, gpointer user_data ) +{ + intf_thread_t *p_intf; + module_config_t *p_config; + GHashTable *hash_table; + GtkWidget *apply_button; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable), + "p_intf" ); + gtk_spin_button_update( GTK_SPIN_BUTTON(editable) ); + + hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data), + "config_hash_table" ); + + /* free old p_config */ + p_config = (module_config_t *)g_hash_table_lookup( hash_table, + (gpointer)editable ); + if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf ); + + p_config = malloc( sizeof(module_config_t) ); + p_config->i_type = CONFIG_ITEM_INTEGER; + p_config->i_value = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(editable) ); + p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable), + "config_option" ); + + g_hash_table_insert( hash_table, (gpointer)editable, + (gpointer)p_config ); + + /* change the highlight status of the Apply button */ + apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "apply_button" ); + gtk_widget_set_sensitive( apply_button, TRUE ); +} + +/**************************************************************************** + * GtkFloatChanged: signal called when the user changes a float value. + ****************************************************************************/ +static void GtkFloatChanged( GtkEditable *editable, gpointer user_data ) +{ + intf_thread_t *p_intf; + module_config_t *p_config; + GHashTable *hash_table; + GtkWidget *apply_button; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(editable), + "p_intf" ); + gtk_spin_button_update( GTK_SPIN_BUTTON(editable) ); + + hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data), + "config_hash_table" ); + + /* free old p_config */ + p_config = (module_config_t *)g_hash_table_lookup( hash_table, + (gpointer)editable ); + if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf ); + + p_config = malloc( sizeof(module_config_t) ); + p_config->i_type = CONFIG_ITEM_FLOAT; + p_config->f_value = gtk_spin_button_get_value_as_float( + GTK_SPIN_BUTTON(editable) ); + p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable), + "config_option" ); + + g_hash_table_insert( hash_table, (gpointer)editable, + (gpointer)p_config ); + + /* change the highlight status of the Apply button */ + apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "apply_button" ); + gtk_widget_set_sensitive( apply_button, TRUE ); +} + +/**************************************************************************** + * GtkBoolChanged: signal called when the user changes a bool value. + ****************************************************************************/ +static void GtkBoolChanged( GtkToggleButton *button, gpointer user_data ) +{ + intf_thread_t *p_intf; + module_config_t *p_config; + GHashTable *hash_table; + GtkWidget *apply_button; + + p_intf = (intf_thread_t *)gtk_object_get_data( GTK_OBJECT(button), + "p_intf" ); + hash_table = (GHashTable *)gtk_object_get_data( GTK_OBJECT(user_data), + "config_hash_table" ); + + /* free old p_config */ + p_config = (module_config_t *)g_hash_table_lookup( hash_table, + (gpointer)button ); + if( p_config ) GtkFreeHashValue( NULL, (gpointer)p_config, (void *)p_intf ); + + p_config = malloc( sizeof(module_config_t) ); + p_config->i_type = CONFIG_ITEM_BOOL; + p_config->i_value = gtk_toggle_button_get_active( button ); + p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(button), + "config_option" ); + + g_hash_table_insert( hash_table, (gpointer)button, + (gpointer)p_config ); + + /* change the highlight status of the Apply button */ + apply_button = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(user_data), + "apply_button" ); + gtk_widget_set_sensitive( apply_button, TRUE ); +} + +/**************************************************************************** + * GtkFreeHashTable: signal called when the config hash table is destroyed. + ****************************************************************************/ +static void GtkFreeHashTable( GtkObject *object ) +{ + GHashTable *hash_table = (GHashTable *)gtk_object_get_data( object, + "config_hash_table" ); + intf_thread_t *p_intf = (intf_thread_t *)gtk_object_get_data( object, + "p_intf" ); + + g_hash_table_foreach( hash_table, GtkFreeHashValue, (void *)p_intf ); + g_hash_table_destroy( hash_table ); +} + +/**************************************************************************** + * GtkFreeHashValue: signal called when an element of the config hash table + * is destroyed. + ****************************************************************************/ +static void GtkFreeHashValue( gpointer key, gpointer value, gpointer user_data) +{ + module_config_t * p_config = (module_config_t *)value; + + if( p_config->i_type == CONFIG_ITEM_STRING ) + if( p_config->psz_value ) g_free( p_config->psz_value ); + free( p_config ); +} + +/**************************************************************************** + * GtkSaveHashValue: callback used when enumerating the hash table in + * GtkConfigApply(). + ****************************************************************************/ +static gboolean GtkSaveHashValue( gpointer key, gpointer value, + gpointer user_data ) +{ + intf_thread_t * p_intf = (intf_thread_t *)user_data; + module_config_t * p_config = (module_config_t *)value; + + switch( p_config->i_type ) + { + + case CONFIG_ITEM_STRING: + case CONFIG_ITEM_FILE: + case CONFIG_ITEM_MODULE: + config_PutPsz( p_intf, p_config->psz_name, + *p_config->psz_value ? p_config->psz_value : NULL ); + break; + case CONFIG_ITEM_INTEGER: + case CONFIG_ITEM_BOOL: + config_PutInt( p_intf, p_config->psz_name, p_config->i_value ); + break; + case CONFIG_ITEM_FLOAT: + config_PutFloat( p_intf, p_config->psz_name, p_config->f_value ); + break; + } + + /* free the hash value we allocated */ + if( p_config->i_type == CONFIG_ITEM_STRING ) + g_free( p_config->psz_value ); + free( p_config ); + + /* return TRUE so glib will free the hash entry */ + return TRUE; +} + +/**************************************************************************** + * GtkConfigDialogDestroyed: callback triggered when the config dialog box is + * destroyed. + ****************************************************************************/ +static void GtkConfigDialogDestroyed( GtkObject *object, gpointer user_data ) +{ + intf_thread_t *p_intf = (intf_thread_t *)user_data; + char *psz_module_name; + + psz_module_name = gtk_object_get_data( object, "psz_module_name" ); + + /* remove the ref to the dialog box */ + gtk_object_set_data( GTK_OBJECT(p_intf->p_sys->p_window), + psz_module_name, NULL ); + + GtkFreeHashTable( object ); +} diff --git a/modules/gui/gtk/preferences.h b/modules/gui/gtk/preferences.h new file mode 100644 index 0000000000..8a03a3338b --- /dev/null +++ b/modules/gui/gtk/preferences.h @@ -0,0 +1,25 @@ +/***************************************************************************** + * gtk_control.h: prototypes for control functions + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: preferences.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * Stéphane Borel + * + * 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 GtkPreferencesShow( GtkMenuItem *, gpointer ); diff --git a/modules/gui/kde/.cvsignore b/modules/gui/kde/.cvsignore new file mode 100644 index 0000000000..e1108c686c --- /dev/null +++ b/modules/gui/kde/.cvsignore @@ -0,0 +1,5 @@ +.dep +*.lo +*.o.* +*.lo.* +*.moc.* diff --git a/modules/gui/kde/Makefile b/modules/gui/kde/Makefile new file mode 100644 index 0000000000..701f9e2edc --- /dev/null +++ b/modules/gui/kde/Makefile @@ -0,0 +1,6 @@ +MOC_SOURCES = interface.moc.cpp slider.moc.cpp disc.moc.cpp net.moc.cpp menu.moc.cpp preferences.moc.cpp pluginsbox.moc.cpp QConfigItem.moc.cpp + +kde_SOURCES = kde.cpp interface.cpp slider.cpp disc.cpp net.cpp menu.cpp preferences.cpp pluginsbox.cpp QConfigItem.cpp $(MOC_SOURCES) + +$(MOC_SOURCES): %.moc.cpp: %.h + $(MOC) $< -o $@ diff --git a/modules/gui/kde/QConfigItem.cpp b/modules/gui/kde/QConfigItem.cpp new file mode 100644 index 0000000000..aad1f3ce2b --- /dev/null +++ b/modules/gui/kde/QConfigItem.cpp @@ -0,0 +1,67 @@ +#include "QConfigItem.h" +#include +QConfigItem::QConfigItem(QObject *parent, QString name, int iType, int i_val) : + QObject(parent, name) +{ + type = iType; + iVal = i_val; +} + +QConfigItem::QConfigItem(QObject *parent, QString name, int iType, float f_val) : + QObject(parent, name) +{ + type = iType; + fVal = f_val; +} + +QConfigItem::QConfigItem(QObject *parent, QString name, int iType, QString s_val) : + QObject(parent, name) +{ + type = iType; + sVal = s_val; +} + +QConfigItem::~QConfigItem() +{ + ; +} + +int QConfigItem::getType() +{ + return type; +} + +int QConfigItem::iValue() +{ + return iVal; +} + +float QConfigItem::fValue() +{ + return fVal; +} + +QString QConfigItem::sValue() +{ + return sVal; +} + +void QConfigItem::setValue(int val) +{ + iVal = val; +} + +void QConfigItem::setValue(float val) +{ + fVal = val; +} + +void QConfigItem::setValue(double val) +{ + fVal = (float)val; +} + +void QConfigItem::setValue(const QString &val) +{ + sVal = val; +} diff --git a/modules/gui/kde/QConfigItem.h b/modules/gui/kde/QConfigItem.h new file mode 100644 index 0000000000..4a2e7fedee --- /dev/null +++ b/modules/gui/kde/QConfigItem.h @@ -0,0 +1,34 @@ +#ifndef _KCONFIGITEM_H_ +#define _KCONFIGITEM_H_ +#include +#include +/* + A class to handle the information for one configuration item. +*/ + +class QConfigItem : public QObject +{ + Q_OBJECT + public: + QConfigItem(QObject *parent, QString name, int iType, int i_val); + QConfigItem(QObject *parent, QString name, int iType, float f_val); + QConfigItem(QObject *parent, QString name, int iType, QString s_val); + ~QConfigItem(); + + int getType(); + float fValue(); + int iValue(); + QString sValue(); + + public slots: + void setValue(int val); + void setValue(float val); + void setValue(double val); + void setValue(const QString &val); + + private: + int iVal, type; + float fVal; + QString sVal; +}; +#endif diff --git a/modules/gui/kde/common.h b/modules/gui/kde/common.h new file mode 100644 index 0000000000..67ec336062 --- /dev/null +++ b/modules/gui/kde/common.h @@ -0,0 +1,20 @@ +/*************************************************************************** + common.h - description + ------------------- + begin : Mon Apr 9 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#ifndef _INTF_PLUGIN_H_ +#define _INTF_PLUGIN_H_ + +#include +#include +#include +#include + +#include +#include + +#endif /* _INTF_PLUGIN_H_ */ diff --git a/modules/gui/kde/disc.cpp b/modules/gui/kde/disc.cpp new file mode 100644 index 0000000000..dd89336449 --- /dev/null +++ b/modules/gui/kde/disc.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + disc.cpp - description + ------------------- + begin : Sat Apr 7 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#include "disc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KDiskDialog::KDiskDialog( QWidget *parent, const char *name ) + :KDialogBase( parent, name, true, QString::null, + Ok|Cancel, Ok, true ) +{ + QVBox *pageVBox = makeVBoxMainWidget(); + + QHBox *deviceSelectHBox = new QHBox( pageVBox ); + deviceSelectHBox->setSpacing( 5 ); + fButtonGroup = new QVButtonGroup( "Disk type", deviceSelectHBox ); + fDVDButton = new QRadioButton( "DVD", fButtonGroup); + fDVDButton->setChecked( true ); + fVCDButton = new QRadioButton( "VCD", fButtonGroup); + fVCDButton->setEnabled( false ); + + QVGroupBox *startVBox = new QVGroupBox( "Starting position", deviceSelectHBox ); + + QHBox *titleHBox = new QHBox( startVBox ); + new QLabel( "Title ", titleHBox ); + fTitle = new QSpinBox( titleHBox ); + QHBox *chapterHBox = new QHBox( startVBox ); + new QLabel( "Chapter ", chapterHBox ); + fChapter = new QSpinBox( chapterHBox ); + + QHBox *deviceNameHBox = new QHBox( pageVBox ); + new QLabel( "Device name ", deviceNameHBox ); + fLineEdit = new KLineEdit( "/dev/dvd", deviceNameHBox ); +} + +KDiskDialog::~KDiskDialog() +{ +} + +QString KDiskDialog::type() const +{ + if ( fDVDButton->isChecked() ) + { + return ( QString("dvd") ); + } + else + { + return ( QString("vcd") ); + } +} + +QString KDiskDialog::device() const +{ + return ( fLineEdit->text() ); +} + +int KDiskDialog::title() const +{ + return ( fTitle->value() ); +} + +int KDiskDialog::chapter() const +{ + return ( fChapter->value() ); +} diff --git a/modules/gui/kde/disc.h b/modules/gui/kde/disc.h new file mode 100644 index 0000000000..86e6d9616e --- /dev/null +++ b/modules/gui/kde/disc.h @@ -0,0 +1,47 @@ +/*************************************************************************** + disc.h - description + ------------------- + begin : Sat Apr 7 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#ifndef KDE_DISC_H +#define KDE_DISC_H + +#include +#include + +class QVButtonGroup; +class QRadioButton; +class QSpinBox; +class KLineEdit; + +/** + *@author andres + */ + +class KDiskDialog : public KDialogBase +{ + Q_OBJECT + public: + KDiskDialog( QWidget *parent=0, const char *name=0 ); + ~KDiskDialog(); + + QString type() const; + QString device() const; + int title() const; + int chapter() const; + + private: + + QVButtonGroup *fButtonGroup; + QRadioButton *fDVDButton; + QRadioButton *fVCDButton; + QSpinBox *fTitle; + QSpinBox *fChapter; + KLineEdit *fLineEdit; + +}; + +#endif diff --git a/modules/gui/kde/interface.cpp b/modules/gui/kde/interface.cpp new file mode 100644 index 0000000000..12b9cf64d6 --- /dev/null +++ b/modules/gui/kde/interface.cpp @@ -0,0 +1,466 @@ +/*************************************************************************** + interface.cpp - description + ------------------- + begin : Sun Mar 25 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#include "disc.h" +#include "interface.h" +#include "net.h" +#include "menu.h" +#include "slider.h" +#include "preferences.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ID_STATUS_MSG 1 +#define ID_DATE 2 +#define ID_STREAM_SOURCE 3 + +KInterface::KInterface( intf_thread_t *p_intf, QWidget *parent, + const char *name ) : KMainWindow(parent,name) +{ + setAcceptDrops(true); + + this->p_intf = p_intf; + + fDiskDialog = new KDiskDialog( this ); + fNetDialog = new KNetDialog( this ); + fTitleMenu = new KTitleMenu( p_intf, this ); + + fSlider = new KVLCSlider( QSlider::Horizontal, this ); + fSlider->setMaxValue(10000); + connect( fSlider, SIGNAL( userChanged( int ) ), this, SLOT( slotSliderMoved( int ) ) ); + connect( fSlider, SIGNAL( valueChanged( int ) ), this, SLOT( slotSliderChanged( int ) ) ); + setCentralWidget(fSlider); + + fTimer = new QTimer( this ); + connect( fTimer, SIGNAL( timeout() ), this, SLOT( slotManage() ) ); + fTimer->start( 100 ); + + resize( 400, 30 ); + + /////////////////////////////////////////////////////////////////// + // call inits to invoke all other construction parts + // XXX could we move this up ? + initStatusBar(); + initActions(); + + // add certain calls to the popup menu + fileOpen->plug( fTitleMenu ); + fileOpenRecent->plug( fTitleMenu ); + diskOpen->plug( fTitleMenu ); + streamOpen->plug( fTitleMenu ); + play->plug( fTitleMenu ); + pause->plug( fTitleMenu ); + slow->plug( fTitleMenu ); + fast->plug( fTitleMenu ); + fileClose->plug( fTitleMenu ); + fileQuit->plug( fTitleMenu ); +} + +KInterface::~KInterface() +{ + ; +} + +void KInterface::initActions() +{ + fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection()); + fileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection()); + fileClose = KStdAction::close(this, SLOT(slotFileClose()), actionCollection()); + preferences = KStdAction::preferences(this, SLOT(slotShowPreferences()), actionCollection()); + fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection()); + viewToolBar = KStdAction::showToolbar(this, SLOT(slotViewToolBar()), actionCollection()); + viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotViewStatusBar()), actionCollection()); + + diskOpen = new KAction( i18n( "Open &Disk" ), 0, 0, this, SLOT( slotOpenDisk() ), actionCollection(), "open_disk" ); + streamOpen = new KAction( i18n( "Open &Stream" ), 0, 0, this, SLOT( slotOpenStream() ), actionCollection(), "open_stream" ); + backward = new KAction( i18n( "&Backward" ), 0, 0, this, SLOT( slotBackward() ), actionCollection(), "backward" ); + stop = new KAction( i18n( "&Stop" ), 0, 0, this, SLOT( slotStop() ), actionCollection(), "stop" ); + play = new KAction( i18n( "&Play" ), 0, 0, this, SLOT( slotPlay() ), actionCollection(), "play" ); + pause = new KAction( i18n( "P&ause" ), 0, 0, this, SLOT( slotPause() ), actionCollection(), "pause" ); + slow = new KAction( i18n( "&Slow" ), 0, 0, this, SLOT( slotSlow() ), actionCollection(), "slow" ); + fast = new KAction( i18n( "Fas&t" ), 0, 0, this, SLOT( slotFast() ), actionCollection(), "fast" ); + prev = new KAction( i18n( "Prev" ), 0, 0, this, SLOT( slotPrev() ), actionCollection(), "prev" ); + next = new KAction( i18n( "Next" ), 0, 0, this, SLOT( slotNext() ), actionCollection(), "next" ); + + fileOpen->setStatusText(i18n("Opens an existing document")); + fileOpenRecent->setStatusText(i18n("Opens a recently used file")); + fileClose->setStatusText(i18n("Closes the actual document")); + fileQuit->setStatusText(i18n("Quits the application")); + viewToolBar->setStatusText(i18n("Enables/disables the toolbar")); + viewStatusBar->setStatusText(i18n("Enables/disables the statusbar")); + + diskOpen->setStatusText( i18n( "Opens a disk") ); + streamOpen->setStatusText( i18n( "Opens a network stream" ) ); + backward->setStatusText( i18n( "Backward" ) ); + stop->setStatusText( i18n( "Stops playback" ) ); + play->setStatusText( i18n( "Starts playback" ) ); + pause->setStatusText( i18n( "Pauses playback" ) ); + slow->setStatusText( i18n( "Slow" ) ); + fast->setStatusText( i18n( "Fast" ) ); + prev->setStatusText( i18n( "Prev" ) ); + next->setStatusText( i18n( "Next" ) ); + // use the absolute path to your ktestui.rc file for testing purpose in createGUI(); + + createGUI("plugins/kde/ui.rc"); +} + +void KInterface::initStatusBar() +{ + /////////////////////////////////////////////////////////////////// + // STATUSBAR + // TODO: add your own items you need for displaying current application status. + statusBar()->insertItem(i18n("Ready."), ID_STATUS_MSG, 1, false); + statusBar()->setItemAlignment( ID_STATUS_MSG, AlignLeft | AlignVCenter ); + statusBar()->insertItem( "0:00:00", ID_DATE, 0, true ); +} + +///////////////////////////////////////////////////////////////////// +// SLOT IMPLEMENTATION +///////////////////////////////////////////////////////////////////// + +void KInterface::slotFileOpen() +{ + playlist_t *p_playlist; + + slotStatusMsg( i18n( "Opening file..." ) ); + KURL url=KFileDialog::getOpenURL( QString::null, + i18n( "*|All files" ), this, i18n( "Open File..." ) ); + + if( !url.isEmpty() ) + { + p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + fileOpenRecent->addURL( url ); + playlist_Add( p_playlist, url.path(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } + } + + slotStatusMsg( i18n( "Ready." ) ); +} + +void KInterface::slotFileOpenRecent(const KURL& url) +{ + slotStatusMsg(i18n("Opening file...")); + slotStatusMsg(i18n("Ready.")); +} + +void KInterface::slotFileClose() +{ + slotStatusMsg(i18n("Closing file...")); + + close(); + + slotStatusMsg(i18n("Ready.")); +} + +void KInterface::slotFileQuit() +{ + slotStatusMsg(i18n("Exiting...")); + p_intf->p_vlc->b_die = VLC_TRUE; + slotStatusMsg(i18n("Ready.")); +} + +void KInterface::slotViewToolBar() +{ + slotStatusMsg(i18n("Toggling toolbar...")); + /////////////////////////////////////////////////////////////////// + // turn Toolbar on or off + if(!viewToolBar->isChecked()) + { + toolBar("mainToolBar")->hide(); + } + else + { + toolBar("mainToolBar")->show(); + } + + slotStatusMsg(i18n("Ready.")); +} + +void KInterface::slotViewStatusBar() +{ + slotStatusMsg(i18n("Toggle the statusbar...")); + /////////////////////////////////////////////////////////////////// + //turn Statusbar on or off + if(!viewStatusBar->isChecked()) + { + statusBar()->hide(); + } + else + { + statusBar()->show(); + } + + slotStatusMsg(i18n("Ready.")); +} + +void KInterface::slotShowPreferences() +{ + // Do something + KPreferences(this->p_intf, "main", this, "preferences"); +} + +void KInterface::slotStatusMsg(const QString &text) +{ + /////////////////////////////////////////////////////////////////// + // change status message permanently + statusBar()->clear(); + statusBar()->changeItem(text, ID_STATUS_MSG); +} + +void KInterface::slotManage() +{ + vlc_mutex_lock( &p_intf->change_lock ); + + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = (input_thread_t *) + vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + /* If the "display popup" flag has changed */ + if( p_intf->b_menu_change ) + { + fTitleMenu->popup( ( QCursor::pos() ) ); + p_intf->b_menu_change = 0; + } + + /* Update language/chapter menus after user request */ +#if 0 + if( p_intf->p_sys->p_input != NULL && p_intf->p_sys->p_window != NULL && + p_intf->p_sys->b_menus_update ) + { +// GnomeSetupMenu( p_intf ); + } +#endif + + /* Manage the slider */ +#define p_area p_intf->p_sys->p_input->stream.p_selected_area + if( p_intf->p_sys->p_input && p_area->i_size ) + { + fSlider->setValue( ( 10000. * p_area->i_tell ) / p_area->i_size ); + } +#undef p_area + + if( p_intf->b_die ) + { + p_intf->p_sys->p_app->quit(); + } + + vlc_mutex_unlock( &p_intf->change_lock ); +} + +void KInterface::slotSliderMoved( int position ) +{ + if( p_intf->p_sys->p_input ) + { + // XXX is this locking really useful ? + vlc_mutex_lock( &p_intf->change_lock ); + + off_t i_seek = ( position * p_intf->p_sys->p_input->stream.p_selected_area->i_size ) / 10000; + input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET ); + + vlc_mutex_unlock( &p_intf->change_lock ); + } +} + +void KInterface::slotSliderChanged( int position ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + char psz_time[ OFFSETTOTIME_MAX_SIZE ]; + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + +#define p_area p_intf->p_sys->p_input->stream.p_selected_area + statusBar()->changeItem( input_OffsetToTime( p_intf->p_sys->p_input, psz_time, ( p_area->i_size * position ) / 10000 ), ID_DATE ); +#undef p_area + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +void KInterface::slotOpenDisk() +{ + playlist_t *p_playlist; + int r = fDiskDialog->exec(); + if ( r ) + { + // Build source name + QString source; + source += fDiskDialog->type(); + source += ':'; + source += fDiskDialog->device(); + + source += '@'; + source += fDiskDialog->title(); + source += ','; + source += fDiskDialog->chapter(); + + p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + // add it to playlist + playlist_Add( p_playlist, source.latin1(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } + } +} + +void KInterface::slotOpenStream() +{ + playlist_t *p_playlist; + int r = fNetDialog->exec(); + if ( r ) + { + // Build source name + QString source; + source += fNetDialog->protocol(); + source += "://"; + source += fNetDialog->server(); + source += ":"; + source += QString().setNum( fNetDialog->port() ); + + p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + // add it to playlist + playlist_Add( p_playlist, source.latin1(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } + } +} + +void KInterface::slotPlay() +{ + if( p_intf->p_sys->p_input ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +void KInterface::slotPause() +{ + if ( p_intf->p_sys->p_input ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); + } +} + +void KInterface::slotStop() +{ + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + } +} + +void KInterface::slotBackward() +{ + msg_Err( p_intf, "KInterface::slotBackward() - Unimplemented" ); +} + +void KInterface::slotPrev() +{ + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); + } +} + +void KInterface::slotNext() +{ + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist ) + { + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); + } +} + +void KInterface::slotSlow() +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); + } +} + +void KInterface::slotFast() +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); + } +} + +void KInterface::dragEnterEvent( QDragEnterEvent *event ) +{ + event->accept( QUriDrag::canDecode( event ) ); +} + +void KInterface::dropEvent( QDropEvent *event ) +{ + KURL::List urlList; + + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + if ( KURLDrag::decode( event, urlList ) ) + { + for ( KURL::List::ConstIterator i = urlList.begin(); i != urlList.end(); i++ ) + { + // XXX add a private function to add a KURL with checking + // actually a whole class for core abstraction would be neat + if( !(*i).isEmpty() ) + { + fileOpenRecent->addURL( *i ); + playlist_Add( p_playlist, (*i).path(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + } + } + } + + vlc_object_release( p_playlist ); +} diff --git a/modules/gui/kde/interface.h b/modules/gui/kde/interface.h new file mode 100644 index 0000000000..9a7c7bf7de --- /dev/null +++ b/modules/gui/kde/interface.h @@ -0,0 +1,150 @@ +/*************************************************************************** + interface.h - description + ------------------- + begin : Sun Mar 25 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#ifndef _KDE_INTERFACE_H_ +#define _KDE_INTERFACE_H_ + +#include "common.h" + +#include +#include +#include +#include +#include +#include + +class KThread; + +class KDiskDialog; +class KNetDialog; +class KRecentFilesAction; +class KTitleMenu; +class KToggleAction; +class KVLCSlider; + +/**Main Window for the KDE vlc interface + *@author andres + */ + +class KInterface : public KMainWindow +{ + Q_OBJECT + public: + KInterface(intf_thread_t *p_intf, QWidget *parent=0, + const char *name=0); + ~KInterface(); + + public slots: + /** open a file and load it into the document*/ + void slotFileOpen(); + /** opens a file from the recent files menu */ + void slotFileOpenRecent(const KURL& url); + /** asks for saving if the file is modified, then closes the actual file and window*/ + void slotFileClose(); + /** closes all open windows by calling close() on each memberList item until the list is empty, then quits the application. + * If queryClose() returns false because the user canceled the saveModified() dialog, the closing breaks. + */ + void slotFileQuit(); + void slotShowPreferences(); + + /** toggles the toolbar + */ + void slotViewToolBar(); + /** toggles the statusbar + */ + void slotViewStatusBar(); + /** changes the statusbar contents for the standard label permanently, used to indicate current actions. + * @param text the text that is displayed in the statusbar + */ + void slotStatusMsg( const QString &text ); + + protected: + /** initializes the KActions of the application */ + void initActions(); + /** sets up the statusbar for the main window by initialzing a statuslabel. + */ + void initStatusBar(); + + virtual void dragEnterEvent( QDragEnterEvent *event ); + virtual void dropEvent( QDropEvent *event ); + + private slots: + /** we use this to manage the communication with the vlc core */ + void slotManage(); + + /** this slot is called when we drag the position seek bar */ + void slotSliderMoved( int position ); + + /** called every time the slider changes values */ + void slotSliderChanged( int position ); + + void slotOpenDisk(); + void slotOpenStream(); + + void slotBackward(); + void slotStop(); + void slotPlay(); + void slotPause(); + void slotSlow(); + void slotFast(); + void slotPrev(); + void slotNext(); + + private: + + intf_thread_t *p_intf; + + /** to call p_intf->pf_manage every now and then */ + QTimer *fTimer; + + /** slider which works well with user movement */ + KVLCSlider *fSlider; + + /** open dvd/vcd */ + KDiskDialog *fDiskDialog; + + /** open net stream */ + KNetDialog *fNetDialog; + + KTitleMenu *fTitleMenu; + + // KAction pointers to enable/disable actions + KAction *fileOpen; + KAction *diskOpen; + KAction *streamOpen; + KRecentFilesAction *fileOpenRecent; + KAction *fileClose; + KAction *fileQuit; + KToggleAction *viewToolBar; + KToggleAction *viewStatusBar; + KAction *backward; + KAction *stop; + KAction *play; + KAction *pause; + KAction *slow; + KAction *fast; + KAction *prev; + KAction *next; + KAction *preferences; +}; + +/***************************************************************************** + * intf_sys_t: description and status of KDE interface + *****************************************************************************/ +struct intf_sys_t +{ + KThread *p_thread; + + KApplication *p_app; + KInterface *p_window; + KAboutData *p_about; + + input_thread_t *p_input; +}; + +#endif /* _KDE_INTERFACE_H_ */ diff --git a/modules/gui/kde/kde.cpp b/modules/gui/kde/kde.cpp new file mode 100644 index 0000000000..1dcc82073c --- /dev/null +++ b/modules/gui/kde/kde.cpp @@ -0,0 +1,174 @@ +/***************************************************************************** + * kde.cpp : KDE plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: kde.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Andres Krapf Sun Mar 25 2001 + * + * 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 "common.h" + +#include "interface.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************** + * The local class. + *****************************************************************************/ +class KInterface; +class KAboutData; + +class KThread +{ + private: + KThread ( KThread &thread ) { }; + KThread &operator= ( KThread &thread ) { return ( *this ); }; + + intf_thread_t *p_intf; + + public: + KThread(intf_thread_t *p_intf); + ~KThread(); + + // These methods get exported to the core + static int open ( vlc_object_t * ); + static void close ( vlc_object_t * ); + static void run ( intf_thread_t * ); +}; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#ifdef WIN32 + int i = 90; +#else + int i = getenv( "DISPLAY" ) == NULL ? 8 : 85; +#endif + set_description( _("KDE interface module") ); + set_capability( "interface", i ); + set_program( "kvlc" ); + //set_callbacks( E_(Open), E_(Close) ); + set_callbacks( KThread::open, KThread::close ); +vlc_module_end(); + +/***************************************************************************** + * KThread::KThread: KDE interface constructor + *****************************************************************************/ +KThread::KThread(intf_thread_t *p_intf) +{ + this->p_intf = p_intf; + + p_intf->p_sys->p_about = + new KAboutData( "VideoLAN Client", I18N_NOOP("Kvlc"), VERSION, + _("This is the VideoLAN client, a DVD and MPEG player. It can play " + "MPEG and MPEG 2 files from a file or from a network source."), + KAboutData::License_GPL, + _("(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team"), + 0, 0, ""); + + char *authors[][2] = { + { "the VideoLAN Team", "" }, + { NULL, NULL }, + }; + + for ( int i = 0; NULL != authors[i][0]; i++ ) { + p_intf->p_sys->p_about->addAuthor( authors[i][0], 0, authors[i][1] ); + } + + int argc = 1; + char *argv[] = { p_intf->p_vlc->psz_object_name, NULL }; + KCmdLineArgs::init( argc, argv, p_intf->p_sys->p_about ); + + p_intf->p_sys->p_app = new KApplication(); + p_intf->p_sys->p_window = new KInterface(p_intf); + p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (KDE interface)" ); + + p_intf->p_sys->p_input = NULL; +} + +/***************************************************************************** + * KThread::~KThread: KDE interface destructor + *****************************************************************************/ +KThread::~KThread() +{ + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + /* XXX: can be deleted if the user closed the window ! */ + //delete p_intf->p_sys->p_window; + + delete p_intf->p_sys->p_app; + delete p_intf->p_sys->p_about; +} + +/***************************************************************************** + * KThread::open: initialize and create window + *****************************************************************************/ +int KThread::open(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 = (intf_sys_t *)malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + p_intf->pf_run = KThread::run; + + p_intf->p_sys->p_thread = new KThread(p_intf); + return ( 0 ); +} + +/***************************************************************************** + * KThread::close: destroy interface window + *****************************************************************************/ +void KThread::close(vlc_object_t *p_this) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + delete p_intf->p_sys->p_thread; + free( p_intf->p_sys ); +} + +/***************************************************************************** + * KThread::run: KDE thread + ***************************************************************************** + * This part of the interface is in a separate thread so that we can call + * exec() from within it without annoying the rest of the program. + *****************************************************************************/ +void KThread::run(intf_thread_t *p_intf) +{ + p_intf->p_sys->p_window->show(); + p_intf->p_sys->p_app->exec(); +} + diff --git a/modules/gui/kde/menu.cpp b/modules/gui/kde/menu.cpp new file mode 100644 index 0000000000..fbdbe4bf6c --- /dev/null +++ b/modules/gui/kde/menu.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + menu.cpp - description + ------------------- + begin : Thu Apr 12 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#include "interface.h" +#include "menu.h" + +#include +#include + +KTitleMenu::KTitleMenu( intf_thread_t *p_intf, QWidget *parent, const char *name ) : KPopupMenu( parent, name ) +{ + fInterfaceThread = p_intf; + connect( this, SIGNAL( aboutToShow() ), this, SLOT( regenerateSlot() ) ); + fLanguageList = new KActionMenu( "Language", 0, this ); +} + +KTitleMenu::~KTitleMenu() +{ +} + +void KTitleMenu::regenerateSlot() +{ + // removal of elements and disconnection of signal/slots happen transparently on delete + delete fLanguageList; + fLanguageList = new KActionMenu( "Language", 0, this ); + + int i_item = 0; + vlc_mutex_lock( &fInterfaceThread->p_sys->p_input->stream.stream_lock ); + + for( int i = 0 ; i < fInterfaceThread->p_sys->p_input->stream.i_es_number ; i++ ) + { + if( fInterfaceThread->p_sys->p_input->stream.pp_es[i]->i_cat /* == i_cat */ ) + { + i_item++; + QString language( fInterfaceThread->p_sys->p_input->stream.pp_es[i]->psz_desc ); + if ( QString::null == language ) + { + language += i18n( "Language" ); + language += " " + i_item; + } + KRadioAction *action = new KRadioAction( language, 0, this, "language_action" ); + fLanguageList->insert( action ); + + if( /* p_es == */ fInterfaceThread->p_sys->p_input->stream.pp_es[i] ) + { + /* don't lose p_item when we append into menu */ + //p_item_active = p_item; + } + } + } + + vlc_mutex_unlock( &fInterfaceThread->p_sys->p_input->stream.stream_lock ); + +#if 0 + /* link the new menu to the menubar item */ + gtk_menu_item_set_submenu( GTK_MENU_ITEM( p_root ), p_menu ); + + /* acitvation will call signals so we can only do it + * when submenu is attached to menu - to get intf_window */ + if( p_item_active != NULL ) + { + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( p_item_active ), + TRUE ); + } +#endif + + /* be sure that menu is sensitive if non empty */ + if ( i_item > 0 ) + { + fLanguageList->setEnabled( true ); + } +} + +/** this method is called when the user selects a language */ +void KTitleMenu::languageSelectedSlot() +{ +} diff --git a/modules/gui/kde/menu.h b/modules/gui/kde/menu.h new file mode 100644 index 0000000000..480d882597 --- /dev/null +++ b/modules/gui/kde/menu.h @@ -0,0 +1,44 @@ +/*************************************************************************** + menu.h - description + ------------------- + begin : Thu Apr 12 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#ifndef _KDE_MENU_H_ +#define _KDE_MENU_H_ + +#include "common.h" + +#include +#include + +class KActionMenu; + +/** + *@author andres + */ + +class KTitleMenu : public KPopupMenu +{ + Q_OBJECT + public: + KTitleMenu( intf_thread_t *p_intf, QWidget *parent=0, + const char *name=0 ); + ~KTitleMenu(); + + private: + intf_thread_t *fInterfaceThread; + KActionMenu *fLanguageList; + + private slots: // Private slots + /** this method regenerates the popup menu */ + void regenerateSlot(); + + /** this method is called when the user selects a language */ + void languageSelectedSlot(); + +}; + +#endif /* _KDE_MENU_H_ */ diff --git a/modules/gui/kde/net.cpp b/modules/gui/kde/net.cpp new file mode 100644 index 0000000000..a2143378e5 --- /dev/null +++ b/modules/gui/kde/net.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** + net.cpp - description + ------------------- + begin : Mon Apr 9 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#include "net.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KNetDialog::KNetDialog( QWidget *parent, const char *name ) + :KDialogBase( parent, name, true, + QString::null, Ok|Cancel, Ok, true ) +{ + QVBox *pageVBox = makeVBoxMainWidget(); + + QHBox *layout = new QHBox( pageVBox ); + layout->setSpacing( 5 ); + fButtonGroup = new QVButtonGroup( "Protocol", layout ); + fTSButton = new QRadioButton( "TS", fButtonGroup); + fTSButton->setChecked( true ); + fRTPButton = new QRadioButton( "RTP", fButtonGroup); + fRTPButton->setEnabled( false ); + fHTTPButton = new QRadioButton( "HTTP", fButtonGroup); + fHTTPButton->setEnabled( false ); + + QVGroupBox *serverVBox = new QVGroupBox( "Starting position", layout ); + + QHBox *titleHBox = new QHBox( serverVBox ); + new QLabel( "Address ", titleHBox ); + fAddress = new KLineEdit( "vls", titleHBox ); + QHBox *portHBox = new QHBox( serverVBox ); + new QLabel( "Port ", portHBox ); + fPort = new QSpinBox( 0, 65535, 1, portHBox ); +} + +KNetDialog::~KNetDialog() +{ +} + +QString KNetDialog::protocol() const +{ + if ( fTSButton->isChecked() ) + { + return ( QString( "ts" ) ); + } + else if ( fRTPButton->isChecked() ) + { + return ( QString( "rtp" ) ); + } + else + { + return ( QString( "http" ) ); + } +} + +QString KNetDialog::server() const +{ + return ( fAddress->text() ); +} + +int KNetDialog::port() const +{ + return ( fPort->value() ); +} diff --git a/modules/gui/kde/net.h b/modules/gui/kde/net.h new file mode 100644 index 0000000000..3f99021618 --- /dev/null +++ b/modules/gui/kde/net.h @@ -0,0 +1,45 @@ +/*************************************************************************** + net.h - description + ------------------- + begin : Mon Apr 9 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ + +#ifndef _KDE_NET_H_ +#define _KDE_NET_H_ + +#include +#include + +class QVButtonGroup; +class QRadioButton; +class QSpinBox; +class KLineEdit; + +/** + *@author andres + */ + +class KNetDialog : public KDialogBase +{ + Q_OBJECT + public: + KNetDialog(QWidget *parent=0, const char *name=0); + ~KNetDialog(); + + QString protocol() const; + QString server() const; + int port() const; + + private: + QVButtonGroup *fButtonGroup; + QRadioButton *fTSButton; + QRadioButton *fRTPButton; + QRadioButton *fHTTPButton; + KLineEdit *fAddress; + QSpinBox *fPort; + +}; + +#endif /* _KDE_NET_H_ */ diff --git a/modules/gui/kde/pluginsbox.cpp b/modules/gui/kde/pluginsbox.cpp new file mode 100644 index 0000000000..e7a3309c7f --- /dev/null +++ b/modules/gui/kde/pluginsbox.cpp @@ -0,0 +1,68 @@ +#include "pluginsbox.h" +#include "preferences.h" + +#include +#include +#include +#include +#include +#include + +KPluginsBox::KPluginsBox(intf_thread_t *p_intf, + QString text, QString value, QWidget *parent, + int spacing, KPreferences *pref) : + QGroupBox( 1, Vertical, text, parent ) +{ + owner = pref; + this->p_intf = p_intf; + QVBox *item_vbox = new QVBox( this ); + item_vbox->setSpacing(spacing); + + listView = new KListView(item_vbox); + listView->setAllColumnsShowFocus(true); + listView->addColumn(_("Name")); + listView->addColumn(_("Description")); + KButtonBox *item_bbox = new KButtonBox(item_vbox); + configure = item_bbox->addButton( _("Configure") ); + configure->setEnabled(false); + selectButton = item_bbox->addButton( _("Select") ); + QHBox *item_hbox = new QHBox(item_vbox); + item_hbox->setSpacing(spacing); + new QLabel( _("Selected:"), item_hbox ); + line = new KLineEdit( value, item_hbox ); + connect(selectButton, SIGNAL(clicked()), this, SLOT(selectClicked())); + connect(configure, SIGNAL(clicked()), this, SLOT(configureClicked())); + connect(listView, SIGNAL(selectionChanged( QListViewItem *)), + this, SLOT( selectionChanged( QListViewItem *))); +} + +KPluginsBox::~KPluginsBox() +{ + ; +} + +QListView* KPluginsBox::getListView() +{ + return listView; +} + +void KPluginsBox::selectClicked() +{ + if (listView->selectedItem()) { + line->setText(listView->selectedItem()->text(0)); + emit selectionChanged(listView->selectedItem()->text(0)); + } +} + +void KPluginsBox::configureClicked() +{ + if (listView->selectedItem()) { + new KPreferences(p_intf, listView->selectedItem()->text(0), this); + } +} +void KPluginsBox::selectionChanged( QListViewItem *item ) +{ + selectButton->setEnabled(true); + /* look for module 'psz_name' */ + configure->setEnabled(owner->isConfigureable(item->text(0))); +} diff --git a/modules/gui/kde/pluginsbox.h b/modules/gui/kde/pluginsbox.h new file mode 100644 index 0000000000..168ecb588f --- /dev/null +++ b/modules/gui/kde/pluginsbox.h @@ -0,0 +1,34 @@ +#ifndef _KDE_PLUGINBOX_H_ +#define _KDE_PLUGINBOX_H_ +#include +#include +#include +#include +#include "preferences.h" +class KPluginsBox : public QGroupBox +{ + Q_OBJECT + public: + KPluginsBox(intf_thread_t *p_intf, QString title, QString value, + QWidget *parent, int spacing, KPreferences *pref); + ~KPluginsBox(); + + QListView *getListView(void); + + private slots: + void selectClicked(void); + void configureClicked(void); + void selectionChanged( QListViewItem * ); + + signals: + void selectionChanged(const QString &text); + + private: + intf_thread_t *p_intf; + KListView *listView; + QPushButton *configure; + QPushButton *selectButton; + KLineEdit *line; + KPreferences *owner; +}; +#endif diff --git a/modules/gui/kde/preferences.cpp b/modules/gui/kde/preferences.cpp new file mode 100644 index 0000000000..56ef09881d --- /dev/null +++ b/modules/gui/kde/preferences.cpp @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "QConfigItem.h" +#include "pluginsbox.h" +#include "preferences.h" + +/* + construkt a new configuration window for the given module +*/ +KPreferences::KPreferences(intf_thread_t *p_intf, const char *psz_module_name, + QWidget *parent, const QString &caption) : + KDialogBase ( Tabbed, caption, Ok| Apply|Cancel|User1, Ok, parent, + "vlc preferences", true, false, "Save") +{ + module_t *p_module, *p_module_bis; + module_config_t *p_item; + QVBox *category_table = NULL; + QString *category_label; + + this->p_intf = p_intf; + + /* Look for the selected module */ + for( p_module = p_intf->p_vlc->p_module_bank->first ; p_module != NULL ; + p_module = p_module->next ) + { + + if( psz_module_name && !strcmp( psz_module_name, p_module->psz_object_name ) ) + break; + } + if( !p_module ) return; + p_item = p_module->p_config; + do + { + switch( p_item->i_type ) + { + + case CONFIG_HINT_CATEGORY: + case CONFIG_HINT_END: + + /* + * Now we can start taking care of the new category + */ + if( p_item->i_type == CONFIG_HINT_CATEGORY ) + { + category_label = new QString( p_item->psz_text ); + QFrame *page = addPage( *category_label ); + QVBoxLayout *toplayout = new QVBoxLayout( page); + QScrollView *sv = new QScrollView(page); + sv->setResizePolicy(QScrollView::AutoOneFit); + sv->setFrameStyle(QScrollView::NoFrame); + toplayout->addWidget(sv); + category_table = new QVBox(sv->viewport()); + sv->addChild(category_table); + toplayout->addStretch(10); + category_table->setSpacing(spacingHint()); + } + + break; + + case CONFIG_ITEM_MODULE: + + { + + vlc_mutex_lock( p_item->p_lock ); + KPluginsBox *item_frame = + new KPluginsBox( p_intf, p_item->psz_text, + p_item->psz_value ? p_item->psz_value :"", + category_table, + spacingHint(), + this ); + QConfigItem *ci = new QConfigItem(this, + p_item->psz_name, + p_item->i_type, + p_item->psz_value); + connect(item_frame, SIGNAL(selectionChanged(const QString &)), + ci, SLOT(setValue(const QString &))); + + + /* build a list of available plugins */ + +#if 0 /* FIXME */ + for( p_module_bis = p_intf->p_vlc->p_module_bank->first ; + p_module_bis != NULL ; + p_module_bis = p_module_bis->next ) { + if( p_module_bis->i_capabilities & (1 << p_item->i_value)){ + new QListViewItem(item_frame->getListView(), + p_module_bis->psz_object_name, + p_module_bis->psz_longname); + } + } +#endif + vlc_mutex_unlock( p_item->p_lock ); + } + break; + + case CONFIG_ITEM_STRING: + case CONFIG_ITEM_FILE: + + { + QHBox *hb = new QHBox(category_table); + hb->setSpacing(spacingHint()); + new QLabel(p_item->psz_text, hb); + /* add input box with default value */ + vlc_mutex_lock( p_item->p_lock ); + + KLineEdit *kl = new KLineEdit( p_item->psz_value ? + p_item->psz_value : "", hb); + QConfigItem *ci = new QConfigItem(this, p_item->psz_name, + p_item->i_type, + p_item->psz_value ? + p_item->psz_value : ""); + connect(kl, SIGNAL(textChanged ( const QString & )), + ci, SLOT(setValue( const QString &))); + QToolTip::add(kl, p_item->psz_longtext); + kl->setMaxLength(10); + + vlc_mutex_unlock( p_item->p_lock ); + + } + break; + + case CONFIG_ITEM_INTEGER: + /* add input box with default value */ + { + QHBox *hb = new QHBox(category_table); + hb->setSpacing(spacingHint()); + new QLabel(p_item->psz_text, hb); + QSpinBox *item_adj = new QSpinBox(-1, 99999, 1, hb); + QConfigItem *ci = new QConfigItem(this, p_item->psz_name, + p_item->i_type, + p_item->i_value); + connect(item_adj, SIGNAL(valueChanged( int)), + ci, SLOT(setValue(int))); + QToolTip::add(item_adj, p_item->psz_longtext); + item_adj->setValue( p_item->i_value ); + } + break; + + case CONFIG_ITEM_FLOAT: + { + QHBox *hb = new QHBox(category_table); + hb->setSpacing(spacingHint()); + new QLabel(p_item->psz_text, hb); + KDoubleNumInput *kdi= new KDoubleNumInput(p_item->f_value, hb); + kdi->setRange(-1, 99999, 0.01, false); + QConfigItem *ci = new QConfigItem(this, p_item->psz_name, + p_item->i_type, + p_item->f_value); + connect(kdi, SIGNAL(valueChanged(double)), + ci, SLOT(setValue(double))); + QToolTip::add(kdi, p_item->psz_longtext); + + } + break; + + + case CONFIG_ITEM_BOOL: + + /* add check button */ + { + QCheckBox *bool_checkbutton = + new QCheckBox(QString(p_item->psz_text), category_table); + QConfigItem *ci = new QConfigItem(this, p_item->psz_name, + p_item->i_type, + p_item->i_value); + bool_checkbutton->setChecked(p_item->i_value); + connect(bool_checkbutton, SIGNAL(stateChanged( int)), + ci, SLOT(setValue(int))); + QToolTip::add(bool_checkbutton, p_item->psz_longtext); + + } + break; + + } + + p_item++; + } + while( p_item->i_type != CONFIG_HINT_END ); + exec(); + +} + +/* + empty destructor, qt takes care of this (I think) +*/ +KPreferences::~KPreferences() +{ +} + +/* + return true if the give module is configureable +*/ +bool KPreferences::isConfigureable(QString module) +{ + module_t *p_module; + for( p_module = p_intf->p_vlc->p_module_bank->first ; + p_module != NULL ; + p_module = p_module->next ) { + if( !module.compare( p_module->psz_object_name ) ) { + return p_module->i_config_items != 0; + } + } + return false; + +} + +/* + run when the Apply button is pressed, and by the methods for the ok + and save buttons +*/ +void KPreferences::slotApply() +{ + QObjectList * l = queryList( "QConfigItem" ); + QObjectListIt it( *l ); // iterate over the config items + QObject * obj; + while ( (obj=it.current()) != 0 ) { + ++it; + QConfigItem *p_config = (QConfigItem *)obj; + msg_Dbg( p_intf, const_cast(p_config->name())); + msg_Dbg( p_intf, "%d", p_config->getType()); + + switch( p_config->getType() ) { + + case CONFIG_ITEM_STRING: + case CONFIG_ITEM_FILE: + case CONFIG_ITEM_MODULE: + if (p_config->sValue()) { + config_PutPsz( p_intf, p_config->name(), + strdup(p_config->sValue().latin1())); + } + else { + config_PutPsz( p_intf, p_config->name(), NULL ); + } + break; + case CONFIG_ITEM_INTEGER: + case CONFIG_ITEM_BOOL: + config_PutInt( p_intf, p_config->name(), p_config->iValue() ); + break; + case CONFIG_ITEM_FLOAT: + config_PutFloat( p_intf, p_config->name(), p_config->fValue() ); + break; + } + } + delete l; +} + +/* + run when the Ok button is pressed +*/ +void KPreferences::slotOk() +{ + slotApply(); + accept(); +} + +/* + run when the save button is pressed +*/ +void KPreferences::slotUser1() +{ + slotApply(); + config_SaveConfigFile( p_intf, NULL ); +} diff --git a/modules/gui/kde/preferences.h b/modules/gui/kde/preferences.h new file mode 100644 index 0000000000..f80880b13e --- /dev/null +++ b/modules/gui/kde/preferences.h @@ -0,0 +1,24 @@ +#ifndef _KDE_PREFERENCES_H_ +#define _KDE_PREFERENCES_H_ +#include "common.h" +#include + +#include "QConfigItem.h" +class KPreferences : KDialogBase +{ + Q_OBJECT + public: + KPreferences(intf_thread_t *p_intf, const char *psz_module_name, + QWidget *parent, const QString &caption=QString::null); + ~KPreferences(); + bool isConfigureable(QString module); + + public slots: + void slotApply(); + void slotOk(); + void slotUser1(); + + private: + intf_thread_t *p_intf; +}; +#endif diff --git a/modules/gui/kde/slider.cpp b/modules/gui/kde/slider.cpp new file mode 100644 index 0000000000..9ef5a34b30 --- /dev/null +++ b/modules/gui/kde/slider.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + slider.cpp - description + ------------------- + begin : Sun Mar 25 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ +/*************************************************************************** + shamelessly copied from noatun's excellent interface +****************************************************************************/ + +#include "slider.h" + +KVLCSlider::KVLCSlider(QWidget * parent, const char * name) : + QSlider(parent,name), pressed(false) +{ +} + +KVLCSlider::KVLCSlider(Orientation o, QWidget * parent, const char * name) : + QSlider(o,parent,name), pressed(false) +{ +} + +KVLCSlider::KVLCSlider(int minValue, int maxValue, int pageStep, int value, + Orientation o, QWidget * parent, const char * name) : + QSlider(minValue, maxValue, pageStep, value, o, parent,name), pressed(false) +{ +} + +void KVLCSlider::setValue(int i) +{ + if ( !pressed ) + { + QSlider::setValue( i ); + } +} + +void KVLCSlider::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() != RightButton ) + { + pressed=true; + QSlider::mousePressEvent( e ); + } +} + +void KVLCSlider::mouseReleaseEvent( QMouseEvent *e ) +{ + pressed=false; + QSlider::mouseReleaseEvent( e ); + emit userChanged( value() ); +} diff --git a/modules/gui/kde/slider.h b/modules/gui/kde/slider.h new file mode 100644 index 0000000000..13cc6e3ec4 --- /dev/null +++ b/modules/gui/kde/slider.h @@ -0,0 +1,45 @@ +/*************************************************************************** + slider.h - description + ------------------- + begin : Sun Apr 03 2001 + copyright : (C) 2001 by andres + email : dae@chez.com + ***************************************************************************/ +/*************************************************************************** + shamelessly copied from noatun's excellent interface +****************************************************************************/ +#ifndef _KDE_SLIDER_H_ +#define _KDE_SLIDER_H_ + +#include + +/** + * This slider can be changed by the vlc while not dragged by the user + */ +class KVLCSlider : public QSlider +{ + Q_OBJECT + public: + KVLCSlider(QWidget * parent, const char * name=0); + KVLCSlider(Orientation, QWidget * parent, const char * name=0); + KVLCSlider(int minValue, int maxValue, int pageStep, int value, + Orientation, QWidget * parent, const char * name=0); + + signals: + /** + * emmited only when the user changes the value by hand + */ + void userChanged( int value ); + + public slots: + virtual void setValue( int ); + + protected: + virtual void mousePressEvent( QMouseEvent * e ); + virtual void mouseReleaseEvent( QMouseEvent * e ); + + private: + bool pressed; // set this to true when the user drags the slider +}; + +#endif /* _KDE_SLIDER_H_ */ diff --git a/modules/gui/kde/ui.rc b/modules/gui/kde/ui.rc new file mode 100644 index 0000000000..8f0d817cfd --- /dev/null +++ b/modules/gui/kde/ui.rc @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + &File + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/gui/macosx/.cvsignore b/modules/gui/macosx/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/macosx/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/macosx/Makefile b/modules/gui/macosx/Makefile new file mode 100644 index 0000000000..8ade2c539a --- /dev/null +++ b/modules/gui/macosx/Makefile @@ -0,0 +1 @@ +macosx_SOURCES = macosx.m aout.m vout.m intf.m open.m playlist.m controls.m diff --git a/modules/gui/macosx/aout.m b/modules/gui/macosx/aout.m new file mode 100644 index 0000000000..4f192832ac --- /dev/null +++ b/modules/gui/macosx/aout.m @@ -0,0 +1,491 @@ +/***************************************************************************** + * aout.m: CoreAudio output plugin + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: aout.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Colin Delacroix + * Jon Lech Johansen + * + * 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 + +#include +#include + +#include +#include +#include +#include + +/***************************************************************************** + * aout_sys_t: private audio output method descriptor + ***************************************************************************** + * This structure is part of the audio output thread descriptor. + * It describes the CoreAudio specific properties of an output thread. + *****************************************************************************/ +struct aout_sys_t +{ + AudioDeviceID device; // the audio device + AudioConverterRef s_converter; // the AudioConverter + int b_format; // format begun + + AudioStreamBasicDescription s_src_stream_format; + AudioStreamBasicDescription s_dst_stream_format; + + Ptr p_buffer; // ptr to the 32 bit float data + UInt32 ui_buffer_size; // audio device buffer size + vlc_bool_t b_buffer_data; // available buffer data? + vlc_mutex_t mutex_lock; // pthread locks for sync of + vlc_cond_t cond_sync; // Play and callback + mtime_t clock_diff; // diff between system clock & audio +}; + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int SetFormat ( aout_thread_t * ); +static int GetBufInfo ( aout_thread_t *, int ); +static void Play ( aout_thread_t *, byte_t *, int ); + +static int CABeginFormat ( aout_thread_t * ); +static int CAEndFormat ( aout_thread_t * ); + +static OSStatus CAIOCallback ( AudioDeviceID inDevice, + const AudioTimeStamp *inNow, + const void *inInputData, + const AudioTimeStamp *inInputTime, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime, + void *threadGlobals ); + +/***************************************************************************** + * OpenAudio: opens a CoreAudio HAL device + *****************************************************************************/ +int E_(OpenAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + OSStatus err; + UInt32 ui_param_size; + + /* allocate instance */ + 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 members */ + memset( p_aout->p_sys, 0, sizeof( aout_sys_t ) ); + + /* get the default output device */ + ui_param_size = sizeof( p_aout->p_sys->device ); + err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, + &ui_param_size, + (void *)&p_aout->p_sys->device ); + + if( err != noErr ) + { + msg_Err( p_aout, "failed to get the device: %d", err ); + return( -1 ); + } + + /* get the buffer size that the device uses for IO */ + ui_param_size = sizeof( p_aout->p_sys->ui_buffer_size ); + err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false, + kAudioDevicePropertyBufferSize, + &ui_param_size, + &p_aout->p_sys->ui_buffer_size ); + + if( err != noErr ) + { + msg_Err( p_aout, "failed to get device buffer size: %d", err ); + return( -1 ); + } + + /* get a description of the data format used by the device */ + ui_param_size = sizeof( p_aout->p_sys->s_dst_stream_format ); + err = AudioDeviceGetProperty( p_aout->p_sys->device, 0, false, + kAudioDevicePropertyStreamFormat, + &ui_param_size, + &p_aout->p_sys->s_dst_stream_format ); + + if( err != noErr ) + { + msg_Err( p_aout, "failed to get dst stream format: %d", err ); + return( -1 ); + } + + if( p_aout->p_sys->s_dst_stream_format.mFormatID != kAudioFormatLinearPCM ) + { + msg_Err( p_aout, "kAudioFormatLinearPCM required" ); + return( -1 ); + } + + /* initialize mutex and cond */ + vlc_mutex_init( p_aout, &p_aout->p_sys->mutex_lock ); + vlc_cond_init( p_aout, &p_aout->p_sys->cond_sync ); + + /* initialize source stream format */ + memcpy( &p_aout->p_sys->s_src_stream_format, + &p_aout->p_sys->s_dst_stream_format, + sizeof( p_aout->p_sys->s_src_stream_format ) ); + + if( CABeginFormat( p_aout ) ) + { + msg_Err( p_aout, "CABeginFormat failed" ); + return( -1 ); + } + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = Play; + + return( 0 ); +} + +/***************************************************************************** + * SetFormat: pretends to set the dsp output format + *****************************************************************************/ +static int SetFormat( aout_thread_t *p_aout ) +{ + if( CAEndFormat( p_aout ) ) + { + msg_Err( p_aout, "CAEndFormat failed" ); + return( -1 ); + } + + switch( p_aout->i_format ) + { + case AOUT_FMT_S8: + msg_Err( p_aout, + "Signed 8 not supported yet, please report stream" ); + return( -1 ); + + case AOUT_FMT_U8: + msg_Err( p_aout, + "Unsigned 8 not supported yet, please report stream" ); + return( -1 ); + + case AOUT_FMT_S16_LE: + p_aout->p_sys->s_src_stream_format.mFormatFlags &= + ~kLinearPCMFormatFlagIsBigEndian; + p_aout->p_sys->s_src_stream_format.mFormatFlags |= + kLinearPCMFormatFlagIsSignedInteger; + break; + + case AOUT_FMT_S16_BE: + p_aout->p_sys->s_src_stream_format.mFormatFlags |= + kLinearPCMFormatFlagIsBigEndian; + p_aout->p_sys->s_src_stream_format.mFormatFlags |= + kLinearPCMFormatFlagIsSignedInteger; + break; + + case AOUT_FMT_U16_LE: + p_aout->p_sys->s_src_stream_format.mFormatFlags &= + ~kLinearPCMFormatFlagIsBigEndian; + p_aout->p_sys->s_src_stream_format.mFormatFlags &= + ~kLinearPCMFormatFlagIsSignedInteger; + break; + + case AOUT_FMT_U16_BE: + p_aout->p_sys->s_src_stream_format.mFormatFlags |= + kLinearPCMFormatFlagIsBigEndian; + p_aout->p_sys->s_src_stream_format.mFormatFlags &= + ~kLinearPCMFormatFlagIsSignedInteger; + break; + + default: + msg_Err( p_aout, "audio format (0x%08x) not supported now," + "please report stream", p_aout->i_format ); + return( -1 ); + } + + /* source format is not float */ + p_aout->p_sys->s_src_stream_format.mFormatFlags &= + ~kLinearPCMFormatFlagIsFloat; + + /* if destination format is float, take size diff into account */ + if( p_aout->p_sys->s_dst_stream_format.mFormatFlags & + kLinearPCMFormatFlagIsFloat ) + { + p_aout->p_sys->s_src_stream_format.mBytesPerPacket = + p_aout->p_sys->s_dst_stream_format.mBytesPerPacket / 2; + p_aout->p_sys->s_src_stream_format.mBytesPerFrame = + p_aout->p_sys->s_src_stream_format.mBytesPerFrame / 2; + p_aout->p_sys->s_src_stream_format.mBitsPerChannel = + p_aout->p_sys->s_src_stream_format.mBitsPerChannel / 2; + } + + /* set sample rate and channels per frame */ + p_aout->p_sys->s_src_stream_format.mSampleRate = p_aout->i_rate; + p_aout->p_sys->s_src_stream_format.mChannelsPerFrame = p_aout->i_channels; + + if( CABeginFormat( p_aout ) ) + { + msg_Err( p_aout, "CABeginFormat failed" ); + return( -1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * GetBufInfo: returns available bytes in buffer + *****************************************************************************/ +static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +{ + return( 0 ); /* send data as soon as possible */ +} + +/***************************************************************************** + * CAIOCallback : callback for audio output + *****************************************************************************/ +static OSStatus CAIOCallback( AudioDeviceID inDevice, + const AudioTimeStamp *inNow, + const void *inInputData, + const AudioTimeStamp *inInputTime, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime, + void *threadGlobals ) +{ + aout_thread_t *p_aout = (aout_thread_t *)threadGlobals; + aout_sys_t *p_sys = p_aout->p_sys; + + AudioTimeStamp host_time; + + host_time.mFlags = kAudioTimeStampHostTimeValid; + AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time ); + //intf_Msg( "%lld", AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000 + p_aout->p_sys->clock_diff - p_aout->date ); + p_aout->date = p_aout->p_sys->clock_diff + AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000; + + /* move data into output data buffer */ + if( p_sys->b_buffer_data ) + { + BlockMoveData( p_sys->p_buffer, + outOutputData->mBuffers[ 0 ].mData, + p_sys->ui_buffer_size ); + } + else + { + memset(outOutputData->mBuffers[ 0 ].mData, 0, p_sys->ui_buffer_size); +//X msg_Warn( p_aout, "audio output is starving, expect glitches" ); + } + + /* see Play below */ + vlc_mutex_lock( &p_sys->mutex_lock ); + p_sys->b_buffer_data = 0; + vlc_cond_signal( &p_sys->cond_sync ); + vlc_mutex_unlock( &p_sys->mutex_lock ); + + return( noErr ); +} + +/***************************************************************************** + * Play: play a sound + *****************************************************************************/ +static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) +{ + OSStatus err; + UInt32 ui_buffer_size = p_aout->p_sys->ui_buffer_size; + + /* + * wait for a callback to occur (to flush the buffer), so Play + * can't be called twice, losing the data we just wrote. + */ + vlc_mutex_lock( &p_aout->p_sys->mutex_lock ); + if ( p_aout->p_sys->b_buffer_data ) + { + vlc_cond_wait( &p_aout->p_sys->cond_sync, &p_aout->p_sys->mutex_lock ); + } + vlc_mutex_unlock( &p_aout->p_sys->mutex_lock ); + + err = AudioConverterConvertBuffer( p_aout->p_sys->s_converter, + i_size, buffer, + &ui_buffer_size, + p_aout->p_sys->p_buffer ); + + if( err != noErr ) + { + msg_Err( p_aout, "ConvertBuffer failed: %d", err ); + } + else + { + p_aout->p_sys->b_buffer_data = 1; + } +} + +/***************************************************************************** + * CloseAudio: closes the CoreAudio HAL device + *****************************************************************************/ +void E_(CloseAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + if( CAEndFormat( p_aout ) ) + { + msg_Err( p_aout, "CAEndFormat failed" ); + } + + /* destroy lock and cond */ + vlc_mutex_destroy( &p_aout->p_sys->mutex_lock ); + vlc_cond_destroy( &p_aout->p_sys->cond_sync ); + + free( p_aout->p_sys ); +} + +/***************************************************************************** + * CABeginFormat: creates an AudioConverter + *****************************************************************************/ +static int CABeginFormat( aout_thread_t *p_aout ) +{ + OSStatus err; + UInt32 ui_param_size; + + if( p_aout->p_sys->b_format ) + { + msg_Err( p_aout, "CABeginFormat (b_format)" ); + return( 1 ); + } + + p_aout->p_sys->ui_buffer_size = 2 * 2 * sizeof(s16) * + ((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000; + + /* set the buffer size that the device uses for IO */ + ui_param_size = sizeof( p_aout->p_sys->ui_buffer_size ); + err = AudioDeviceSetProperty( p_aout->p_sys->device, 0, 0, false, + kAudioDevicePropertyBufferSize, + ui_param_size, + &p_aout->p_sys->ui_buffer_size ); + //p_aout->i_latency = p_aout->p_sys->ui_buffer_size / 2; + + if( err != noErr ) + { + msg_Err( p_aout, "AudioDeviceSetProperty failed: %d", err ); + return( 1 ); + } + + /* allocate audio buffer */ + p_aout->p_sys->p_buffer = NewPtrClear( p_aout->p_sys->ui_buffer_size ); + + if( p_aout->p_sys->p_buffer == nil ) + { + msg_Err( p_aout, "failed to allocate audio buffer" ); + return( 1 ); + } + + /* create a new AudioConverter */ + err = AudioConverterNew( &p_aout->p_sys->s_src_stream_format, + &p_aout->p_sys->s_dst_stream_format, + &p_aout->p_sys->s_converter ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioConverterNew failed: %d", err ); + DisposePtr( p_aout->p_sys->p_buffer ); + return( 1 ); + } + + /* add callback */ + err = AudioDeviceAddIOProc( p_aout->p_sys->device, + (AudioDeviceIOProc)CAIOCallback, + (void *)p_aout ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioDeviceAddIOProc failed: %d", err ); + AudioConverterDispose( p_aout->p_sys->s_converter ); + DisposePtr( p_aout->p_sys->p_buffer ); + return( 1 ); + } + + /* open the output */ + err = AudioDeviceStart( p_aout->p_sys->device, + (AudioDeviceIOProc)CAIOCallback ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioDeviceStart failed: %d", err ); + AudioConverterDispose( p_aout->p_sys->s_converter ); + DisposePtr( p_aout->p_sys->p_buffer ); + return( 1 ); + } + + /* Let's pray for the following operation to be atomic... */ + p_aout->p_sys->clock_diff = mdate() + - AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) / 1000 + + (mtime_t)p_aout->p_sys->ui_buffer_size / 4 * 1000000 / (mtime_t)p_aout->i_rate + + p_aout->p_vlc->i_desync; + + p_aout->p_sys->b_format = 1; + + return( 0 ); +} + +/***************************************************************************** + * CAEndFormat: destroys the AudioConverter + *****************************************************************************/ +static int CAEndFormat( aout_thread_t *p_aout ) +{ + OSStatus err; + + if( !p_aout->p_sys->b_format ) + { + msg_Err( p_aout, "CAEndFormat (!b_format)" ); + return( 1 ); + } + + /* stop playing sound through the device */ + err = AudioDeviceStop( p_aout->p_sys->device, + (AudioDeviceIOProc)CAIOCallback ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioDeviceStop failed: %d", err ); + return( 1 ); + } + + /* remove the callback */ + err = AudioDeviceRemoveIOProc( p_aout->p_sys->device, + (AudioDeviceIOProc)CAIOCallback ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: %d", err ); + return( 1 ); + } + + /* destroy the AudioConverter */ + err = AudioConverterDispose( p_aout->p_sys->s_converter ); + + if( err != noErr ) + { + msg_Err( p_aout, "AudioConverterDispose failed: %d", err ); + return( 1 ); + } + + /* release audio buffer */ + DisposePtr( p_aout->p_sys->p_buffer ); + + p_aout->p_sys->b_format = 0; + + return( 0 ); +} diff --git a/modules/gui/macosx/controls.m b/modules/gui/macosx/controls.m new file mode 100644 index 0000000000..3e2a6b29b4 --- /dev/null +++ b/modules/gui/macosx/controls.m @@ -0,0 +1,518 @@ +/***************************************************************************** + * controls.m: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: controls.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * Christophe Massiot + * + * 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 /* malloc(), free() */ +#include /* for MAXPATHLEN */ +#include + +#include +#include + +#include +#include + +#include "intf.h" +#include "vout.h" + +/***************************************************************************** + * VLCControls interface + *****************************************************************************/ +@interface VLCControls : NSObject +{ + IBOutlet id o_open; +} + +- (IBAction)play:(id)sender; +- (IBAction)pause:(id)sender; +- (IBAction)stop:(id)sender; +- (IBAction)faster:(id)sender; +- (IBAction)slower:(id)sender; + +- (IBAction)prev:(id)sender; +- (IBAction)next:(id)sender; +- (IBAction)loop:(id)sender; + +- (IBAction)volumeUp:(id)sender; +- (IBAction)volumeDown:(id)sender; +- (IBAction)mute:(id)sender; +- (IBAction)fullscreen:(id)sender; +- (IBAction)deinterlace:(id)sender; + +- (IBAction)toggleProgram:(id)sender; +- (IBAction)toggleTitle:(id)sender; +- (IBAction)toggleChapter:(id)sender; +- (IBAction)toggleLanguage:(id)sender; + +@end + +/***************************************************************************** + * VLCControls implementation + *****************************************************************************/ +@implementation VLCControls + +- (IBAction)play:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + /* If the playlist is empty, open a file requester instead */ + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + + [o_open openFile: nil]; + } +} + +- (IBAction)pause:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + + if( p_intf->p_sys->p_input == NULL ) + { + return; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); +} + +- (IBAction)stop:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); +} + +- (IBAction)faster:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + + if( p_intf->p_sys->p_input == NULL ) + { + return; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); +} + +- (IBAction)slower:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + + if( p_intf->p_sys->p_input == NULL ) + { + return; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); +} + +- (IBAction)prev:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); +} + +- (IBAction)next:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); +} + +- (IBAction)loop:(id)sender +{ + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + if( p_intf->p_sys->b_loop ) + { + [o_mi setState: NSOffState]; + playlist_Delete( p_playlist, p_playlist->i_size - 1 ); + } + else + { + [o_mi setState: NSOnState]; + playlist_Add( p_playlist, "vlc:loop", + PLAYLIST_APPEND, PLAYLIST_END ); + } + + p_intf->p_sys->b_loop = !p_intf->p_sys->b_loop; + + vlc_object_release( p_playlist ); +} + +- (IBAction)volumeUp:(id)sender +{ + /* + intf_thread_t * p_intf = [NSApp getIntf]; + */ + + /* TODO, kAudioDevicePropertyVolumeScalar */ +} + +- (IBAction)volumeDown:(id)sender +{ + /* + intf_thread_t * p_intf = [NSApp getIntf]; + */ + + /* TODO, kAudioDevicePropertyVolumeScalar */ +} + +- (IBAction)mute:(id)sender +{ + OSStatus err; + AudioDeviceID device; + UInt32 ui_param_size; + + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + UInt32 b_mute = !p_intf->p_sys->b_mute; + + [o_mi setState: b_mute ? NSOnState : NSOffState]; + p_intf->p_sys->b_mute = !p_intf->p_sys->b_mute; + + ui_param_size = sizeof( device ); + err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, + &ui_param_size, (void *)&device ); + if( err != noErr ) + { + msg_Err( p_intf, "AudioHardwareGetProperty failed (%d)", err ); + return; + } + + ui_param_size = sizeof( b_mute ); + err = AudioDeviceSetProperty( device, 0, 0, false, + kAudioDevicePropertyMute, + ui_param_size, (void *)&b_mute ); + if( err != noErr ) + { + msg_Err( p_intf, "AudioDeviceSetProperty failed (%d)", err ); + return; + } +} + +- (IBAction)fullscreen:(id)sender +{ + id o_window = [NSApp keyWindow]; + + if( [[o_window className] isEqualToString: @"VLCWindow"] ) + { + [o_window toggleFullscreen]; + } +} + +- (IBAction)deinterlace:(id)sender +{ + intf_thread_t * p_intf = [NSApp getIntf]; + BOOL bEnable = [sender state] == NSOffState; + + if( bEnable ) + { + config_PutPsz( p_intf, "filter", "deinterlace" ); + config_PutPsz( p_intf, "deinterlace-mode", + [[sender title] lossyCString] ); + } + else + { + config_PutPsz( p_intf, "filter", NULL ); + } +} + +- (IBAction)toggleProgram:(id)sender +{ + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + + if( [o_mi state] == NSOffState ) + { + u16 i_program_id = [o_mi tag]; + + input_ChangeProgram( p_intf->p_sys->p_input, i_program_id ); + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +- (IBAction)toggleTitle:(id)sender +{ + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + + if( [o_mi state] == NSOffState ) + { + int i_title = [o_mi tag]; + +#define p_input p_intf->p_sys->p_input + input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] ); + input_SetStatus( p_input, INPUT_STATUS_PLAY ); +#undef p_input + } +} + +- (IBAction)toggleChapter:(id)sender +{ + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + + if( [o_mi state] == NSOffState ) + { + int i_chapter = [o_mi tag]; + +#define p_input p_intf->p_sys->p_input + p_input->stream.p_selected_area->i_part = i_chapter; + input_ChangeArea( p_input, p_input->stream.p_selected_area ); + input_SetStatus( p_input, INPUT_STATUS_PLAY ); +#undef p_input + } +} + +- (IBAction)toggleLanguage:(id)sender +{ + NSMenuItem * o_mi = (NSMenuItem *)sender; + intf_thread_t * p_intf = [NSApp getIntf]; + +#define p_input p_intf->p_sys->p_input + + if( !p_intf->p_sys->b_audio_update ) + { + NSValue * o_value = [o_mi representedObject]; + es_descriptor_t * p_es = [o_value pointerValue]; + + if( [o_mi state] == NSOnState ) + { + /* we just have one ES to disable */ + input_ToggleES( p_input, p_es, 0 ); + } + else + { + int i; + int i_cat = [o_mi tag]; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + +#define ES p_input->stream.pp_selected_es[i] + + /* unselect the selected ES in the same class */ + for( i = 0; i < p_input->stream.i_selected_es_number; i++ ) + { + if( ES->i_cat == i_cat ) + { + vlc_mutex_unlock( &p_input->stream.stream_lock ); + input_ToggleES( p_input, ES, 0 ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + break; + } + } + +#undef ES + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + input_ToggleES( p_input, p_es, 1 ); + } + } + +#undef p_input +} + +@end + +@implementation VLCControls (NSMenuValidation) + +- (BOOL)validateMenuItem:(NSMenuItem *)o_mi +{ + BOOL bEnabled = TRUE; + NSMenu * o_menu = [o_mi menu]; + intf_thread_t * p_intf = [NSApp getIntf]; + + if( [[o_mi title] isEqualToString: _NS("Pause")] || + [[o_mi title] isEqualToString: _NS("Faster")] || + [[o_mi title] isEqualToString: _NS("Slower")] ) + { + if( p_intf->p_sys->p_input != NULL ) + { +#define p_input p_intf->p_sys->p_input + vlc_mutex_lock( &p_input->stream.stream_lock ); + bEnabled = p_input->stream.b_pace_control; + vlc_mutex_unlock( &p_input->stream.stream_lock ); +#undef p_input + } + else + { + bEnabled = FALSE; + } + } + else if( [[o_mi title] isEqualToString: _NS("Stop")] ) + { + bEnabled = p_intf->p_sys->p_input != NULL; + } + else if( [[o_mi title] isEqualToString: _NS("Prev")] || + [[o_mi title] isEqualToString: _NS("Next")] ) + { + playlist_t * p_playlist = vlc_object_find( p_intf, + VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + bEnabled = FALSE; + } + else + { + vlc_mutex_lock( &p_playlist->object_lock ); + bEnabled = p_playlist->i_size > 1; + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + } + } + else if( [[o_mi title] isEqualToString: _NS("Volume Up")] || + [[o_mi title] isEqualToString: _NS("Volume Down")] ) + { + bEnabled = FALSE; /* not implemented yet */ + } + else if( [[o_mi title] isEqualToString: _NS("Mute")] ) + { + OSStatus err; + UInt32 b_mute; + AudioDeviceID device; + UInt32 ui_param_size; + + ui_param_size = sizeof( device ); + err = AudioHardwareGetProperty( + kAudioHardwarePropertyDefaultOutputDevice, + &ui_param_size, (void *)&device ); + if( err != noErr ) + { + msg_Err( p_intf, "AudioHardwareGetProperty failed (%d)", err ); + } + else + { + ui_param_size = sizeof( b_mute ); + err = AudioDeviceGetProperty( device, 0, 0, + kAudioDevicePropertyMute, + &ui_param_size, (void *)&b_mute ); + if( err != noErr ) + { + msg_Err( p_intf, "AudioDeviceGetProperty failed (%d)", err ); + } + else + { + [o_mi setState: b_mute ? NSOnState : NSOffState]; + p_intf->p_sys->b_mute = (vlc_bool_t)b_mute ? 1 : 0; + } + } + } + else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ) + { + id o_window = [NSApp keyWindow]; + + if( [[o_window className] isEqualToString: @"VLCWindow"] ) + { + [o_mi setState: [o_window isFullscreen] ? + NSOnState : NSOffState]; + } + else + { + bEnabled = FALSE; + } + } + else if( o_menu != nil && + [[o_menu title] isEqualToString: _NS("Deinterlace")] ) + { + char * psz_filter = config_GetPsz( p_intf, "filter" ); + + if( psz_filter != NULL ) + { + free( psz_filter ); + + psz_filter = config_GetPsz( p_intf, "deinterlace-mode" ); + } + + if( psz_filter != NULL ) + { + if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 ) + { + [o_mi setState: NSOnState]; + } + else + { + [o_mi setState: NSOffState]; + } + + free( psz_filter ); + } + else + { + [o_mi setState: NSOffState]; + } + } + + return( bEnabled ); +} + +@end diff --git a/modules/gui/macosx/intf.h b/modules/gui/macosx/intf.h new file mode 100644 index 0000000000..276ef928d1 --- /dev/null +++ b/modules/gui/macosx/intf.h @@ -0,0 +1,163 @@ +/***************************************************************************** + * intf.h: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: intf.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * Christophe Massiot + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * VLCApplication interface + *****************************************************************************/ +@interface VLCApplication : NSApplication +{ + NSStringEncoding i_encoding; + intf_thread_t *p_intf; +} + +- (void)initIntlSupport; +- (NSString *)localizedString:(char *)psz; + +- (void)setIntf:(intf_thread_t *)p_intf; +- (intf_thread_t *)getIntf; + +@end + +#define _NS(s) [NSApp localizedString: _(s)] + +/***************************************************************************** + * intf_sys_t: description and status of the interface + *****************************************************************************/ +struct intf_sys_t +{ + NSAutoreleasePool * o_pool; + NSPort * o_sendport; + + /* special actions */ + vlc_bool_t b_loop; + vlc_bool_t b_playing; + vlc_bool_t b_mute; + + /* menus handlers */ + vlc_bool_t b_chapter_update; + vlc_bool_t b_program_update; + vlc_bool_t b_title_update; + vlc_bool_t b_audio_update; + vlc_bool_t b_spu_update; + + /* The input thread */ + input_thread_t * p_input; + + /* The messages window */ + msg_subscription_t * p_sub; + + /* DVD mode */ + int i_part; +}; + +/***************************************************************************** + * VLCMain interface + *****************************************************************************/ +@interface VLCMain : NSObject +{ + IBOutlet id o_window; /* main window */ + + IBOutlet id o_controls; /* VLCControls */ + IBOutlet id o_playlist; /* VLCPlaylist */ + + IBOutlet id o_messages; /* messages tv */ + IBOutlet id o_msgs_panel; /* messages panel */ + IBOutlet id o_msgs_btn_ok; /* messages btn */ + + /* main menu */ + + IBOutlet id o_mi_about; + IBOutlet id o_mi_hide; + IBOutlet id o_mi_hide_others; + IBOutlet id o_mi_show_all; + IBOutlet id o_mi_quit; + + IBOutlet id o_mu_file; + IBOutlet id o_mi_open_file; + IBOutlet id o_mi_open_disc; + IBOutlet id o_mi_open_net; + IBOutlet id o_mi_open_quickly; + IBOutlet id o_mi_open_recent; + IBOutlet id o_mi_open_recent_cm; + + IBOutlet id o_mu_edit; + IBOutlet id o_mi_cut; + IBOutlet id o_mi_copy; + IBOutlet id o_mi_paste; + IBOutlet id o_mi_clear; + IBOutlet id o_mi_select_all; + + IBOutlet id o_mu_view; + IBOutlet id o_mi_playlist; + IBOutlet id o_mi_messages; + + IBOutlet id o_mu_controls; + IBOutlet id o_mi_play; + IBOutlet id o_mi_pause; + IBOutlet id o_mi_stop; + IBOutlet id o_mi_faster; + IBOutlet id o_mi_slower; + IBOutlet id o_mi_previous; + IBOutlet id o_mi_next; + IBOutlet id o_mi_loop; + IBOutlet id o_mi_vol_up; + IBOutlet id o_mi_vol_down; + IBOutlet id o_mi_mute; + IBOutlet id o_mi_fullscreen; + IBOutlet id o_mi_deinterlace; + IBOutlet id o_mi_program; + IBOutlet id o_mi_title; + IBOutlet id o_mi_chapter; + IBOutlet id o_mi_language; + IBOutlet id o_mi_subtitle; + + IBOutlet id o_mu_window; + IBOutlet id o_mi_minimize; + IBOutlet id o_mi_bring_atf; + + /* dock menu */ + IBOutlet id o_dmi_play; + IBOutlet id o_dmi_pause; + IBOutlet id o_dmi_stop; +} + +- (void)terminate; + +- (void)manage; +- (void)manageMode; + +- (void)setupMenus; +- (void)setupLangMenu:(NSMenuItem *)o_mi + es:(es_descriptor_t *)p_es + category:(int)i_cat + selector:(SEL)pf_callback; + +- (IBAction)clearRecentItems:(id)sender; +- (void)openRecentItem:(id)sender; + +@end + +@interface VLCMain (Internal) +- (void)handlePortMessage:(NSPortMessage *)o_msg; +@end diff --git a/modules/gui/macosx/intf.m b/modules/gui/macosx/intf.m new file mode 100644 index 0000000000..774a5ac0a9 --- /dev/null +++ b/modules/gui/macosx/intf.m @@ -0,0 +1,900 @@ +/***************************************************************************** + * intf.m: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: intf.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * Christophe Massiot + * + * 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 /* malloc(), free() */ +#include /* for MAXPATHLEN */ +#include + +#include +#include +#include + +#include +#include + +#include "intf.h" +#include "vout.h" +#include "playlist.h" + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static void Run ( intf_thread_t *p_intf ); + +/***************************************************************************** + * OpenIntf: initialize interface + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + + p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + return( 1 ); + } + + memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) ); + + p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init]; + p_intf->p_sys->o_sendport = [[NSPort port] retain]; + + p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + + p_intf->pf_run = Run; + + [[VLCApplication sharedApplication] autorelease]; + [NSApp initIntlSupport]; + [NSApp setIntf: p_intf]; + + [NSBundle loadNibNamed: @"MainMenu" owner: NSApp]; + + return( 0 ); +} + +/***************************************************************************** + * CloseIntf: destroy interface + *****************************************************************************/ +void E_(CloseIntf) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + [p_intf->p_sys->o_sendport release]; + [p_intf->p_sys->o_pool release]; + + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: main loop + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + [NSApp run]; +} + +/***************************************************************************** + * VLCApplication implementation + *****************************************************************************/ +@implementation VLCApplication + +- (id)init +{ + /* default encoding: ISO-8859-1 */ + i_encoding = NSISOLatin1StringEncoding; + + return( [super init] ); +} + +- (void)initIntlSupport +{ + char *psz_lang = getenv( "LANG" ); + + if( psz_lang == NULL ) + { + return; + } + + if( strncmp( psz_lang, "pl", 2 ) == 0 ) + { + i_encoding = NSISOLatin2StringEncoding; + } + else if( strncmp( psz_lang, "ja", 2 ) == 0 ) + { + i_encoding = NSJapaneseEUCStringEncoding; + } + else if( strncmp( psz_lang, "ru", 2 ) == 0 ) + { +#define CFSENC2NSSENC(e) CFStringConvertEncodingToNSStringEncoding(e) + i_encoding = CFSENC2NSSENC( kCFStringEncodingKOI8_R ); +#undef CFSENC2NSSENC + } +} + +- (NSString *)localizedString:(char *)psz +{ + UInt32 uiLength = (UInt32)strlen( psz ); + NSData * o_data = [NSData dataWithBytes: psz length: uiLength]; + NSString *o_str = [[NSString alloc] initWithData: o_data + encoding: i_encoding]; + return( [o_str autorelease] ); +} + +- (void)setIntf:(intf_thread_t *)_p_intf +{ + p_intf = _p_intf; +} + +- (intf_thread_t *)getIntf +{ + return( p_intf ); +} + +- (void)terminate:(id)sender +{ + [self getIntf]->p_vlc->b_die = VLC_TRUE; +} + +@end + +/***************************************************************************** + * VLCMain implementation + *****************************************************************************/ +@implementation VLCMain + +- (void)awakeFromNib +{ + NSString * pTitle = [NSString + stringWithCString: VOUT_TITLE " (Cocoa)"]; + + [o_window setTitle: pTitle]; + + [o_msgs_panel setTitle: _NS("Messages")]; + [o_msgs_btn_ok setTitle: _NS("Close")]; + + [o_mi_about setTitle: _NS("About vlc")]; + [o_mi_hide setTitle: _NS("Hide vlc")]; + [o_mi_hide_others setTitle: _NS("Hide Others")]; + [o_mi_show_all setTitle: _NS("Show All")]; + [o_mi_quit setTitle: _NS("Quit vlc")]; + + [o_mu_file setTitle: _NS("File")]; + [o_mi_open_file setTitle: _NS("Open File")]; + [o_mi_open_disc setTitle: _NS("Open Disc")]; + [o_mi_open_net setTitle: _NS("Open Network")]; + [o_mi_open_quickly setTitle: _NS("Open Quickly...")]; + [o_mi_open_recent setTitle: _NS("Open Recent")]; + [o_mi_open_recent_cm setTitle: _NS("Clear Menu")]; + + [o_mu_edit setTitle: _NS("Edit")]; + [o_mi_cut setTitle: _NS("Cut")]; + [o_mi_copy setTitle: _NS("Copy")]; + [o_mi_paste setTitle: _NS("Paste")]; + [o_mi_clear setTitle: _NS("Clear")]; + [o_mi_select_all setTitle: _NS("Select All")]; + + [o_mu_view setTitle: _NS("View")]; + [o_mi_playlist setTitle: _NS("Playlist")]; + [o_mi_messages setTitle: _NS("Messages")]; + + [o_mu_controls setTitle: _NS("Controls")]; + [o_mi_play setTitle: _NS("Play")]; + [o_mi_pause setTitle: _NS("Pause")]; + [o_mi_stop setTitle: _NS("Stop")]; + [o_mi_faster setTitle: _NS("Faster")]; + [o_mi_slower setTitle: _NS("Slower")]; + [o_mi_previous setTitle: _NS("Prev")]; + [o_mi_next setTitle: _NS("Next")]; + [o_mi_loop setTitle: _NS("Loop")]; + [o_mi_vol_up setTitle: _NS("Volume Up")]; + [o_mi_vol_down setTitle: _NS("Volume Down")]; + [o_mi_mute setTitle: _NS("Mute")]; + [o_mi_fullscreen setTitle: _NS("Fullscreen")]; + [o_mi_deinterlace setTitle: _NS("Deinterlace")]; + [o_mi_program setTitle: _NS("Program")]; + [o_mi_title setTitle: _NS("Title")]; + [o_mi_chapter setTitle: _NS("Chapter")]; + [o_mi_language setTitle: _NS("Language")]; + [o_mi_subtitle setTitle: _NS("Subtitles")]; + + [o_mu_window setTitle: _NS("Window")]; + [o_mi_minimize setTitle: _NS("Minimize")]; + [o_mi_bring_atf setTitle: _NS("Bring All to Front")]; + + /* dock menu */ + [o_dmi_play setTitle: _NS("Play")]; + [o_dmi_pause setTitle: _NS("Pause")]; + [o_dmi_stop setTitle: _NS("Stop")]; + + [self manageMode]; +} + +- (void)applicationWillFinishLaunching:(NSNotification *)o_notification +{ + intf_thread_t * p_intf = [NSApp getIntf]; + + [NSThread detachNewThreadSelector: @selector(manage) + toTarget: self withObject: nil]; + + [p_intf->p_sys->o_sendport setDelegate: self]; + [[NSRunLoop currentRunLoop] + addPort: p_intf->p_sys->o_sendport + forMode: NSDefaultRunLoopMode]; +} + +- (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename +{ + [o_playlist appendArray: + [NSArray arrayWithObject: o_filename] atPos: -1]; + + return( TRUE ); +} + +- (void)manage +{ + NSDate * o_sleep_date; + intf_thread_t * p_intf = [NSApp getIntf]; + NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; + + while( !p_intf->b_die ) + { + int i_start, i_stop; + + vlc_mutex_lock( &p_intf->change_lock ); + + /* update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + if( p_intf->p_sys->p_input ) + { + input_thread_t *p_input = p_intf->p_sys->p_input; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( !p_input->b_die ) + { + /* New input or stream map change */ + if( p_input->stream.b_changed ) + { + [self manageMode]; + [self setupMenus]; + p_intf->p_sys->b_playing = 1; + } + + if( p_intf->p_sys->i_part != + p_input->stream.p_selected_area->i_part ) + { + p_intf->p_sys->b_chapter_update = 1; + [self setupMenus]; + } + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + else if( p_intf->p_sys->b_playing && !p_intf->b_die ) + { + [self manageMode]; + p_intf->p_sys->b_playing = 0; + } + + /* update the log window */ + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + i_stop = *p_intf->p_sys->p_sub->pi_stop; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + + if( p_intf->p_sys->p_sub->i_start != i_stop ) + { + NSColor *o_white = [NSColor whiteColor]; + NSColor *o_red = [NSColor redColor]; + NSColor *o_yellow = [NSColor yellowColor]; + NSColor *o_gray = [NSColor grayColor]; + + unsigned int ui_length = [[o_messages string] length]; + + NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray }; + static const char * ppsz_type[4] = { ": ", " error: ", + " warning: ", " debug: " }; + + [o_messages setEditable: YES]; + [o_messages setSelectedRange: NSMakeRange( ui_length, 0 )]; + [o_messages scrollRangeToVisible: NSMakeRange( ui_length, 0 )]; + + for( i_start = p_intf->p_sys->p_sub->i_start; + i_start != i_stop; + i_start = (i_start+1) % VLC_MSG_QSIZE ) + { + NSString *o_msg; + NSDictionary *o_attr; + NSAttributedString *o_msg_color; + int i_type = p_intf->p_sys->p_sub->p_msg[i_start].i_type; + + o_attr = [NSDictionary dictionaryWithObject: o_gray + forKey: NSForegroundColorAttributeName]; + o_msg = [NSString stringWithFormat: @"%s%s", + p_intf->p_sys->p_sub->p_msg[i_start].psz_module, + ppsz_type[i_type]]; + o_msg_color = [[NSAttributedString alloc] + initWithString: o_msg attributes: o_attr]; + [o_messages insertText: o_msg_color]; + + o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type] + forKey: NSForegroundColorAttributeName]; + o_msg = [NSString stringWithCString: + p_intf->p_sys->p_sub->p_msg[i_start].psz_msg]; + o_msg_color = [[NSAttributedString alloc] + initWithString: o_msg attributes: o_attr]; + [o_messages insertText: o_msg_color]; + + [o_messages insertText: @"\n"]; + } + + [o_messages setEditable: NO]; + + vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock ); + p_intf->p_sys->p_sub->i_start = i_start; + vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock ); + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + o_sleep_date = [NSDate dateWithTimeIntervalSinceNow: 0.1]; + [NSThread sleepUntilDate: o_sleep_date]; + } + + [self terminate]; + + [o_pool release]; +} + +- (void)terminate +{ + NSEvent * pEvent; + vout_thread_t * p_vout; + playlist_t * p_playlist; + intf_thread_t * p_intf = [NSApp getIntf]; + + /* release input */ + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + /* + * Free playlists + */ + msg_Dbg( p_intf, "removing all playlists" ); + while( (p_playlist = vlc_object_find( p_intf->p_vlc, VLC_OBJECT_PLAYLIST, + FIND_CHILD )) ) + { + vlc_object_detach_all( p_playlist ); + vlc_object_release( p_playlist ); + playlist_Destroy( p_playlist ); + } + + /* + * Free video outputs + */ + msg_Dbg( p_intf, "removing all video outputs" ); + while( (p_vout = vlc_object_find( p_intf->p_vlc, + VLC_OBJECT_VOUT, FIND_CHILD )) ) + { + vlc_object_detach_all( p_vout ); + vlc_object_release( p_vout ); + vout_DestroyThread( p_vout ); + } + + [NSApp stop: nil]; + + /* write cached user defaults to disk */ + [[NSUserDefaults standardUserDefaults] synchronize]; + + /* send a dummy event to break out of the event loop */ + pEvent = [NSEvent mouseEventWithType: NSLeftMouseDown + location: NSMakePoint( 1, 1 ) modifierFlags: 0 + timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber] + context: [NSGraphicsContext currentContext] eventNumber: 1 + clickCount: 1 pressure: 0.0]; + [NSApp postEvent: pEvent atStart: YES]; +} + +- (void)manageMode +{ + vlc_bool_t b_control = 0; + intf_thread_t * p_intf = [NSApp getIntf]; + + if( p_intf->p_sys->p_input ) + { + /* control buttons for free pace streams */ + b_control = p_intf->p_sys->p_input->stream.b_pace_control; + + /* get ready for menu regeneration */ + p_intf->p_sys->b_program_update = 1; + p_intf->p_sys->b_title_update = 1; + p_intf->p_sys->b_chapter_update = 1; + p_intf->p_sys->b_audio_update = 1; + p_intf->p_sys->b_spu_update = 1; + p_intf->p_sys->i_part = 0; + + p_intf->p_sys->p_input->stream.b_changed = 0; + msg_Dbg( p_intf, "stream has changed, refreshing interface" ); + } + else + { + /* unsensitize menus */ + [o_mi_program setEnabled: FALSE]; + [o_mi_title setEnabled: FALSE]; + [o_mi_chapter setEnabled: FALSE]; + [o_mi_language setEnabled: FALSE]; + [o_mi_subtitle setEnabled: FALSE]; + } +} + +- (void)setupMenus +{ + int i, i_nb_items; + NSMenuItem * o_item; + NSString * o_menu_title; + char psz_title[ 256 ]; + + es_descriptor_t * p_audio_es = NULL; + es_descriptor_t * p_spu_es = NULL; + + intf_thread_t * p_intf = [NSApp getIntf]; + + p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update; + p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + +#define p_input (p_intf->p_sys->p_input) + + if( p_intf->p_sys->b_program_update ) + { + NSMenu * o_program; + SEL pf_toggle_program; + pgrm_descriptor_t * p_pgrm; + + if( p_input->stream.p_new_program ) + { + p_pgrm = p_input->stream.p_new_program; + } + else + { + p_pgrm = p_input->stream.p_selected_program; + } + + o_program = [o_mi_program submenu]; + pf_toggle_program = @selector(toggleProgram:); + + /* remove previous program items */ + i_nb_items = [o_program numberOfItems]; + for( i = 0; i < i_nb_items; i++ ) + { + [o_program removeItemAtIndex: 0]; + } + + /* make (un)sensitive */ + [o_mi_program setEnabled: + p_input->stream.i_pgrm_number > 1]; + + /* add program items */ + for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ ) + { + snprintf( psz_title, sizeof(psz_title), "id %d", + p_input->stream.pp_programs[i]->i_number ); + psz_title[sizeof(psz_title) - 1] = '\0'; + + o_menu_title = [NSString stringWithCString: psz_title]; + + o_item = [o_program addItemWithTitle: o_menu_title + action: pf_toggle_program keyEquivalent: @""]; + [o_item setTag: p_input->stream.pp_programs[i]->i_number]; + [o_item setTarget: o_controls]; + + if( p_pgrm == p_input->stream.pp_programs[i] ) + { + [o_item setState: NSOnState]; + } + } + + p_intf->p_sys->b_program_update = 0; + } + + if( p_intf->p_sys->b_title_update ) + { + NSMenu * o_title; + SEL pf_toggle_title; + + o_title = [o_mi_title submenu]; + pf_toggle_title = @selector(toggleTitle:); + + /* remove previous title items */ + i_nb_items = [o_title numberOfItems]; + for( i = 0; i < i_nb_items; i++ ) + { + [o_title removeItemAtIndex: 0]; + } + + /* make (un)sensitive */ + [o_mi_title setEnabled: + p_input->stream.i_area_nb > 1]; + + /* add title items */ + for( i = 1 ; i < p_input->stream.i_area_nb ; i++ ) + { + snprintf( psz_title, sizeof(psz_title), "Title %d (%d)", i, + p_input->stream.pp_areas[i]->i_part_nb ); + psz_title[sizeof(psz_title) - 1] = '\0'; + + o_menu_title = [NSString stringWithCString: psz_title]; + + o_item = [o_title addItemWithTitle: o_menu_title + action: pf_toggle_title keyEquivalent: @""]; + [o_item setTag: i]; + [o_item setTarget: o_controls]; + + if( ( p_input->stream.pp_areas[i] == + p_input->stream.p_selected_area ) ) + { + [o_item setState: NSOnState]; + } + } + + p_intf->p_sys->b_title_update = 0; + } + + if( p_intf->p_sys->b_chapter_update ) + { + NSMenu * o_chapter; + SEL pf_toggle_chapter; + + o_chapter = [o_mi_chapter submenu]; + pf_toggle_chapter = @selector(toggleChapter:); + + /* remove previous chapter items */ + i_nb_items = [o_chapter numberOfItems]; + for( i = 0; i < i_nb_items; i++ ) + { + [o_chapter removeItemAtIndex: 0]; + } + + /* make (un)sensitive */ + [o_mi_chapter setEnabled: + p_input->stream.p_selected_area->i_part_nb > 1]; + + /* add chapter items */ + for( i = 0 ; i < p_input->stream.p_selected_area->i_part_nb ; i++ ) + { + snprintf( psz_title, sizeof(psz_title), "Chapter %d", i + 1 ); + psz_title[sizeof(psz_title) - 1] = '\0'; + + o_menu_title = [NSString stringWithCString: psz_title]; + + o_item = [o_chapter addItemWithTitle: o_menu_title + action: pf_toggle_chapter keyEquivalent: @""]; + [o_item setTag: i + 1]; + [o_item setTarget: o_controls]; + + if( ( p_input->stream.p_selected_area->i_part == i + 1 ) ) + { + [o_item setState: NSOnState]; + } + } + + p_intf->p_sys->i_part = + p_input->stream.p_selected_area->i_part; + + p_intf->p_sys->b_chapter_update = 0; + } + + for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ ) + { + if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES ) + { + p_audio_es = p_input->stream.pp_selected_es[i]; + } + else if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES ) + { + p_spu_es = p_input->stream.pp_selected_es[i]; + } + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + if( p_intf->p_sys->b_audio_update ) + { + [self setupLangMenu: o_mi_language es: p_audio_es + category: AUDIO_ES selector: @selector(toggleLanguage:)]; + + p_intf->p_sys->b_audio_update = 0; + } + + if( p_intf->p_sys->b_spu_update ) + { + [self setupLangMenu: o_mi_subtitle es: p_spu_es + category: SPU_ES selector: @selector(toggleLanguage:)]; + + p_intf->p_sys->b_spu_update = 0; + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + +#undef p_input +} + +- (void)setupLangMenu:(NSMenuItem *)o_mi + es:(es_descriptor_t *)p_es + category:(int)i_cat + selector:(SEL)pf_callback +{ + int i, i_nb_items; + NSMenu * o_menu = [o_mi submenu]; + intf_thread_t * p_intf = [NSApp getIntf]; + + /* remove previous language items */ + i_nb_items = [o_menu numberOfItems]; + for( i = 0; i < i_nb_items; i++ ) + { + [o_menu removeItemAtIndex: 0]; + } + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + +#define ES p_intf->p_sys->p_input->stream.pp_es[i] + for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ ) + { + if( ( ES->i_cat == i_cat ) && + ( !ES->p_pgrm || + ES->p_pgrm == + p_intf->p_sys->p_input->stream.p_selected_program ) ) + { + NSMenuItem * o_lmi; + NSString * o_title; + + if( *ES->psz_desc ) + { + o_title = [NSString stringWithCString: ES->psz_desc]; + } + else + { + char psz_title[ 256 ]; + + snprintf( psz_title, sizeof(psz_title), "Language 0x%x", + ES->i_id ); + psz_title[sizeof(psz_title) - 1] = '\0'; + + o_title = [NSString stringWithCString: psz_title]; + } + + o_lmi = [o_menu addItemWithTitle: o_title + action: pf_callback keyEquivalent: @""]; + [o_lmi setRepresentedObject: + [NSValue valueWithPointer: ES]]; + [o_lmi setTarget: o_controls]; + [o_lmi setTag: i_cat]; + + if( /*p_es == ES*/ ES->p_decoder_fifo != NULL ) + { + [o_lmi setState: NSOnState]; + } + } + } +#undef ES + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + + /* make (un)sensitive */ + [o_mi setEnabled: + [o_menu numberOfItems] ? TRUE : FALSE]; +} + +- (IBAction)clearRecentItems:(id)sender +{ + [[NSDocumentController sharedDocumentController] + clearRecentDocuments: nil]; +} + +- (void)openRecentItem:(id)sender +{ + [self application: nil openFile: [sender title]]; +} + +@end + +@implementation VLCMain (NSMenuValidation) + +- (BOOL)validateMenuItem:(NSMenuItem *)o_mi +{ + BOOL bEnabled = TRUE; + + /* Recent Items Menu */ + + if( [[o_mi title] isEqualToString: _NS("Clear Menu")] ) + { + NSMenu * o_menu = [o_mi_open_recent submenu]; + int i_nb_items = [o_menu numberOfItems]; + NSArray * o_docs = [[NSDocumentController sharedDocumentController] + recentDocumentURLs]; + UInt32 i_nb_docs = [o_docs count]; + + if( i_nb_items > 1 ) + { + while( --i_nb_items ) + { + [o_menu removeItemAtIndex: 0]; + } + } + + if( i_nb_docs > 0 ) + { + NSURL * o_url; + NSString * o_doc; + + [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0]; + + while( TRUE ) + { + i_nb_docs--; + + o_url = [o_docs objectAtIndex: i_nb_docs]; + + if( [o_url isFileURL] ) + { + o_doc = [o_url path]; + } + else + { + o_doc = [o_url absoluteString]; + } + + [o_menu insertItemWithTitle: o_doc + action: @selector(openRecentItem:) + keyEquivalent: @"" atIndex: 0]; + + if( i_nb_docs == 0 ) + { + break; + } + } + } + else + { + bEnabled = FALSE; + } + } + + return( bEnabled ); +} + +@end + +@implementation VLCMain (Internal) + +- (void)handlePortMessage:(NSPortMessage *)o_msg +{ + NSData * o_req; + vout_req_t * p_req; + + o_req = [[o_msg components] lastObject]; + p_req = *((vout_req_t **)[o_req bytes]); + + [p_req->o_lock lock]; + + if( p_req->i_type == VOUT_REQ_CREATE_WINDOW ) + { + VLCView * o_view; + + p_req->p_vout->p_sys->o_window = [VLCWindow alloc]; + [p_req->p_vout->p_sys->o_window setVout: p_req->p_vout]; + [p_req->p_vout->p_sys->o_window setReleasedWhenClosed: YES]; + + if( p_req->p_vout->b_fullscreen ) + { + [p_req->p_vout->p_sys->o_window + initWithContentRect: [[NSScreen mainScreen] frame] + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreBuffered + defer: NO screen: [NSScreen mainScreen]]; + + [p_req->p_vout->p_sys->o_window + setLevel: NSModalPanelWindowLevel]; + } + else + { + unsigned int i_stylemask = NSTitledWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask; + + [p_req->p_vout->p_sys->o_window + initWithContentRect: p_req->p_vout->p_sys->s_rect + styleMask: i_stylemask + backing: NSBackingStoreBuffered + defer: NO screen: [NSScreen mainScreen]]; + + if( !p_req->p_vout->p_sys->b_pos_saved ) + { + [p_req->p_vout->p_sys->o_window center]; + } + } + + o_view = [[VLCView alloc] init]; + [o_view setVout: p_req->p_vout]; + [o_view setMenu: o_mu_controls]; + [p_req->p_vout->p_sys->o_window setContentView: o_view]; + [o_view autorelease]; + + [o_view lockFocus]; + p_req->p_vout->p_sys->p_qdport = [o_view qdPort]; + [o_view unlockFocus]; + + [p_req->p_vout->p_sys->o_window setTitle: [NSString + stringWithCString: VOUT_TITLE " (QuickTime)"]]; + [p_req->p_vout->p_sys->o_window setAcceptsMouseMovedEvents: YES]; + [p_req->p_vout->p_sys->o_window makeKeyAndOrderFront: nil]; + + p_req->i_result = 1; + } + else if( p_req->i_type == VOUT_REQ_DESTROY_WINDOW ) + { + if( !p_req->p_vout->b_fullscreen ) + { + NSRect s_rect; + + s_rect = [[p_req->p_vout->p_sys->o_window contentView] frame]; + p_req->p_vout->p_sys->s_rect.size = s_rect.size; + + s_rect = [p_req->p_vout->p_sys->o_window frame]; + p_req->p_vout->p_sys->s_rect.origin = s_rect.origin; + + p_req->p_vout->p_sys->b_pos_saved = 1; + } + + p_req->p_vout->p_sys->p_qdport = nil; + [p_req->p_vout->p_sys->o_window close]; + p_req->p_vout->p_sys->o_window = nil; + + p_req->i_result = 1; + } + + [p_req->o_lock unlockWithCondition: 1]; +} + +@end + diff --git a/modules/gui/macosx/macosx.m b/modules/gui/macosx/macosx.m new file mode 100644 index 0000000000..afb59a743b --- /dev/null +++ b/modules/gui/macosx/macosx.m @@ -0,0 +1,62 @@ +/***************************************************************************** + * macosx.m: MacOS X plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: macosx.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Colin Delacroix + * Eugenio Jarosiewicz + * Florian G. Pflug + * Jon Lech Johansen + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t * ); +void E_(CloseIntf) ( vlc_object_t * ); + +int E_(OpenAudio) ( vlc_object_t * ); +void E_(CloseAudio) ( vlc_object_t * ); + +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("MacOS X interface, sound and video module") ); + add_submodule(); + set_capability( "interface", 100 ); + set_callbacks( E_(OpenIntf), E_(CloseIntf) ); + add_submodule(); + set_capability( "video output", 100 ); + set_callbacks( E_(OpenVideo), E_(CloseVideo) ); + add_submodule(); + set_capability( "audio output", 100 ); + set_callbacks( E_(OpenAudio), E_(CloseAudio) ); +vlc_module_end(); + diff --git a/modules/gui/macosx/open.h b/modules/gui/macosx/open.h new file mode 100644 index 0000000000..cb6df0d433 --- /dev/null +++ b/modules/gui/macosx/open.h @@ -0,0 +1,73 @@ +/***************************************************************************** + * open.h: MacOS X plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: open.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * + * 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. + *****************************************************************************/ + +NSArray *GetEjectableMediaOfClass( const char *psz_class ); + +/***************************************************************************** + * Intf_Open interface + *****************************************************************************/ +@interface VLCOpen : NSObject +{ + IBOutlet id o_playlist; + + IBOutlet id o_disc_panel; + IBOutlet id o_disc_btn_ok; + IBOutlet id o_disc_btn_cancel; + IBOutlet id o_disc_lbl_type; + IBOutlet id o_disc_lbl_sp; + IBOutlet id o_disc_type; + IBOutlet id o_disc_title; + IBOutlet id o_disc_chapter; + IBOutlet id o_disc_device; + + IBOutlet id o_net_panel; + IBOutlet id o_net_btn_ok; + IBOutlet id o_net_btn_cancel; + IBOutlet id o_net_box_mode; + IBOutlet id o_net_box_addr; + IBOutlet id o_net_mode; + IBOutlet id o_net_address; + IBOutlet id o_net_port; + IBOutlet id o_net_port_lbl; + IBOutlet id o_net_port_stp; + + IBOutlet id o_quickly_panel; + IBOutlet id o_quickly_btn_ok; + IBOutlet id o_quickly_btn_cancel; + IBOutlet id o_quickly_source; +} + +- (IBAction)openFile:(id)sender; + +- (IBAction)openDisc:(id)sender; +- (IBAction)openDiscTypeChanged:(id)sender; + +- (IBAction)openNet:(id)sender; +- (IBAction)openNetModeChanged:(id)sender; + +- (IBAction)openQuickly:(id)sender; + +- (IBAction)panelCancel:(id)sender; +- (IBAction)panelOk:(id)sender; + +@end diff --git a/modules/gui/macosx/open.m b/modules/gui/macosx/open.m new file mode 100644 index 0000000000..d8dd38d60d --- /dev/null +++ b/modules/gui/macosx/open.m @@ -0,0 +1,382 @@ +/***************************************************************************** + * open.m: MacOS X plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: open.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * + * 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 /* malloc(), free() */ +#include /* for MAXPATHLEN */ +#include + +#include +#include +#include +#include +#include +#include + +#import + +#include +#include + +#include "netutils.h" + +#import "intf.h" +#import "playlist.h" +#import "intf_open.h" + +/***************************************************************************** + * GetEjectableMediaOfClass + *****************************************************************************/ +NSArray *GetEjectableMediaOfClass( const char *psz_class ) +{ + io_object_t next_media; + mach_port_t master_port; + kern_return_t kern_result; + NSArray *o_devices = nil; + NSMutableArray *p_list = nil; + io_iterator_t media_iterator; + CFMutableDictionaryRef classes_to_match; + + kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + classes_to_match = IOServiceMatching( psz_class ); + if( classes_to_match == NULL ) + { + return( nil ); + } + + CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectable ), + kCFBooleanTrue ); + + kern_result = IOServiceGetMatchingServices( master_port, classes_to_match, + &media_iterator ); + if( kern_result != KERN_SUCCESS ) + { + return( nil ); + } + + p_list = [NSMutableArray arrayWithCapacity: 1]; + + next_media = IOIteratorNext( media_iterator ); + if( next_media != NULL ) + { + char psz_buf[0x32]; + size_t dev_path_length; + CFTypeRef str_bsd_path; + + do + { + str_bsd_path = IORegistryEntryCreateCFProperty( next_media, + CFSTR( kIOBSDName ), + kCFAllocatorDefault, + 0 ); + if( str_bsd_path == NULL ) + { + IOObjectRelease( next_media ); + continue; + } + + snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' ); + dev_path_length = strlen( psz_buf ); + + if( CFStringGetCString( str_bsd_path, + (char*)&psz_buf + dev_path_length, + sizeof(psz_buf) - dev_path_length, + kCFStringEncodingASCII ) ) + { + [p_list addObject: [NSString stringWithCString: psz_buf]]; + } + + CFRelease( str_bsd_path ); + + IOObjectRelease( next_media ); + + } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL ); + } + + IOObjectRelease( media_iterator ); + + o_devices = [NSArray arrayWithArray: p_list]; + + return( o_devices ); +} + +/***************************************************************************** + * VLCOpen implementation + *****************************************************************************/ +@implementation VLCOpen + +- (void)awakeFromNib +{ + [o_disc_panel setTitle: _NS("Open Disc")]; + [o_disc_btn_ok setTitle: _NS("OK")]; + [o_disc_btn_cancel setTitle: _NS("Cancel")]; + [o_disc_lbl_type setTitle: _NS("Disc type")]; + [o_disc_lbl_sp setTitle: _NS("Starting position")]; + [o_disc_title setTitle: _NS("Title")]; + [o_disc_chapter setTitle: _NS("Chapter")]; + + [o_net_panel setTitle: _NS("Open Network")]; + [o_net_box_mode setTitle: _NS("Network mode")]; + [o_net_box_addr setTitle: _NS("Address")]; + [o_net_port_lbl setStringValue: _NS("Port")]; + + [o_quickly_panel setTitle: _NS("Open Quickly")]; + [o_quickly_btn_ok setTitle: _NS("OK")]; + [o_quickly_btn_cancel setTitle: _NS("Cancel")]; +} + +- (IBAction)openDisc:(id)sender +{ + int i_result; + + [self openDiscTypeChanged: nil]; + + [o_disc_panel makeKeyAndOrderFront: self]; + i_result = [NSApp runModalForWindow: o_disc_panel]; + [o_disc_panel close]; + + if( i_result ) + { + NSString *o_source; + + NSString *o_type = [[o_disc_type selectedCell] title]; + NSString *o_device = [o_disc_device stringValue]; + int i_title = [o_disc_title intValue]; + int i_chapter = [o_disc_chapter intValue]; + + o_source = [NSString stringWithFormat: @"%@:%@@%d,%d", + [o_type lowercaseString], o_device, i_title, i_chapter]; + + [o_playlist appendArray: + [NSArray arrayWithObject: o_source] atPos: -1]; + } +} + +- (IBAction)openDiscTypeChanged:(id)sender +{ + NSString *o_type; + NSArray *o_devices; + const char *psz_class = NULL; + + [o_disc_device removeAllItems]; + + o_type = [[o_disc_type selectedCell] title]; + + if( [o_type isEqualToString: @"DVD"] ) + { + psz_class = kIODVDMediaClass; + } + else + { + psz_class = kIOCDMediaClass; + } + + o_devices = GetEjectableMediaOfClass( psz_class ); + if( o_devices != nil ) + { + int i_devices = [o_devices count]; + + if( i_devices ) + { + int i; + + for( i = 0; i < i_devices; i++ ) + { + [o_disc_device + addItemWithObjectValue: [o_devices objectAtIndex: i]]; + } + + [o_disc_device selectItemAtIndex: 0]; + [o_disc_btn_ok setEnabled: TRUE]; + } + else + { + [o_disc_device setStringValue: + [NSString stringWithFormat: @"No %@s found", o_type]]; + [o_disc_btn_ok setEnabled: FALSE]; + } + } +} + +- (IBAction)openFile:(id)sender +{ + NSOpenPanel *o_panel = [NSOpenPanel openPanel]; + + [o_panel setAllowsMultipleSelection: YES]; + + if( [o_panel runModalForDirectory: nil + file: nil types: nil] == NSOKButton ) + { + [o_playlist appendArray: [o_panel filenames] atPos: -1]; + } +} + +- (IBAction)openNet:(id)sender +{ + int i_result; + intf_thread_t * p_intf = [NSApp getIntf]; + + [o_net_panel makeKeyAndOrderFront: self]; + i_result = [NSApp runModalForWindow: o_net_panel]; + [o_net_panel close]; + + if( i_result ) + { + NSString * o_source = nil; + UInt32 i_port = [o_net_port intValue]; + NSString * o_addr = [o_net_address stringValue]; + NSString * o_mode = [[o_net_mode selectedCell] title]; + + if( i_port > 65536 ) + { + NSBeep(); + return; + } + + if( [o_mode isEqualToString: @"UDP"] ) + { + o_source = [NSString + stringWithFormat: @"udp:@:%i", i_port]; + } + else if( [o_mode isEqualToString: @"UDP Multicase"] ) + { + o_source = [NSString + stringWithFormat: @"udp:@%@:%i", o_addr, i_port]; + } + else if( [o_mode isEqualToString: @"Channel server"] ) + { + if( p_intf->p_vlc->p_channel == NULL ) + { + network_ChannelCreate( p_intf ); + } + + config_PutPsz( p_intf, "channel-server", + (char *)[o_addr lossyCString] ); + config_PutInt( p_intf, "channel-port", i_port ); + + p_intf->p_sys->b_playing = 1; + } + else if( [o_mode isEqualToString: @"HTTP"] ) + { + o_source = o_addr; + } + + if( o_source != nil ) + { + [o_playlist appendArray: + [NSArray arrayWithObject: o_source] atPos: -1]; + } + } +} + +- (IBAction)openNetModeChanged:(id)sender +{ + NSString * o_mode; + SInt32 i_port = 1234; + NSString * o_addr = nil; + + o_mode = [[o_net_mode selectedCell] title]; + + if( [o_mode isEqualToString: @"UDP Multicast"] ) + { + o_addr = @""; + } + else if( [o_mode isEqualToString: @"Channel server"] ) + { + o_addr = @"localhost"; + i_port = 6010; + } + else if( [o_mode isEqualToString: @"HTTP"] ) + { + o_addr = @"http://"; + i_port = -1; + } + + if( o_addr != nil ) + { + [o_net_address setEnabled: TRUE]; + [o_net_address setStringValue: o_addr]; + } + else + { + [o_net_address setEnabled: FALSE]; + } + + if( i_port > -1 ) + { + [o_net_port setEnabled: TRUE]; + [o_net_port_stp setEnabled: TRUE]; + [o_net_port setIntValue: i_port]; + } + else + { + [o_net_port setEnabled: FALSE]; + [o_net_port_stp setEnabled: FALSE]; + } +} + +- (IBAction)openQuickly:(id)sender +{ + int i_result; + + [o_quickly_source setStringValue: @""]; + [o_quickly_panel makeKeyAndOrderFront: self]; + i_result = [NSApp runModalForWindow: o_quickly_panel]; + [o_quickly_panel close]; + + if( i_result ) + { + NSString * o_source; + + o_source = [o_quickly_source stringValue]; + + if( [o_source length] > 0 ) + { + [o_playlist appendArray: + [NSArray arrayWithObject: o_source] atPos: -1]; + } + else + { + NSBeep(); + } + } +} + +- (IBAction)panelCancel:(id)sender +{ + [NSApp stopModalWithCode: 0]; +} + +- (IBAction)panelOk:(id)sender +{ + [NSApp stopModalWithCode: 1]; +} + +@end diff --git a/modules/gui/macosx/playlist.h b/modules/gui/macosx/playlist.h new file mode 100644 index 0000000000..adbf1f222a --- /dev/null +++ b/modules/gui/macosx/playlist.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * playlist.h: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: playlist.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * VLCPlaylistView interface + *****************************************************************************/ +@interface VLCPlaylistView : NSTableView +{ + +} + +@end + +/***************************************************************************** + * VLCPlaylist interface + *****************************************************************************/ +@interface VLCPlaylist : NSObject +{ + IBOutlet id o_panel; + IBOutlet id o_btn_close; + IBOutlet id o_table_view; +} + +- (void)appendArray:(NSArray*)o_array atPos:(int)i_pos; + +@end + diff --git a/modules/gui/macosx/playlist.m b/modules/gui/macosx/playlist.m new file mode 100644 index 0000000000..d290a41d90 --- /dev/null +++ b/modules/gui/macosx/playlist.m @@ -0,0 +1,246 @@ +/***************************************************************************** + * playlist.m: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: playlist.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Jon Lech Johansen + * + * 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 /* malloc(), free() */ +#include /* for MAXPATHLEN */ +#include + +#include +#include + +#include + +#include "intf.h" +#include "playlist.h" + +/***************************************************************************** + * VLCPlaylistView implementation + *****************************************************************************/ +@implementation VLCPlaylistView + +- (NSMenu *)menuForEvent:(NSEvent *)o_event +{ + /* TODO */ + + return( nil ); +} + +@end + +/***************************************************************************** + * VLCPlaylist implementation + *****************************************************************************/ +@implementation VLCPlaylist + +- (void)awakeFromNib +{ + [o_table_view setTarget: self]; + [o_table_view setDelegate: self]; + [o_table_view setDataSource: self]; + + [o_table_view setDoubleAction: @selector(doubleClick:)]; + + [o_table_view registerForDraggedTypes: + [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; + + [o_panel setTitle: _NS("Playlist")]; + [o_btn_close setTitle: _NS("Close")]; +} + +- (BOOL)tableView:(NSTableView *)o_tv + shouldEditTableColumn:(NSTableColumn *)o_tc + row:(int)i_row +{ + return( NO ); +} + +- (NSDragOperation)tableView:(NSTableView*)o_tv + validateDrop:(id )info + proposedRow:(int)i_row + proposedDropOperation:(NSTableViewDropOperation)operation +{ + return( NSDragOperationPrivate ); +} + +- (BOOL)tableView:(NSTableView*)o_tv + acceptDrop:(id )info + row:(int)i_row + dropOperation:(NSTableViewDropOperation)operation +{ + NSArray * o_values; + NSPasteboard * o_pasteboard; + + o_pasteboard = [info draggingPasteboard]; + + if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] ) + { + o_values = [o_pasteboard propertyListForType: NSFilenamesPboardType]; + + [self appendArray: o_values atPos: i_row]; + + if( i_row != -1 ) + { + [o_table_view reloadData]; + } + + return( YES ); + } + + return( NO ); +} + +- (void)tableView:(NSTableView *)o_tv willDisplayCell:(id)o_cell + forTableColumn:(NSTableColumn *)o_tc row:(int)i_row +{ + [o_cell setDrawsBackground: YES]; + + if( i_row % 2 ) + { + [o_cell setBackgroundColor: + [NSColor colorWithDeviceRed: 0.937255 + green: 0.968627 + blue: 1.0 + alpha: 1.0]]; + } + else + { + [o_cell setBackgroundColor: [NSColor whiteColor]]; + } +} + +- (IBAction)doubleClick:(id)sender +{ + NSTableView * o_tv = sender; + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } + + playlist_Goto( p_playlist, [o_tv clickedRow] ); + + vlc_object_release( p_playlist ); +} + +- (void)appendArray:(NSArray*)o_array atPos:(int)i_pos +{ + int i_items; + NSString * o_value; + NSEnumerator * o_enum; + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } + + if( p_intf->p_sys->b_loop ) + { + playlist_Delete( p_playlist, p_playlist->i_size - 1 ); + } + + i_items = 0; + o_enum = [o_array objectEnumerator]; + while( ( o_value = [o_enum nextObject] ) ) + { + NSURL * o_url; + + int i_mode = i_items == 0 ? PLAYLIST_INSERT | PLAYLIST_GO : + PLAYLIST_INSERT; + + playlist_Add( p_playlist, [o_value fileSystemRepresentation], + i_mode, i_pos == -1 ? PLAYLIST_END : i_pos + i_items ); + + o_url = [NSURL fileURLWithPath: o_value]; + if( o_url != nil ) + { + [[NSDocumentController sharedDocumentController] + noteNewRecentDocumentURL: o_url]; + } + + i_items++; + } + + if( p_intf->p_sys->b_loop ) + { + playlist_Add( p_playlist, "vlc:loop", + PLAYLIST_APPEND, PLAYLIST_END ); + } + + vlc_object_release( p_playlist ); +} + +@end + +@implementation VLCPlaylist (NSTableDataSource) + +- (int)numberOfRowsInTableView:(NSTableView *)o_tv +{ + int i_count = 0; + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist != NULL ) + { + i_count = p_playlist->i_size; + vlc_object_release( p_playlist ); + } + + return( i_count ); +} + +- (id)tableView:(NSTableView *)o_tv + objectValueForTableColumn:(NSTableColumn *)o_tc + row:(int)i_row +{ + id o_value = nil; + intf_thread_t * p_intf = [NSApp getIntf]; + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return( nil ); + } + + vlc_mutex_lock( &p_playlist->object_lock ); + o_value = [NSString stringWithCString: + p_playlist->pp_items[i_row]->psz_name]; + vlc_mutex_unlock( &p_playlist->object_lock ); + + vlc_object_release( p_playlist ); + + return( o_value ); +} + +@end + diff --git a/modules/gui/macosx/vout.h b/modules/gui/macosx/vout.h new file mode 100644 index 0000000000..2e072b6a47 --- /dev/null +++ b/modules/gui/macosx/vout.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * vout.h: MacOS X interface plugin + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: vout.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Colin Delacroix + * Florian G. Pflug + * Jon Lech Johansen + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * VLCWindow interface + *****************************************************************************/ +@interface VLCWindow : NSWindow +{ + vout_thread_t * p_vout; +} + +- (void)setVout:(vout_thread_t *)_p_vout; + +- (void)toggleFullscreen; +- (BOOL)isFullscreen; + +@end + +/***************************************************************************** + * VLCView interface + *****************************************************************************/ +@interface VLCView : NSQuickDrawView +{ + vout_thread_t * p_vout; +} + +- (void)setVout:(vout_thread_t *)_p_vout; + +@end + +/***************************************************************************** + * vout_sys_t: MacOS X video output method descriptor + *****************************************************************************/ +struct vout_sys_t +{ + intf_thread_t * p_intf; + VLCWindow * o_window; + + NSRect s_rect; + int b_pos_saved; + + vlc_bool_t b_mouse_moved; + vlc_bool_t b_mouse_pointer_visible; + mtime_t i_time_mouse_last_moved; + +#ifdef __QUICKTIME__ + CodecType i_codec; + CGrafPtr p_qdport; + ImageSequence i_seq; + MatrixRecordPtr p_matrix; + DecompressorComponent img_dc; + ImageDescriptionHandle h_img_descr; +#endif +}; + +/***************************************************************************** + * vout_req_t: MacOS X video output request + *****************************************************************************/ +#define VOUT_REQ_CREATE_WINDOW 0x00000001 +#define VOUT_REQ_DESTROY_WINDOW 0x00000002 + +typedef struct vout_req_t +{ + int i_type; + int i_result; + + NSConditionLock * o_lock; + + vout_thread_t * p_vout; +} vout_req_t; diff --git a/modules/gui/macosx/vout.m b/modules/gui/macosx/vout.m new file mode 100644 index 0000000000..e39ea9c965 --- /dev/null +++ b/modules/gui/macosx/vout.m @@ -0,0 +1,800 @@ +/***************************************************************************** + * vout.m: MacOS X video output plugin + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: vout.m,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Colin Delacroix + * Florian G. Pflug + * Jon Lech Johansen + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include +#include + +#include +#include + +#include "intf.h" +#include "vout.h" + +#define QT_MAX_DIRECTBUFFERS 10 + +struct picture_sys_t +{ + void *p_info; + unsigned int i_size; + + /* When using I420 output */ + PlanarPixmapInfoYUV420 pixmap_i420; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int vout_Init ( vout_thread_t * ); +static void vout_End ( vout_thread_t * ); +static int vout_Manage ( vout_thread_t * ); +static void vout_Render ( vout_thread_t *, picture_t * ); +static void vout_Display ( vout_thread_t *, picture_t * ); + +static int CoSendRequest ( vout_thread_t *, long ); +static int CoCreateWindow ( vout_thread_t * ); +static int CoDestroyWindow ( vout_thread_t * ); +static int CoToggleFullscreen ( vout_thread_t * ); + +static void QTScaleMatrix ( vout_thread_t * ); +static int QTCreateSequence ( vout_thread_t * ); +static void QTDestroySequence ( vout_thread_t * ); +static int QTNewPicture ( vout_thread_t *, picture_t * ); +static void QTFreePicture ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * OpenVideo: allocates MacOS X video thread output method + ***************************************************************************** + * This function allocates and initializes a MacOS X vout method. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + OSErr err; + + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) ); + + p_vout->p_sys->p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_vout->p_sys->p_intf == NULL ) + { + msg_Err( p_vout, "no interface present" ); + free( p_vout->p_sys ); + return( 1 ); + } + + if( p_vout->p_sys->p_intf->p_module == NULL || + strcmp( p_vout->p_sys->p_intf->p_module->psz_object_name, + MODULE_STRING ) != 0 ) + { + msg_Err( p_vout, "MacOS X interface module required" ); + vlc_object_release( p_vout->p_sys->p_intf ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->p_sys->h_img_descr = + (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) ); + p_vout->p_sys->p_matrix = (MatrixRecordPtr)malloc( sizeof(MatrixRecord) ); + + p_vout->p_sys->b_mouse_pointer_visible = 1; + + /* set window size */ + p_vout->p_sys->s_rect.size.width = p_vout->i_window_width; + p_vout->p_sys->s_rect.size.height = p_vout->i_window_height; + + if( ( err = EnterMovies() ) != noErr ) + { + msg_Err( p_vout, "EnterMovies failed: %d", err ); + free( p_vout->p_sys->p_matrix ); + DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); + free( p_vout->p_sys ); + return( 1 ); + } + + if( vout_ChromaCmp( p_vout->render.i_chroma, VLC_FOURCC('I','4','2','0') ) ) + { + err = FindCodec( kYUV420CodecType, bestSpeedCodec, + nil, &p_vout->p_sys->img_dc ); + if( err == noErr && p_vout->p_sys->img_dc != 0 ) + { + p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0'); + p_vout->p_sys->i_codec = kYUV420CodecType; + } + else + { + msg_Err( p_vout, "failed to find an appropriate codec" ); + } + } + else + { + msg_Err( p_vout, "chroma 0x%08x not supported", + p_vout->render.i_chroma ); + } + + if( p_vout->p_sys->img_dc == 0 ) + { + free( p_vout->p_sys->p_matrix ); + DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); + free( p_vout->p_sys ); + return( 1 ); + } + + if( CoCreateWindow( p_vout ) ) + { + msg_Err( p_vout, "unable to create window" ); + free( p_vout->p_sys->p_matrix ); + DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->pf_init = vout_Init; + p_vout->pf_end = vout_End; + p_vout->pf_manage = vout_Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = vout_Display; + + return( 0 ); +} + +/***************************************************************************** + * vout_Init: initialize video thread output method + *****************************************************************************/ +static int vout_Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure; we already found a codec, + * and the corresponding chroma we will be using. Since we can + * arbitrary scale, stick to the coordinates and aspect. */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + SetPort( p_vout->p_sys->p_qdport ); + QTScaleMatrix( p_vout ); + + if( QTCreateSequence( p_vout ) ) + { + msg_Err( p_vout, "unable to create sequence" ); + return( 1 ); + } + + /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * vout_End: terminate video thread output method + *****************************************************************************/ +static void vout_End( vout_thread_t *p_vout ) +{ + int i_index; + + QTDestroySequence( p_vout ); + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES; i_index; ) + { + i_index--; + QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); + } +} + +/***************************************************************************** + * CloseVideo: destroy video thread output method + *****************************************************************************/ +void E_(CloseVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + if( CoDestroyWindow( p_vout ) ) + { + msg_Err( p_vout, "unable to destroy window" ); + } + + ExitMovies(); + + free( p_vout->p_sys->p_matrix ); + DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); + + vlc_object_release( p_vout->p_sys->p_intf ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * vout_Manage: handle events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int vout_Manage( vout_thread_t *p_vout ) +{ + if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + if( CoToggleFullscreen( p_vout ) ) + { + return( 1 ); + } + + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + } + + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + QTScaleMatrix( p_vout ); + SetDSequenceMatrix( p_vout->p_sys->i_seq, + p_vout->p_sys->p_matrix ); + + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + } + + /* hide/show mouse cursor */ + if( p_vout->p_sys->b_mouse_moved || + p_vout->p_sys->i_time_mouse_last_moved ) + { + vlc_bool_t b_change = 0; + + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + CGDisplayShowCursor( kCGDirectMainDisplay ); + b_change = 1; + } +#if 0 + else if( !p_vout->p_sys->b_mouse_moved && + mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 && + p_vout->p_sys->b_mouse_pointer_visible ) + { + CGDisplayHideCursor( kCGDirectMainDisplay ); + b_change = 1; + } +#endif + + if( b_change ) + { + p_vout->p_sys->i_time_mouse_last_moved = 0; + p_vout->p_sys->b_mouse_moved = 0; + p_vout->p_sys->b_mouse_pointer_visible = + !p_vout->p_sys->b_mouse_pointer_visible; + } + } + + return( 0 ); +} + +/***************************************************************************** + * vout_Display: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to the display. + *****************************************************************************/ +static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + OSErr err; + CodecFlags flags; + + if( ( err = DecompressSequenceFrameS( + p_vout->p_sys->i_seq, + p_pic->p_sys->p_info, + p_pic->p_sys->i_size, + codecFlagUseImageBuffer, &flags, nil ) != noErr ) ) + { + msg_Err( p_vout, "DecompressSequenceFrameS failed: %d", err ); + } + else + { + QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil ); + } +} + +/***************************************************************************** + * CoSendRequest: send request to interface thread + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int CoSendRequest( vout_thread_t *p_vout, long i_request ) +{ + NSArray *o_array; + NSPortMessage *o_msg; + struct vout_req_t req; + struct vout_req_t *p_req = &req; + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; + NSPort *recvPort = [[NSPort port] retain]; + + memset( &req, 0, sizeof(req) ); + req.i_type = i_request; + req.p_vout = p_vout; + + req.o_lock = [[NSConditionLock alloc] initWithCondition: 0]; + + o_array = [NSArray arrayWithObject: + [NSData dataWithBytes: &p_req length: sizeof(void *)]]; + o_msg = [[NSPortMessage alloc] + initWithSendPort: p_vout->p_sys->p_intf->p_sys->o_sendport + receivePort: recvPort components: o_array]; + + [o_msg sendBeforeDate: [NSDate distantPast]]; + + [req.o_lock lockWhenCondition: 1]; + [req.o_lock unlock]; + + [o_msg release]; + [req.o_lock release]; + + [recvPort release]; + [o_pool release]; + + return( !req.i_result ); +} + +/***************************************************************************** + * CoCreateWindow: create new window + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int CoCreateWindow( vout_thread_t *p_vout ) +{ + if( CoSendRequest( p_vout, VOUT_REQ_CREATE_WINDOW ) ) + { + msg_Err( p_vout, "CoSendRequest (CREATE_WINDOW) failed" ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * CoDestroyWindow: destroy window + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int CoDestroyWindow( vout_thread_t *p_vout ) +{ + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + CGDisplayShowCursor( kCGDirectMainDisplay ); + p_vout->p_sys->b_mouse_pointer_visible = 1; + } + + if( CoSendRequest( p_vout, VOUT_REQ_DESTROY_WINDOW ) ) + { + msg_Err( p_vout, "CoSendRequest (DESTROY_WINDOW) failed" ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * CoToggleFullscreen: toggle fullscreen + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int CoToggleFullscreen( vout_thread_t *p_vout ) +{ + QTDestroySequence( p_vout ); + + if( CoDestroyWindow( p_vout ) ) + { + msg_Err( p_vout, "unable to destroy window" ); + return( 1 ); + } + + p_vout->b_fullscreen = !p_vout->b_fullscreen; + + if( p_vout->b_fullscreen ) + { + HideMenuBar(); + } + else + { + ShowMenuBar(); + } + + if( CoCreateWindow( p_vout ) ) + { + msg_Err( p_vout, "unable to create window" ); + return( 1 ); + } + + SetPort( p_vout->p_sys->p_qdport ); + QTScaleMatrix( p_vout ); + + if( QTCreateSequence( p_vout ) ) + { + msg_Err( p_vout, "unable to create sequence" ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * QTScaleMatrix: scale matrix + *****************************************************************************/ +static void QTScaleMatrix( vout_thread_t *p_vout ) +{ + Rect s_rect; + int i_width, i_height; + Fixed factor_x, factor_y; + int i_offset_x = 0; + int i_offset_y = 0; + + GetPortBounds( p_vout->p_sys->p_qdport, &s_rect ); + + i_width = s_rect.right - s_rect.left; + i_height = s_rect.bottom - s_rect.top; + + if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR ) + { + int i_adj_width = i_height * p_vout->output.i_aspect / + VOUT_ASPECT_FACTOR; + + factor_x = FixDiv( Long2Fix( i_adj_width ), + Long2Fix( p_vout->output.i_width ) ); + factor_y = FixDiv( Long2Fix( i_height ), + Long2Fix( p_vout->output.i_height ) ); + + i_offset_x = (i_width - i_adj_width) / 2; + } + else + { + int i_adj_height = i_width * VOUT_ASPECT_FACTOR / + p_vout->output.i_aspect; + + factor_x = FixDiv( Long2Fix( i_width ), + Long2Fix( p_vout->output.i_width ) ); + factor_y = FixDiv( Long2Fix( i_adj_height ), + Long2Fix( p_vout->output.i_height ) ); + + i_offset_y = (i_height - i_adj_height) / 2; + } + + SetIdentityMatrix( p_vout->p_sys->p_matrix ); + + ScaleMatrix( p_vout->p_sys->p_matrix, + factor_x, factor_y, + Long2Fix(0), Long2Fix(0) ); + + TranslateMatrix( p_vout->p_sys->p_matrix, + Long2Fix(i_offset_x), + Long2Fix(i_offset_y) ); +} + +/***************************************************************************** + * QTCreateSequence: create a new sequence + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int QTCreateSequence( vout_thread_t *p_vout ) +{ + OSErr err; + ImageDescriptionPtr p_descr; + + HLock( (Handle)p_vout->p_sys->h_img_descr ); + p_descr = *p_vout->p_sys->h_img_descr; + + p_descr->idSize = sizeof(ImageDescription); + p_descr->cType = p_vout->p_sys->i_codec; + p_descr->version = 1; + p_descr->revisionLevel = 0; + p_descr->vendor = 'appl'; + p_descr->width = p_vout->output.i_width; + p_descr->height = p_vout->output.i_height; + p_descr->hRes = Long2Fix(72); + p_descr->vRes = Long2Fix(72); + p_descr->spatialQuality = codecLosslessQuality; + p_descr->frameCount = 1; + p_descr->clutID = -1; + p_descr->dataSize = 0; + p_descr->depth = 24; + + HUnlock( (Handle)p_vout->p_sys->h_img_descr ); + + if( ( err = DecompressSequenceBeginS( + &p_vout->p_sys->i_seq, + p_vout->p_sys->h_img_descr, + NULL, 0, + p_vout->p_sys->p_qdport, + NULL, NULL, + p_vout->p_sys->p_matrix, + 0, NULL, + codecFlagUseImageBuffer, + codecLosslessQuality, + p_vout->p_sys->img_dc ) ) ) + { + msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * QTDestroySequence: destroy sequence + *****************************************************************************/ +static void QTDestroySequence( vout_thread_t *p_vout ) +{ + CDSequenceEnd( p_vout->p_sys->i_seq ); +} + +/***************************************************************************** + * QTNewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, 1 otherwise + *****************************************************************************/ +static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + int i_width = p_vout->output.i_width; + int i_height = p_vout->output.i_height; + + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return( -1 ); + } + + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + + p_pic->p_sys->p_info = (void *)&p_pic->p_sys->pixmap_i420; + p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420); + + /* Allocate the memory buffer */ + p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, + 16, i_width * i_height * 3 / 2 ); + + /* Y buffer */ + p_pic->Y_PIXELS = p_pic->p_data; + p_pic->p[Y_PLANE].i_lines = i_height; + p_pic->p[Y_PLANE].i_pitch = i_width; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = i_width; + + /* U buffer */ + p_pic->U_PIXELS = p_pic->Y_PIXELS + i_height * i_width; + p_pic->p[U_PLANE].i_lines = i_height / 2; + p_pic->p[U_PLANE].i_pitch = i_width / 2; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = i_width / 2; + + /* V buffer */ + p_pic->V_PIXELS = p_pic->U_PIXELS + i_height * i_width / 4; + p_pic->p[V_PLANE].i_lines = i_height / 2; + p_pic->p[V_PLANE].i_pitch = i_width / 2; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = i_width / 2; + + /* We allocated 3 planes */ + p_pic->i_planes = 3; + +#define P p_pic->p_sys->pixmap_i420 + P.componentInfoY.offset = (void *)p_pic->Y_PIXELS + - p_pic->p_sys->p_info; + P.componentInfoCb.offset = (void *)p_pic->U_PIXELS + - p_pic->p_sys->p_info; + P.componentInfoCr.offset = (void *)p_pic->V_PIXELS + - p_pic->p_sys->p_info; + + P.componentInfoY.rowBytes = i_width; + P.componentInfoCb.rowBytes = i_width / 2; + P.componentInfoCr.rowBytes = i_width / 2; +#undef P + + break; + + default: + /* Unknown chroma, tell the guy to get lost */ + free( p_pic->p_sys ); + msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)", + p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma ); + p_pic->i_planes = 0; + return( -1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * QTFreePicture: destroy a picture allocated with QTNewPicture + *****************************************************************************/ +static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + free( p_pic->p_data_orig ); + break; + } + + free( p_pic->p_sys ); +} + +/***************************************************************************** + * VLCWindow implementation + *****************************************************************************/ +@implementation VLCWindow + +- (void)setVout:(vout_thread_t *)_p_vout +{ + p_vout = _p_vout; +} + +- (void)toggleFullscreen +{ + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; +} + +- (BOOL)isFullscreen +{ + return( p_vout->b_fullscreen ); +} + +- (BOOL)canBecomeKeyWindow +{ + return( YES ); +} + +- (void)keyDown:(NSEvent *)o_event +{ + unichar key = 0; + + if( [[o_event characters] length] ) + { + key = [[o_event characters] characterAtIndex: 0]; + } + + switch( key ) + { + case (unichar)0xf700: /* up-arrow */ + { + aout_thread_t * p_aout = vlc_object_find( p_vout, VLC_OBJECT_AOUT, + FIND_ANYWHERE ); + if( p_aout != NULL ) + { + if( p_aout->i_volume + VOLUME_STEP <= VOLUME_MAX ) + { + p_aout->i_volume += VOLUME_STEP; + } + + vlc_object_release( p_aout ); + } + } + break; + + case (unichar)0xf701: /* down-arrow */ + { + aout_thread_t * p_aout = vlc_object_find( p_vout, VLC_OBJECT_AOUT, + FIND_ANYWHERE ); + if( p_aout != NULL ) + { + if( p_aout->i_volume - VOLUME_STEP >= VOLUME_MIN ) + { + p_aout->i_volume -= VOLUME_STEP; + } + + vlc_object_release( p_aout ); + } + } + break; + + case 'f': case 'F': + [self toggleFullscreen]; + break; + + case (unichar)0x1b: /* escape */ + if( [self isFullscreen] ) + { + [self toggleFullscreen]; + } + break; + + case 'q': case 'Q': + p_vout->p_vlc->b_die = VLC_TRUE; + break; + + case ' ': + input_SetStatus( p_vout, INPUT_STATUS_PAUSE ); + break; + + default: + [super keyDown: o_event]; + break; + } +} + +@end + +/***************************************************************************** + * VLCView implementation + *****************************************************************************/ +@implementation VLCView + +- (void)setVout:(vout_thread_t *)_p_vout +{ + p_vout = _p_vout; +} + +- (void)drawRect:(NSRect)rect +{ + [[NSColor blackColor] set]; + NSRectFill( rect ); + [super drawRect: rect]; + + p_vout->i_changes |= VOUT_SIZE_CHANGE; +} + +@end diff --git a/modules/gui/ncurses/.cvsignore b/modules/gui/ncurses/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/ncurses/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/ncurses/Makefile b/modules/gui/ncurses/Makefile new file mode 100644 index 0000000000..ec417edd8c --- /dev/null +++ b/modules/gui/ncurses/Makefile @@ -0,0 +1 @@ +ncurses_SOURCES = ncurses.c diff --git a/modules/gui/ncurses/ncurses.c b/modules/gui/ncurses/ncurses.c new file mode 100644 index 0000000000..0e3625940b --- /dev/null +++ b/modules/gui/ncurses/ncurses.c @@ -0,0 +1,630 @@ +/***************************************************************************** + * ncurses.c : NCurses plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: ncurses.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include +#include /* ENOMEM */ +#include +#include + +#include + +#include +#include +#include + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static void Run ( intf_thread_t * ); +static void FullScreen ( intf_thread_t * ); +static void Play ( intf_thread_t * ); +static void Stop ( intf_thread_t * ); +static void Next ( intf_thread_t * ); +static void Eject ( intf_thread_t * ); +static void Pause ( intf_thread_t * ); +static void PrevTitle ( intf_thread_t * ); +static void NextTitle ( intf_thread_t * ); +static void PrevChapter ( intf_thread_t * ); +static void NextChapter ( intf_thread_t * ); + +static int HandleKey ( intf_thread_t *, int ); +static void Redraw ( intf_thread_t *, time_t * ); +static int PrintFullLine ( const char *p_fmt, ... ); +static void ManageSlider ( intf_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ncurses interface module") ); + set_capability( "interface", 10 ); + set_callbacks( Open, Close ); + add_shortcut( "curses" ); +vlc_module_end(); + +/***************************************************************************** + * intf_sys_t: description and status of ncurses interface + *****************************************************************************/ +struct intf_sys_t +{ + input_thread_t * p_input; + + float f_slider_state; + float f_slider_state_old; +}; + +/***************************************************************************** + * Open: initialize and create window + *****************************************************************************/ +static int Open( 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 ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + p_intf->p_sys->p_input = NULL; + + p_intf->pf_run = Run; + + /* Initialize the curses library */ + initscr(); + /* Don't do NL -> CR/NL */ + nonl(); + /* Take input chars one at a time */ + cbreak(); + /* Don't echo */ + noecho(); + + curs_set(0); + timeout(0); + + clear(); + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface window + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + /* Close the ncurses interface */ + endwin(); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: ncurses thread + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + signed char i_key; + time_t t_last_refresh; + + /* + * force drawing the interface for the first time + */ + t_last_refresh = ( time( 0 ) - 1); + + while( !p_intf->b_die ) + { + msleep( INTF_IDLE_SLEEP ); + + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + while( (i_key = getch()) != -1 ) + { + /* + * HandleKey returns 1 if the screen needs to be redrawn + */ + if ( HandleKey( p_intf, i_key ) ) + { + Redraw( p_intf, &t_last_refresh ); + } + } + + /* + * redraw the screen every second + */ + if ( (time(0) - t_last_refresh) >= 1 ) + { + ManageSlider ( p_intf ); + Redraw( p_intf, &t_last_refresh ); + } + } +} + +/* following functions are local */ + +static int HandleKey( intf_thread_t *p_intf, int i_key ) +{ + switch( i_key ) + { + case 'q': + case 'Q': + p_intf->b_die = 1; + return 0; + + case 'f': + FullScreen( p_intf ); + return 1; + + case 'p': + Play( p_intf ); + return 1; + + case ' ': + Pause( p_intf ); + return 1; + + case 's': + Stop( p_intf ); + return 1; + + case 'n': + Next( p_intf ); + return 1; + + case 'e': + Eject( p_intf ); + return 1; + + case '[': + PrevTitle( p_intf ); + break; + + case ']': + NextTitle( p_intf ); + break; + + case '<': + PrevChapter( p_intf ); + break; + + case '>': + NextChapter( p_intf ); + break; + + case KEY_RIGHT: + p_intf->p_sys->f_slider_state += 100; + ManageSlider ( p_intf ); + break; + + case KEY_LEFT: + p_intf->p_sys->f_slider_state--; + ManageSlider ( p_intf ); + break; + + /* + * ^l should clear and redraw the screen + */ + case 0x0c: + clear(); + return 1; + + default: + break; + } + + return 0; +} + +static int PrintFullLine ( const char *p_fmt, ... ) +{ + va_list vl_args; + char * p_buf = NULL; + int i_len; + + va_start ( vl_args, p_fmt ); + vasprintf ( &p_buf, p_fmt, vl_args ); + va_end ( vl_args ); + + if ( p_buf == NULL ) + { +//X msg_Err( p_input, "intf error: %s", strerror ( ENOMEM ) ); + return ( -1 ); + } + + i_len = strlen( p_buf ); + + /* + * make sure we don't exceed the border on the right side + */ + if ( i_len > COLS ) + { + p_buf[COLS] = '\0'; + i_len = COLS; + printw( "%s", p_buf ); + } + else + { + printw( "%s", p_buf ); + hline( ' ', COLS - i_len ); + } + + free ( p_buf ); + + return i_len; +} + +static void +Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh ) +{ + int row = 0; + + move ( row, 0 ); + + attrset ( A_REVERSE ); + PrintFullLine( VOUT_TITLE " (ncurses interface)" ); + attroff ( A_REVERSE ); + + row++; + + row++; + move ( row, 0 ); + + if ( p_intf->p_sys->p_input != NULL ) + { + PrintFullLine ( " DVD Chapter:%3d DVD Title:%3d", + p_intf->p_sys->p_input->stream.p_selected_area->i_part, + p_intf->p_sys->p_input->stream.p_selected_area->i_id ); + } + + row++; + mvaddch ( row, 0, ACS_ULCORNER ); + mvhline ( row, 1, ACS_HLINE, COLS-2 ); + mvaddch ( row, COLS-1, ACS_URCORNER ); + + row++; + mvaddch ( row, 0, ACS_VLINE ); + attrset ( A_REVERSE ); + mvhline ( row, 1, ' ', ( (int) p_intf->p_sys->f_slider_state % COLS-2) ); + attroff ( A_REVERSE ); + mvaddch ( row, COLS-1, ACS_VLINE ); + + row++; + mvaddch ( row, 0, ACS_LLCORNER ); + mvhline ( row, 1, ACS_HLINE, COLS-2 ); + mvaddch ( row, COLS-1, ACS_LRCORNER ); + + refresh(); + + *t_last_refresh = time( 0 ); +} + +static void FullScreen( intf_thread_t *p_intf ) +{ + vout_thread_t *p_vout; + + p_vout = vlc_object_find( p_intf->p_sys->p_input, + VLC_OBJECT_VOUT, FIND_CHILD ); + if( p_vout == NULL ) + { + return; + } + + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_object_release( p_vout ); +} + +static void Eject ( intf_thread_t *p_intf ) +{ + char *psz_device = NULL, *psz_parser, *psz_name; + + /* + * Get the active input + * Determine whether we can eject a media, ie it's a VCD or DVD + * If it's neither a VCD nor a DVD, then return + */ + + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + + if( p_playlist->i_index < 0 ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + return; + } + + psz_name = p_playlist->pp_items[ p_playlist->i_index ]->psz_name; + + if( psz_name ) + { + if( !strncmp(psz_name, "dvd:", 4) ) + { + switch( psz_name[4] ) + { + case '\0': + case '@': + psz_device = config_GetPsz( p_intf, "dvd_device" ); + break; + default: + /* Omit the first 4 characters */ + psz_device = strdup( psz_name + 4 ); + break; + } + } + else if( !strncmp(psz_name, "vcd:", 4) ) + { + switch( psz_name[4] ) + { + case '\0': + case '@': + psz_device = config_GetPsz( p_intf, "vcd_device" ); + break; + default: + /* Omit the first 4 characters */ + psz_device = strdup( psz_name + 4 ); + break; + } + } + else + { + psz_device = strdup( psz_name ); + } + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + + if( psz_device == NULL ) + { + return; + } + + /* Remove what we have after @ */ + psz_parser = psz_device; + for( psz_parser = psz_device ; *psz_parser ; psz_parser++ ) + { + if( *psz_parser == '@' ) + { + *psz_parser = '\0'; + break; + } + } + + /* If there's a stream playing, we aren't allowed to eject ! */ + if( p_intf->p_sys->p_input == NULL ) + { +//X msg_Dbg( p_input, "ejecting %s", psz_device ); + + intf_Eject( p_intf, psz_device ); + } + + free(psz_device); + return; +} + +static void Play ( intf_thread_t *p_intf ) +{ + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist ) + { + vlc_mutex_lock( &p_playlist->object_lock ); + + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + } + } +} + +static void Pause ( intf_thread_t *p_intf ) +{ + if( p_intf->p_sys->p_input == NULL ) + { + return; + } + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); + + return; +} + +static void Stop ( intf_thread_t *p_intf ) +{ + playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + + return; +} + +static void Next ( intf_thread_t *p_intf ) +{ + int i_id; + input_area_t * p_area; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id+1; + + if ( i_id < p_intf->p_sys->p_input->stream.i_area_nb ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + + input_ChangeArea( p_intf->p_sys->p_input, + (input_area_t *) p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +static void ManageSlider ( intf_thread_t *p_intf ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + + if( p_intf->p_sys->p_input->stream.b_seekable && + p_intf->p_sys->p_input->stream.control.i_status == PLAYING_S ) + { + float newvalue = p_intf->p_sys->f_slider_state; + +#define p_area p_intf->p_sys->p_input->stream.p_selected_area + + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( newvalue == p_intf->p_sys->f_slider_state_old ) + { + /* Update the value */ + p_intf->p_sys->f_slider_state = + p_intf->p_sys->f_slider_state_old = + ( 100 * p_area->i_tell ) / p_area->i_size; + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else + { + off_t i_seek = ( newvalue * p_area->i_size ) / 100; + + /* release the lock to be able to seek */ + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + input_Seek( p_intf, i_seek, INPUT_SEEK_SET ); + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + + /* Update the old value */ + p_intf->p_sys->f_slider_state_old = newvalue; + } +# undef p_area + } + + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +static void PrevTitle ( intf_thread_t *p_intf ) +{ + input_area_t * p_area; + int i_id; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1; + + /* Disallow area 0 since it is used for video_ts.vob */ + if ( i_id > 0 ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +static void NextTitle ( intf_thread_t *p_intf ) +{ + input_area_t * p_area; + int i_id; + + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1; + + if ( i_id < p_intf->p_sys->p_input->stream.i_area_nb ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +static void PrevChapter ( intf_thread_t *p_intf ) +{ + input_area_t * p_area; + + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if ( p_area->i_part > 0 ) + { + p_area->i_part--; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +static void NextChapter( intf_thread_t *p_intf ) +{ + input_area_t * p_area; + + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if ( p_area->i_part < p_area->i_part_nb ) + { + p_area->i_part++; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + diff --git a/modules/gui/qnx/.cvsignore b/modules/gui/qnx/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/qnx/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/qnx/Makefile b/modules/gui/qnx/Makefile new file mode 100644 index 0000000000..be320aa32b --- /dev/null +++ b/modules/gui/qnx/Makefile @@ -0,0 +1 @@ +qnx_SOURCES = qnx.c aout.c vout.c diff --git a/modules/gui/qnx/aout.c b/modules/gui/qnx/aout.c new file mode 100644 index 0000000000..adbf84c33c --- /dev/null +++ b/modules/gui/qnx/aout.c @@ -0,0 +1,243 @@ +/***************************************************************************** + * aout.c : QNX audio output + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * + * Authors: Henri Fallon + * Jon Lech Johansen + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include + +struct aout_sys_t +{ + snd_pcm_t * p_pcm_handle; + int i_card; + int i_device; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int SetFormat ( aout_thread_t * ); +static int GetBufInfo ( aout_thread_t *, int ); +static void Play ( aout_thread_t *, byte_t *, int ); + +/***************************************************************************** + * Open : creates a handle and opens an alsa device + ***************************************************************************** + * This function opens an alsa device, through the alsa API + *****************************************************************************/ +int E_(OpenAudio)( vlc_object_t *p_this ) +{ + aout_thread_t *p_aout = (aout_thread_t *)p_this; + int i_ret; + + /* 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 ); + } + + /* open audio device */ + if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle, + &p_aout->p_sys->i_card, + &p_aout->p_sys->i_device, + SND_PCM_OPEN_PLAYBACK ) ) < 0 ) + { + msg_Err( p_aout, "unable to open audio device (%s)", + snd_strerror( i_ret ) ); + free( p_aout->p_sys ); + return( 1 ); + } + + /* disable mmap */ + if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle, + PLUGIN_DISABLE_MMAP ) ) < 0 ) + { + msg_Err( p_aout, "unable to disable mmap (%s)", snd_strerror(i_ret) ); + Close( p_this ); + free( p_aout->p_sys ); + return( 1 ); + } + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = Play; + + return( 0 ); +} + +/***************************************************************************** + * SetFormat : set the audio 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_ret; + int i_bytes_per_sample; + snd_pcm_channel_info_t pi; + snd_pcm_channel_params_t pp; + + memset( &pi, 0, sizeof(pi) ); + memset( &pp, 0, sizeof(pp) ); + + pi.channel = SND_PCM_CHANNEL_PLAYBACK; + if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle, + &pi ) ) < 0 ) + { + msg_Err( p_aout, "unable to get plugin info (%s)", + snd_strerror( i_ret ) ); + return( 1 ); + } + + pp.mode = SND_PCM_MODE_BLOCK; + pp.channel = SND_PCM_CHANNEL_PLAYBACK; + pp.start_mode = SND_PCM_START_FULL; + pp.stop_mode = SND_PCM_STOP_STOP; + + pp.buf.block.frags_max = 1; + pp.buf.block.frags_min = 1; + + pp.format.interleave = 1; + pp.format.rate = p_aout->i_rate; + pp.format.voices = p_aout->i_channels; + + switch( p_aout->i_format ) + { + case AOUT_FMT_S16_LE: + pp.format.format = SND_PCM_SFMT_S16_LE; + i_bytes_per_sample = 2; + break; + + default: + pp.format.format = SND_PCM_SFMT_S16_BE; + i_bytes_per_sample = 2; + break; + } + + pp.buf.block.frag_size = + (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) * + p_aout->i_channels * i_bytes_per_sample; + + /* set parameters */ + if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle, + &pp ) ) < 0 ) + { + msg_Err( p_aout, "unable to set parameters (%s)", snd_strerror(i_ret) ); + return( 1 ); + } + + /* prepare channel */ + if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle, + SND_PCM_CHANNEL_PLAYBACK ) ) < 0 ) + { + msg_Err( p_aout, "unable to prepare channel (%s)", + snd_strerror( i_ret ) ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * GetBufInfo: 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 ) +{ + int i_ret; + snd_pcm_channel_status_t status; + + /* get current pcm status */ + memset( &status, 0, sizeof(status) ); + if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle, + &status ) ) < 0 ) + { + msg_Err( p_aout, "unable to get device status (%s)", + snd_strerror( i_ret ) ); + return( -1 ); + } + + /* check for underrun */ + switch( status.status ) + { + case SND_PCM_STATUS_READY: + case SND_PCM_STATUS_UNDERRUN: + if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle, + SND_PCM_CHANNEL_PLAYBACK ) ) < 0 ) + { + msg_Err( p_aout, "unable to prepare channel (%s)", + snd_strerror( i_ret ) ); + } + break; + } + + return( status.count ); +} + +/***************************************************************************** + * Play : plays a sample + ***************************************************************************** + * Plays a sample using the snd_pcm_write function from the alsa API + *****************************************************************************/ +static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) +{ + int i_ret; + + if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle, + (void *) buffer, + (size_t) i_size ) ) <= 0 ) + { + msg_Err( p_aout, "unable to write data (%s)", snd_strerror(i_ret) ); + } +} + +/***************************************************************************** + * CloseAudio: close the audio device + *****************************************************************************/ +static void E_(CloseAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t *p_aout = (aout_thread_t *)p_this; + int i_ret; + + if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 ) + { + msg_Err( p_aout, "unable to close audio device (%s)", + snd_strerror( i_ret ) ); + } + + free( p_aout->p_sys ); +} diff --git a/modules/gui/qnx/qnx.c b/modules/gui/qnx/qnx.c new file mode 100644 index 0000000000..32fbff1f07 --- /dev/null +++ b/modules/gui/qnx/qnx.c @@ -0,0 +1,52 @@ +/***************************************************************************** + * qnx.c : QNX RTOS plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * + * Authors: Jon Lech Johansen + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + ******************************************************************************/ +int E_(OpenAudio) ( vlc_object_t * ); +void E_(CloseAudio) ( vlc_object_t * ); + +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("QNX RTOS module") ); + add_submodule(); + set_capability( "video output", 100 ); + set_callbacks( E_(OpenVideo), E_(CloseVideo) ); + add_submodule(); + set_capability( "audio output", 100 ); + set_callbacks( E_(OpenAudio), E_(CloseAudio) ); +vlc_module_end(); + diff --git a/modules/gui/qnx/vout.c b/modules/gui/qnx/vout.c new file mode 100644 index 0000000000..b49d7135a5 --- /dev/null +++ b/modules/gui/qnx/vout.c @@ -0,0 +1,1099 @@ +/***************************************************************************** + * vout.c: QNX RTOS video output display method + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * + * Authors: Jon Lech Johansen + * Pascal Levesque + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include +#include + +#include +#include +#include + +/***************************************************************************** + * vout_sys_t: video output QNX method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the QNX specific properties of an output thread. QNX video + * output is performed through regular resizable windows. Windows can be + * dynamically resized to adapt to the size of the streams. + *****************************************************************************/ +#define MAX_DIRECTBUFFERS 2 + +#define MODE_NORMAL_MEM 0 +#define MODE_SHARED_MEM 1 +#define MODE_VIDEO_MEM 2 +#define MODE_VIDEO_OVERLAY 3 + +struct vout_sys_t +{ + /* video mode */ + int i_mode; + + /* internal stuff */ + PtWidget_t * p_window; + + /* Color palette for 8bpp */ + PgColor_t p_colors[255]; + + /* [shared] memory blit */ + int i_img_type; + + /* video memory blit */ + + /* video overlay */ + PgVideoChannel_t * p_channel; + int i_vc_flags; + int i_vc_format; + + int i_screen_depth; + int i_bytes_per_pixel; + int i_bytes_per_line; + + /* position & dimensions */ + PhPoint_t pos; + PhDim_t dim; + PhPoint_t old_pos; + PhDim_t old_dim; + PhDim_t screen_dim; + PhRect_t frame; +}; + + +/***************************************************************************** + * picture_sys_t: direct buffer method descriptor + ***************************************************************************** + * This structure is part of the picture descriptor, it describes the + * XVideo specific properties of a direct buffer. + *****************************************************************************/ +struct picture_sys_t +{ + /* [shared] memory blit */ + PhImage_t * p_image; + + /* video memory blit and video overlay */ + PdOffscreenContext_t * p_ctx[3]; /* 0: y, 1: u, 2: v */ + char * p_buf[3]; +}; + + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int QNXInit ( vout_thread_t * ); +static void QNXEnd ( vout_thread_t * ); +static int QNXManage ( vout_thread_t * ); +static void QNXDisplay ( vout_thread_t *, picture_t * ); + +static int QNXInitDisplay ( vout_thread_t * ); +static int QNXCreateWnd ( vout_thread_t * ); +static int QNXDestroyWnd ( vout_thread_t * ); + +static int NewPicture ( vout_thread_t *, picture_t *, int ); +static void FreePicture ( vout_thread_t *, picture_t * ); +static int ResizeOverlayOutput ( vout_thread_t * ); +static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); + +/***************************************************************************** + * OpenVideo: allocate QNX video thread output method + ***************************************************************************** + * This function allocate and initialize a QNX vout method. It uses some of the + * vout properties to choose the window size, and change them according to the + * actual properties of the display. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + /* init connection to photon */ + if( PtInit( "/dev/photon" ) != 0 ) + { + msg_Err( p_vout, "unable to connect to photon" ); + return( 1 ); + } + + /* allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) ); + + p_vout->b_fullscreen = config_GetInt( p_vout, "fullscreen" ); + p_vout->p_sys->i_mode = config_GetInt( p_vout, "overlay" ) ? + MODE_VIDEO_OVERLAY : MODE_VIDEO_MEM; + p_vout->p_sys->dim.w = p_vout->i_window_width; + p_vout->p_sys->dim.h = p_vout->i_window_height; + + /* init display and create window */ + if( QNXInitDisplay( p_vout ) || QNXCreateWnd( p_vout ) ) + { + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->pf_init = QNXInit; + p_vout->pf_end = QNXEnd; + p_vout->pf_manage = QNXManage; + p_vout->pf_render = NULL; + p_vout->pf_display = QNXDisplay; + + return( 0 ); +} + +/***************************************************************************** + * QNXInit: initialize QNX video thread output method + ***************************************************************************** + * This function create the buffers needed by the output thread. It is called + * at the beginning of the thread, but also each time the window is resized. + *****************************************************************************/ +static int QNXInit( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + switch( p_vout->p_sys->i_mode ) + { + case MODE_NORMAL_MEM: + case MODE_SHARED_MEM: + p_vout->output.i_width = p_vout->p_sys->dim.w; + p_vout->output.i_height = p_vout->p_sys->dim.h; + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->p_sys->dim.w + * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h; + break; + + case MODE_VIDEO_MEM: + p_vout->output.i_width = p_vout->p_sys->dim.w; + p_vout->output.i_height = p_vout->p_sys->dim.h; + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->p_sys->dim.w + * VOUT_ASPECT_FACTOR / p_vout->p_sys->dim.h; + break; + + case MODE_VIDEO_OVERLAY: + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + if (ResizeOverlayOutput(p_vout)) + { + return (1); + } + break; + + default: + /* This shouldn't happen ! */ + break; + } + + /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || NewPicture( p_vout, p_pic, I_OUTPUTPICTURES ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * QNXEnd: terminate QNX video thread output method + ***************************************************************************** + * Destroy the buffers created by QNXInit. It is called at the end of + * the thread, but also each time the window is resized. + *****************************************************************************/ +static void QNXEnd( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); + } +} + +/***************************************************************************** + * CloseVideo: destroy QNX video thread output method + ***************************************************************************** + * Terminate an output method created by QNXCreate + *****************************************************************************/ +void E_(CloseVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + /* destroy the window */ + QNXDestroyWnd( p_vout ); + + /* destroy structure */ + free( p_vout->p_sys ); +} + +/***************************************************************************** + * QNXManage: handle QNX events + ***************************************************************************** + * This function should be called regularly by video output thread. It allows + * window resizing. It returns a non null value on error. + *****************************************************************************/ +static int QNXManage( vout_thread_t *p_vout ) +{ + int i_ev, i_buflen; + PhEvent_t *p_event; + vlc_bool_t b_repos = 0; + + if (p_vout->b_die == 1) + { + return ( 0 ); + } + + /* allocate buffer for event */ + i_buflen = sizeof( PhEvent_t ) * 4; + if( ( p_event = malloc( i_buflen ) ) == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* event loop */ + do + { + memset( p_event, 0, i_buflen ); + i_ev = PhEventPeek( p_event, i_buflen ); + + if( i_ev == Ph_RESIZE_MSG ) + { + i_buflen = PhGetMsgSize( p_event ); + if( ( p_event = realloc( p_event, i_buflen ) ) == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + } + else if( i_ev == Ph_EVENT_MSG ) + { + PtEventHandler( p_event ); + + if( p_event->type == Ph_EV_WM ) + { + PhWindowEvent_t *p_ev = PhGetData( p_event ); + + switch( p_ev->event_f ) + { + case Ph_WM_CLOSE: + p_vout->p_vlc->b_die = 1; + break; + + case Ph_WM_MOVE: + p_vout->p_sys->pos.x = p_ev->pos.x; + p_vout->p_sys->pos.y = p_ev->pos.y; + b_repos = 1; + break; + + case Ph_WM_RESIZE: + p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w; + p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h; + p_vout->p_sys->dim.w = p_ev->size.w; + p_vout->p_sys->dim.h = p_ev->size.h; + p_vout->i_changes |= VOUT_SIZE_CHANGE; + break; + } + } + else if( p_event->type == Ph_EV_KEY ) + { + PhKeyEvent_t *p_ev = PhGetData( p_event ); + long i_key = p_ev->key_sym; + + if( ( p_ev->key_flags & Pk_KF_Key_Down ) && + ( p_ev->key_flags & Pk_KF_Sym_Valid ) ) + { + switch( i_key ) + { + case Pk_q: + case Pk_Q: + p_vout->p_vlc->b_die = 1; + break; + + case Pk_f: + case Pk_F: + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + case Pk_c: + case Pk_C: + p_vout->b_grayscale = ! p_vout->b_grayscale; + p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE; + break; + + default: + if( i_key >= Pk_0 && i_key <= Pk_9 ) + { +// network_ChannelJoin( i_key ); + } + break; + } + } + } + } + } while( i_ev != -1 && i_ev != 0 ); + + free( p_event ); + + /* + * fullscreen + */ + if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + PhDim_t dim; + + p_vout->b_fullscreen = !p_vout->b_fullscreen; + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + + if( p_vout->b_fullscreen ) + { + p_vout->p_sys->old_pos.x = p_vout->p_sys->pos.x; + p_vout->p_sys->old_pos.y = p_vout->p_sys->pos.y; + p_vout->p_sys->pos.x = p_vout->p_sys->pos.y = 0; + dim.w = p_vout->p_sys->screen_dim.w + 1; + dim.h = p_vout->p_sys->screen_dim.h + 1; + } + else + { + p_vout->p_sys->pos.x = p_vout->p_sys->old_pos.x; + p_vout->p_sys->pos.y = p_vout->p_sys->old_pos.y; + dim.w = p_vout->p_sys->old_dim.w + 1; + dim.h = p_vout->p_sys->old_dim.h + 1; + } + + /* modify render flags, border */ + PtSetResource( p_vout->p_sys->p_window, + Pt_ARG_WINDOW_RENDER_FLAGS, + p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE, + Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE ); + + /* set position and dimension */ + PtSetResource( p_vout->p_sys->p_window, + Pt_ARG_POS, &p_vout->p_sys->pos, 0 ); + PtSetResource( p_vout->p_sys->p_window, + Pt_ARG_DIM, &dim, 0 ); + + /* mark as damaged to force redraw */ + PtDamageWidget( p_vout->p_sys->p_window ); + } + + /* + * size change + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + + if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) + { + ResizeOverlayOutput(p_vout); + } +#if 0 + else + { + p_vout->output.i_width = p_vout->p_sys->dim.w; + p_vout->output.i_height = p_vout->p_sys->dim.h; + p_vout->i_changes |= VOUT_YUV_CHANGE; + + QNXEnd( p_vout ); + if( QNXInit( p_vout ) ) + { + msg_Err( p_vout, "cannot resize display" ); + return( 1 ); + } + } +#endif + + msg_Dbg( p_vout, "video display resized (%dx%d)", + p_vout->p_sys->dim.w, p_vout->p_sys->dim.h ); + } + + /* + * position change, move video channel + */ + if( b_repos && p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) + { + ResizeOverlayOutput(p_vout); + } + + return( i_ev == -1 ); +} + +/***************************************************************************** + * QNXDisplay: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to QNX server, wait until + * it is displayed and switch the two rendering buffer, preparing next frame. + *****************************************************************************/ +static void QNXDisplay( vout_thread_t *p_vout, picture_t *p_pic ) +{ + if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM || + p_vout->p_sys->i_mode == MODE_SHARED_MEM ) + { + PhPoint_t pos = { 0, 0 }; + + PgSetRegion( PtWidgetRid( p_vout->p_sys->p_window ) ); + if (p_vout->p_sys->i_screen_depth == 8) + { + PgSetPalette( p_vout->p_sys->p_colors, 0, 0, 255, Pg_PALSET_SOFT, 0); + } + PgDrawPhImagemx( &pos, p_pic->p_sys->p_image, 0 ); + PgFlush(); + } + else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM ) + { + PhRect_t rc = { { 0, 0 }, { p_vout->output.i_width, p_vout->output.i_height } }; + +// PgSetRegion( PtWidgetRid ( p_vout->p_sys->p_window ) ); + PgContextBlit( p_pic->p_sys->p_ctx[0], &rc, NULL, &rc ); + PgFlush(); + } +} + +/***************************************************************************** + * QNXInitDisplay: check screen resolution, depth, amount of video ram, etc + *****************************************************************************/ +static int QNXInitDisplay( vout_thread_t * p_vout ) +{ + PgHWCaps_t hwcaps; + PgDisplaySettings_t cfg; + PgVideoModeInfo_t minfo; + + /* get graphics card hw capabilities */ + if( PgGetGraphicsHWCaps( &hwcaps ) != 0 ) + { + msg_Err( p_vout, "unable to get gfx card capabilities" ); + return( 1 ); + } + + /* get current video mode */ + if( PgGetVideoMode( &cfg ) != 0 ) + { + msg_Err( p_vout, "unable to get current video mode" ); + return( 1 ); + } + + /* get video mode info */ + if( PgGetVideoModeInfo( cfg.mode, &minfo ) != 0 ) + { + msg_Err( p_vout, "unable to get info for video mode" ); + return( 1 ); + } + + /* switch to normal mode if no overlay support */ +// printf("minfo.mode_capabilities1: 0x%x\n", minfo.mode_capabilities1); + + if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY && + !( minfo.mode_capabilities1 & PgVM_MODE_CAP1_VIDEO_OVERLAY ) ) + { + msg_Err( p_vout, "no overlay support detected" ); + p_vout->p_sys->i_mode = MODE_NORMAL_MEM; + } + + if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) + { + int i = 0; + PgScalerCaps_t vcaps; + + if( ( p_vout->p_sys->p_channel = + PgCreateVideoChannel( Pg_VIDEO_CHANNEL_SCALER, 0 ) ) == NULL ) + { + msg_Err( p_vout, "unable to create video channel" ); + printf("errno = %d\n", errno); + p_vout->p_sys->i_mode = MODE_NORMAL_MEM; + } + else + { + vcaps.size = sizeof( vcaps ); + while( PgGetScalerCapabilities( p_vout->p_sys->p_channel, + i++, &vcaps ) == 0 ) + { + printf("vcaps.format = 0x%x\n", vcaps.format); + if( vcaps.format == Pg_VIDEO_FORMAT_YV12 || + vcaps.format == Pg_VIDEO_FORMAT_YUV420 || + vcaps.format == Pg_VIDEO_FORMAT_YUY2 || + vcaps.format == Pg_VIDEO_FORMAT_UYVY || + vcaps.format == Pg_VIDEO_FORMAT_RGB555 || + vcaps.format == Pg_VIDEO_FORMAT_RGB565 || + vcaps.format == Pg_VIDEO_FORMAT_RGB8888 ) + { + p_vout->p_sys->i_vc_flags = vcaps.flags; + p_vout->p_sys->i_vc_format = vcaps.format; + } + + vcaps.size = sizeof( vcaps ); + } + + if( p_vout->p_sys->i_vc_format == 0 ) + { + msg_Warn( p_vout, "need YV12, YUY2 or RGB8888 overlay" ); + + p_vout->p_sys->i_mode = MODE_NORMAL_MEM; + } + } + } + + /* use video ram if we have enough available */ + if( p_vout->p_sys->i_mode == MODE_NORMAL_MEM && + (minfo.bits_per_pixel != 8) && + hwcaps.currently_available_video_ram >= + ( ( minfo.width * minfo.height * minfo.bits_per_pixel * MAX_DIRECTBUFFERS) / 8 ) ) + { + p_vout->p_sys->i_mode = MODE_VIDEO_MEM; + printf("Using video memory...\n"); + } + + p_vout->p_sys->i_img_type = minfo.type; + p_vout->p_sys->screen_dim.w = minfo.width; + p_vout->p_sys->screen_dim.h = minfo.height; + p_vout->p_sys->i_screen_depth = minfo.bits_per_pixel; + + switch( p_vout->p_sys->i_screen_depth ) + { + case 8: + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); + p_vout->p_sys->i_bytes_per_pixel = 1; + p_vout->output.pf_setpalette = SetPalette; + break; + + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); + p_vout->p_sys->i_bytes_per_pixel = 2; + p_vout->output.i_rmask = 0x7c00; + p_vout->output.i_gmask = 0x03e0; + p_vout->output.i_bmask = 0x001f; + break; + + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); + p_vout->p_sys->i_bytes_per_pixel = 2; + p_vout->output.i_rmask = 0xf800; + p_vout->output.i_gmask = 0x07e0; + p_vout->output.i_bmask = 0x001f; + break; + + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); + p_vout->p_sys->i_bytes_per_pixel = 3; + p_vout->output.i_rmask = 0xff0000; + p_vout->output.i_gmask = 0x00ff00; + p_vout->output.i_bmask = 0x0000ff; + break; + + case 32: + default: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); + p_vout->p_sys->i_bytes_per_pixel = 4; + p_vout->output.i_rmask = 0xff0000; + p_vout->output.i_gmask = 0x00ff00; + p_vout->output.i_bmask = 0x0000ff; + break; + } + + return( 0 ); +} + +/***************************************************************************** + * QNXCreateWnd: create and realize the main window + *****************************************************************************/ +static int QNXCreateWnd( vout_thread_t * p_vout ) +{ + PtArg_t args[8]; + PhPoint_t pos = { 0, 0 }; + PgColor_t color = Pg_BLACK; + + if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) + { + if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY ) + { + color = PgGetOverlayChromaColor(); + } + } + + /* fullscreen, set dimension */ + if( p_vout->b_fullscreen ) + { + p_vout->p_sys->old_dim.w = p_vout->p_sys->dim.w; + p_vout->p_sys->old_dim.h = p_vout->p_sys->dim.h; + p_vout->output.i_width = p_vout->p_sys->dim.w = p_vout->p_sys->screen_dim.w; + p_vout->output.i_height = p_vout->p_sys->dim.h = p_vout->p_sys->screen_dim.h; + } + + /* set window parameters */ + PtSetArg( &args[0], Pt_ARG_POS, &pos, 0 ); + PtSetArg( &args[1], Pt_ARG_DIM, &p_vout->p_sys->dim, 0 ); + PtSetArg( &args[2], Pt_ARG_FILL_COLOR, color, 0 ); + PtSetArg( &args[3], Pt_ARG_WINDOW_TITLE, "VideoLan Client", 0 ); + PtSetArg( &args[4], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE ); + PtSetArg( &args[5], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, + Ph_WM_MOVE | Ph_WM_RESIZE | Ph_WM_CLOSE ); + PtSetArg( &args[6], Pt_ARG_WINDOW_RENDER_FLAGS, + p_vout->b_fullscreen ? Pt_FALSE : Pt_TRUE, + Ph_WM_RENDER_BORDER | Ph_WM_RENDER_TITLE ); + + /* create window */ + p_vout->p_sys->p_window = PtCreateWidget( PtWindow, Pt_NO_PARENT, 7, args); + if( p_vout->p_sys->p_window == NULL ) + { + msg_Err( p_vout, "unable to create window" ); + return( 1 ); + } + + /* realize the window widget */ + if( PtRealizeWidget( p_vout->p_sys->p_window ) != 0 ) + { + msg_Err( p_vout, "unable to realize window widget" ); + PtDestroyWidget( p_vout->p_sys->p_window ); + return( 1 ); + } + + /* get window frame size */ + if( PtWindowFrameSize( NULL, p_vout->p_sys->p_window, + &p_vout->p_sys->frame ) != 0 ) + { + msg_Err( p_vout, "unable to get window frame size" ); + PtDestroyWidget( p_vout->p_sys->p_window ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * QNXDestroyWnd: unrealize and destroy the main window + *****************************************************************************/ +static int QNXDestroyWnd( vout_thread_t * p_vout ) +{ + /* destroy the window widget */ + PtUnrealizeWidget( p_vout->p_sys->p_window ); +// PtDestroyWidget( p_vout->p_sys->p_window ); + + /* destroy video channel */ + if( p_vout->p_sys->i_mode == MODE_VIDEO_OVERLAY ) + { + PgDestroyVideoChannel( p_vout->p_sys->p_channel ); + } + + return( 0 ); +} + + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index ) +{ + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return -1; + } + + switch( p_vout->p_sys->i_mode ) + { + case MODE_NORMAL_MEM: + case MODE_SHARED_MEM: + /* create images for [shared] memory blit */ + if( !( p_pic->p_sys->p_image = PhCreateImage( NULL, + p_vout->p_sys->dim.w, p_vout->p_sys->dim.h, + p_vout->p_sys->i_img_type, NULL, 0, + p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) { + msg_Err( p_vout, "cannot create image" ); + free( p_pic->p_sys ); + return( -1 ); + } + + p_pic->p->p_pixels = p_pic->p_sys->p_image->image; + p_pic->p->i_lines = p_pic->p_sys->p_image->size.h; + p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl; + p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; + p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel + * p_pic->p_sys->p_image->size.w; + p_pic->i_planes = 1; + break; + + case MODE_VIDEO_MEM: + /* create offscreen contexts for video memory blit */ + if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0, + p_vout->p_sys->dim.w, p_vout->p_sys->dim.h, + Pg_OSC_MEM_PAGE_ALIGN) ) == NULL ) + { + msg_Err( p_vout, "unable to create offscreen context" ); + free( p_pic->p_sys ); + return( -1 ); + } + + /* get context pointers */ + if( ( p_pic->p_sys->p_buf[0] = + PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL ) + { + msg_Err( p_vout, "unable to get offscreen context ptr" ); + PhDCRelease ( p_pic->p_sys->p_ctx[0] ); + p_pic->p_sys->p_ctx[0] = NULL; + free( p_pic->p_sys ); + return( -1 ); + } + + p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch; + memset( p_pic->p_sys->p_buf[0], 0, + p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h ); + + p_pic->p->p_pixels = p_pic->p_sys->p_buf[0]; + p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h; + p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch; + p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; + p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel + * p_pic->p_sys->p_ctx[0]->dim.w; + p_pic->i_planes = 1; + break; + + case MODE_VIDEO_OVERLAY: + if (index == 0) + { + p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1; + p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1; + p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1; + } + else + { + p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2; + p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2; + p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2; + } + + p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] ); + if( p_pic->p_sys->p_buf[Y_PLANE] == NULL ) + { + msg_Err( p_vout, "unable to get video channel ctx ptr" ); + return( 1 ); + } + + switch (p_vout->p_sys->i_vc_format) + { + case Pg_VIDEO_FORMAT_YUV420: + p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0'); + + p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] ); + p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] ); + + if( p_pic->p_sys->p_buf[U_PLANE] == NULL || + p_pic->p_sys->p_buf[V_PLANE] == NULL ) + { + msg_Err( p_vout, "unable to get video channel ctx ptr" ); + return( 1 ); + } + + p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE]; + p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE]; + p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + case Pg_VIDEO_FORMAT_YV12: + p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2'); + + p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] ); + p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] ); + + if( p_pic->p_sys->p_buf[U_PLANE] == NULL || + p_pic->p_sys->p_buf[V_PLANE] == NULL ) + { + msg_Err( p_vout, "unable to get video channel ctx ptr" ); + return( 1 ); + } + + p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE]; + p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE]; + p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + case Pg_VIDEO_FORMAT_UYVY: + case Pg_VIDEO_FORMAT_YUY2: + if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY) + { + p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y'); + } + else + { + p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2'); + } + + p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; + + case Pg_VIDEO_FORMAT_RGB555: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); + p_vout->output.i_rmask = 0x001f; + p_vout->output.i_gmask = 0x03e0; + p_vout->output.i_bmask = 0x7c00; + + p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p->i_pixel_pitch = 2; + p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; + + p_pic->i_planes = 1; + break; + + case Pg_VIDEO_FORMAT_RGB565: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); + p_vout->output.i_rmask = 0x001f; + p_vout->output.i_gmask = 0x07e0; + p_vout->output.i_bmask = 0xf800; + + p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; + + p_pic->i_planes = 1; + break; + + case Pg_VIDEO_FORMAT_RGB8888: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); + p_vout->output.i_rmask = 0x000000ff; + p_vout->output.i_gmask = 0x0000ff00; + p_vout->output.i_bmask = 0x00ff0000; + + p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; + p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; + p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; + + p_pic->i_planes = 1; + break; + } + +#if 0 + switch( p_vout->output.i_chroma ) + { +#ifdef MODULE_NAME_IS_xvideo + case VLC_FOURCC('Y','2','1','1'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + /* XXX: this just looks so plain wrong... check it out ! */ + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; +#endif + +#endif + + default: + /* This shouldn't happen ! */ + break; + } + + return 0; +} + +/***************************************************************************** + * FreePicture: destroy a picture allocated with NewPicture + ***************************************************************************** + * Destroy XImage AND associated data. If using Shm, detach shared memory + * segment from server and process, then free it. The XDestroyImage manpage + * says that both the image structure _and_ the data pointed to by the + * image structure are freed, so no need to free p_image->data. + *****************************************************************************/ +static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM || + p_vout->p_sys->i_mode == MODE_SHARED_MEM ) && + p_pic->p_sys->p_image ) + { + PhReleaseImage( p_pic->p_sys->p_image ); + free( p_pic->p_sys->p_image ); + } + else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM && + p_pic->p_sys->p_ctx[0] ) + { + PhDCRelease( p_pic->p_sys->p_ctx[0] ); + } + + free( p_pic->p_sys ); +} + + +static int ResizeOverlayOutput(vout_thread_t *p_vout) +{ + int i_width, i_height, i_x, i_y; + int i_ret; + PgScalerProps_t props; + + props.size = sizeof( props ); + props.format = p_vout->p_sys->i_vc_format; + props.flags = Pg_SCALER_PROP_SCALER_ENABLE | + Pg_SCALER_PROP_DOUBLE_BUFFER; + + /* enable chroma keying if available */ + if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY ) + { + props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE; + } + + /* set viewport position */ + props.viewport.ul.x = p_vout->p_sys->pos.x; + props.viewport.ul.y = p_vout->p_sys->pos.y; + if( !p_vout->b_fullscreen ) + { + props.viewport.ul.x += p_vout->p_sys->frame.ul.x; + props.viewport.ul.y += p_vout->p_sys->frame.ul.y; + } + + /* set viewport dimension */ + vout_PlacePicture( p_vout, p_vout->p_sys->dim.w, + p_vout->p_sys->dim.h, + &i_x, &i_y, &i_width, &i_height ); + + props.viewport.ul.x += i_x; + props.viewport.ul.y += i_y; + props.viewport.lr.x = i_width + props.viewport.ul.x; + props.viewport.lr.y = i_height + props.viewport.ul.y; + + /* set source dimension */ + props.src_dim.w = p_vout->output.i_width; + props.src_dim.h = p_vout->output.i_height; + + /* configure scaler channel */ + i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props ); + + if( i_ret == -1 ) + { + msg_Err( p_vout, "unable to configure video channel" ); + return( 1 ); + } + + return ( 0 ); +} + + +/***************************************************************************** + * SetPalette: sets an 8 bpp palette + ***************************************************************************** + * This function sets the palette given as an argument. It does not return + * anything, but could later send information on which colors it was unable + * to set. + *****************************************************************************/ +static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) +{ + int i; + + /* allocate palette */ + for( i = 0; i < 255; i++ ) + { + /* kludge: colors are indexed reversely because color 255 seems + * to be reserved for black even if we try to set it to white */ + p_vout->p_sys->p_colors[ i ] = PgRGB( red[ i ] >> 8, green[ i ] >> 8, blue[ i ] >> 8 ); + } +} diff --git a/modules/gui/qt/.cvsignore b/modules/gui/qt/.cvsignore new file mode 100644 index 0000000000..12c27ba6fd --- /dev/null +++ b/modules/gui/qt/.cvsignore @@ -0,0 +1,5 @@ +.dep +*.lo +*.o.* +*.lo.* +*.moc diff --git a/modules/gui/qt/Makefile b/modules/gui/qt/Makefile new file mode 100644 index 0000000000..e0e4e8fb38 --- /dev/null +++ b/modules/gui/qt/Makefile @@ -0,0 +1,8 @@ +qt_SOURCES = qt.cpp intf.cpp +MOC_QT = intf.moc + +EXTRA_DEP = $(MOC_QT) + +$(MOC_QT): %.moc: %.cpp + $(MOC) -i $< -o $@ + diff --git a/modules/gui/qt/intf.cpp b/modules/gui/qt/intf.cpp new file mode 100644 index 0000000000..cefbfdd395 --- /dev/null +++ b/modules/gui/qt/intf.cpp @@ -0,0 +1,596 @@ +/***************************************************************************** + * intf.cpp: Qt interface + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: intf.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/***************************************************************************** + * Local Qt slider class + *****************************************************************************/ +class IntfSlider : public QSlider +{ + Q_OBJECT + +public: + IntfSlider( intf_thread_t *, QWidget * ); /* Constructor and destructor */ + ~IntfSlider(); + + bool b_free; /* Is the slider free ? */ + + int oldvalue ( void ) { return i_oldvalue; }; + void setOldValue( int i_value ) { i_oldvalue = i_value; }; + +private slots: + void SlideStart ( void ) { b_free = FALSE; }; + void SlideStop ( void ) { b_free = TRUE; }; + +private: + intf_thread_t *p_intf; + int i_oldvalue; +}; + +/***************************************************************************** + * Local Qt interface window class + *****************************************************************************/ +class IntfWindow : public QMainWindow +{ + Q_OBJECT + +public: + IntfWindow( intf_thread_t * ); + ~IntfWindow(); + +private slots: + void Manage ( void ); + + void FileOpen ( void ); + void FileQuit ( void ); + + void PlaybackPlay ( void ); + void PlaybackPause ( void ); + void PlaybackSlow ( void ); + void PlaybackFast ( void ); + + void PlaylistPrev ( void ); + void PlaylistNext ( void ); + + void DateDisplay ( int ); + void About ( void ); + + void Unimplemented( void ) { msg_Warn( p_intf, "unimplemented" ); }; + +private: + intf_thread_t *p_intf; + + IntfSlider *p_slider; + + QToolBar *p_toolbar; + QPopupMenu *p_popup; + QLabel *p_date; +}; + +#include "intf.moc" + +#define SLIDER_MIN 0x00000 +#define SLIDER_MAX 0x10000 +#define SLIDER_STEP (SLIDER_MAX >> 4) + +/***************************************************************************** + * intf_sys_t: description and status of Qt interface + *****************************************************************************/ +struct intf_sys_t +{ + QApplication *p_app; + IntfWindow *p_window; + + input_thread_t *p_input; +}; + +/***************************************************************************** + * Local prototype + *****************************************************************************/ +static void Run ( intf_thread_t *p_intf ); + +/***************************************************************************** + * Open: initialize and create window + *****************************************************************************/ +int E_(Open) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + char *pp_argv[] = { "" }; + int i_argc = 1; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return 1; + } + + p_intf->pf_run = Run; + + /* Create the C++ objects */ + p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv ); + p_intf->p_sys->p_window = new IntfWindow( p_intf ); + + /* Tell the world we are here */ + p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" ); + + p_intf->p_sys->p_input = NULL; + + return 0; +} + +/***************************************************************************** + * Close: destroy interface window + *****************************************************************************/ +void E_(Close) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + /* Get rid of the C++ objects */ + delete p_intf->p_sys->p_window; + delete p_intf->p_sys->p_app; + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: Qt thread + ***************************************************************************** + * This part of the interface is in a separate thread so that we can call + * exec() from within it without annoying the rest of the program. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + p_intf->p_sys->p_window->show(); + + p_intf->p_sys->p_app->exec(); +} + +/* following functions are local */ + +/***************************************************************************** + * IntfWindow: interface window creator + ***************************************************************************** + * This function creates the interface window, and populates it with a + * menu bar, a toolbar and a slider. + *****************************************************************************/ +IntfWindow::IntfWindow( intf_thread_t *p_intf ) + :QMainWindow( 0 ) +{ + setUsesTextLabel( TRUE ); + + this->p_intf = p_intf; + + /* + * Create the toolbar + */ + + p_toolbar = new QToolBar( this, "toolbar" ); + p_toolbar->setHorizontalStretchable( TRUE ); + + QIconSet * set = new QIconSet(); + QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal ); + +#define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar ); + addbut( "Open", "Open a File", SLOT(FileOpen()) ); + addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) ); + addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) ); + p_toolbar->addSeparator(); + addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) ); + addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) ); + addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) ); + addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) ); + addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) ); + addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) ); + p_toolbar->addSeparator(); + addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) ); + addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) ); + addbut( "Next", "Next File", SLOT(PlaylistNext()) ); +#undef addbut + + /* + * Create the menubar + */ + + QPopupMenu * p_tmpmenu = new QPopupMenu( this ); + +#define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y ) + menuBar()->insertItem( "&File", p_tmpmenu ); + instmp( "&Open File...", SLOT(FileOpen()), Key_F3 ); + instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 ); + instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 ); + p_tmpmenu->insertSeparator(); + instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q ); + + p_tmpmenu = new QPopupMenu( this ); + menuBar()->insertItem( "&View", p_tmpmenu ); + instmp( "&Playlist...", SLOT(Unimplemented()) ); + instmp( "&Modules...", SLOT(Unimplemented()) ); + + p_tmpmenu = new QPopupMenu( this ); + menuBar()->insertItem( "&Settings", p_tmpmenu ); + instmp( "&Preferences...", SLOT(Unimplemented()) ); + + p_tmpmenu = new QPopupMenu( this ); + menuBar()->insertItem( "&Help", p_tmpmenu ); + instmp( "&About...", SLOT(About()) ); +#undef instmp + + /* + * Create the popup menu + */ + + p_popup = new QPopupMenu( /* floating menu */ ); + +#define inspop( x, y... ) p_popup->insertItem( x, this, ## y ) + inspop( "&Play", SLOT(PlaybackPlay()) ); + inspop( "Pause", SLOT(PlaybackPause()) ); + inspop( "&Slow", SLOT(PlaybackSlow()) ); + inspop( "&Fast", SLOT(PlaybackFast()) ); + p_popup->insertSeparator(); + inspop( "&Open File...", SLOT(FileOpen()), Key_F3 ); + inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 ); + inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 ); + p_popup->insertSeparator(); + inspop( "&About...", SLOT(About()) ); + inspop( "&Exit", SLOT(FileQuit()) ); +#undef inspop + + /* Activate the statusbar */ + statusBar(); + + /* Add the vertical box */ + QVBox * p_vbox = new QVBox( this ); + setCentralWidget( p_vbox ); + + /* The horizontal box */ + QHBox * p_hbox = new QHBox( p_vbox ); + + /* The date label */ + p_date = new QLabel( p_hbox ); + p_date->setAlignment( AlignHCenter | AlignVCenter ); + p_date->setText( "-:--:--" ); + + /* The status label */ + QLabel *p_label = new QLabel( p_hbox ); + p_label->setAlignment( AlignHCenter | AlignVCenter ); + p_label->setText( "Status: foo" ); + + /* The bar label */ + p_label = new QLabel( p_hbox ); + p_label->setAlignment( AlignHCenter | AlignVCenter ); + p_label->setText( "Bar: baz quux" ); + + /* Create the slider and connect it to the date label */ + p_slider = new IntfSlider( p_intf, p_vbox ); + + connect( p_slider, SIGNAL(valueChanged(int)), + this, SLOT(DateDisplay(int)) ); + + /* The timer */ + QTimer *p_timer = new QTimer( this ); + connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) ); + p_timer->start( INTF_IDLE_SLEEP / 1000 ); + + /* Everything worked fine */ + resize( 620, 30 ); +} + +/***************************************************************************** + * ~IntfWindow: interface window destructor + ***************************************************************************** + * This function is called when the interface window is destroyed. + *****************************************************************************/ +IntfWindow::~IntfWindow( void ) +{ + /* FIXME: remove everything cleanly */ +} + +/***************************************************************************** + * DateDisplay: display date + ***************************************************************************** + * This function displays the current date in the date label. + *****************************************************************************/ +void IntfWindow::DateDisplay( int i_range ) +{ + if( p_intf->p_sys->p_input ) + { + char psz_time[ OFFSETTOTIME_MAX_SIZE ]; + + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + p_date->setText( input_OffsetToTime( p_intf->p_sys->p_input, psz_time, + ( p_intf->p_sys->p_input->stream.p_selected_area->i_size * i_range ) + / SLIDER_MAX ) ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} + +/***************************************************************************** + * FileOpen: open a file + ***************************************************************************** + * This function opens a file requester and adds the selected file to + * the playlist. + *****************************************************************************/ +void IntfWindow::FileOpen( void ) +{ + playlist_t *p_playlist; + QString file = QFileDialog::getOpenFileName( QString::null, + QString::null, this ); + + if( file.isEmpty() ) + { + statusBar()->message( "No file loaded", 2000 ); + } + else + { + p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Add( p_playlist, file.latin1(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } +} + +/***************************************************************************** + * FileQuit: terminate vlc + *****************************************************************************/ +void IntfWindow::FileQuit( void ) +{ + p_intf->p_vlc->b_die = VLC_TRUE; +} + +/***************************************************************************** + * About: display the "about" box + ***************************************************************************** + * This function displays a simple "about" box with copyright information. + *****************************************************************************/ +void IntfWindow::About( void ) +{ + QMessageBox::about( this, "About", + "VideoLAN Client\n" + "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n" + "\n" + "This is the VideoLAN client, a DVD and MPEG player.\n" + "It can play MPEG and MPEG 2 files from a file " + "or from a network source.\n" + "\n" + "More information: http://www.videolan.org/" ); +} + +/***************************************************************************** + * Manage: manage main thread messages + ***************************************************************************** + * In this function, called approx. 10 times a second, we check what the + * main program wanted to tell us. + *****************************************************************************/ +void IntfWindow::Manage( void ) +{ + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = (input_thread_t *) + vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + /* Manage the slider */ + if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable ) + { + int i_value = p_slider->value(); + +#define p_area p_intf->p_sys->p_input->stream.p_selected_area + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( i_value == p_slider->oldvalue() ) + { + i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size; + + p_slider->setValue( i_value ); + p_slider->setOldValue( i_value ); + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else if( p_slider->b_free ) + { + off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX; + + input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET ); + + /* Update the old value */ + p_slider->setOldValue( i_value ); + } +#undef p_area + } + + /* If the "display popup" flag has changed, popup the context menu */ + if( p_intf->b_menu_change ) + { + p_popup->popup( QCursor::pos() ); + p_intf->b_menu_change = 0; + } + + if( p_intf->b_die ) + { + qApp->quit(); + } +} + +/***************************************************************************** + * PlaybackPlay: play + *****************************************************************************/ +void IntfWindow::PlaybackPlay( void ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + } +} + +/***************************************************************************** + * PlaybackPause: pause + *****************************************************************************/ +void IntfWindow::PlaybackPause( void ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE ); + } +} + +/***************************************************************************** + * PlaybackSlow: slow + *****************************************************************************/ +void IntfWindow::PlaybackSlow( void ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER ); + } +} + +/***************************************************************************** + * PlaybackFast: fast + *****************************************************************************/ +void IntfWindow::PlaybackFast( void ) +{ + if( p_intf->p_sys->p_input != NULL ) + { + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER ); + } +} + +/***************************************************************************** + * PlaylistPrev: previous playlist entry + *****************************************************************************/ +void IntfWindow::PlaylistPrev( void ) +{ + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } + + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); +} + +/***************************************************************************** + * PlaylistNext: next playlist entry + *****************************************************************************/ +void IntfWindow::PlaylistNext( void ) +{ + playlist_t *p_playlist = (playlist_t *) + vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } + + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); +} + +/***************************************************************************** + * IntfSlider: slider creator + ***************************************************************************** + * This function creates the slider, sets its default values, and connects + * the interesting signals. + *****************************************************************************/ +IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent ) + :QSlider( Horizontal, p_parent ) +{ + this->p_intf = p_intf; + + setRange( SLIDER_MIN, SLIDER_MAX ); + setPageStep( SLIDER_STEP ); + + setValue( SLIDER_MIN ); + setOldValue( SLIDER_MIN ); + + setTracking( TRUE ); + b_free = TRUE; + + connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) ); + connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) ); + connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) ); +} + +/***************************************************************************** + * ~IntfSlider: slider destructor + ***************************************************************************** + * This function is called when the interface slider is destroyed. + *****************************************************************************/ +IntfSlider::~IntfSlider( void ) +{ + /* We don't need to remove anything */ +} + + diff --git a/modules/gui/qt/qt.cpp b/modules/gui/qt/qt.cpp new file mode 100644 index 0000000000..62939a91ea --- /dev/null +++ b/modules/gui/qt/qt.cpp @@ -0,0 +1,52 @@ +/***************************************************************************** + * qt.cpp : Qt plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: qt.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(Open) ( vlc_object_t * ); +void E_(Close) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#ifdef WIN32 + int i = 80; +#else + int i = getenv( "DISPLAY" ) == NULL ? 7 : 80; +#endif + set_description( _("Qt interface module") ); + set_capability( "interface", i ); + set_program( "qvlc" ); + set_callbacks( E_(Open), E_(Close) ); +vlc_module_end(); + diff --git a/modules/gui/win32/.cvsignore b/modules/gui/win32/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/gui/win32/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/gui/win32/Makefile b/modules/gui/win32/Makefile new file mode 100644 index 0000000000..62ef5e89e9 --- /dev/null +++ b/modules/gui/win32/Makefile @@ -0,0 +1,12 @@ +# +# Borland C++ project +# we override everything by setting win32_CUSTOM +# +win32_CUSTOM = yes + +../win32.so: Makefile + rm -f win32.mak + $(BCBUILDER)/Bin/bpr2mak win32.bpr -s | sed 's#^LIBPATH = .*#&;$$(RELEASELIBPATH)# ; s#^USERDEFINES = .*#& -DWIN32 -D__PLUGIN__ -D__VLC__ -DMODULE_NAME_IS_win32 -DMODULE_NAME=win32#' > win32.mak + $(BCBUILDER)/Bin/make -f win32.mak -b + + diff --git a/modules/gui/win32/about.cpp b/modules/gui/win32/about.cpp new file mode 100644 index 0000000000..10c307e281 --- /dev/null +++ b/modules/gui/win32/about.cpp @@ -0,0 +1,47 @@ +/***************************************************************************** + * about.cpp: The "About" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include +#include + +#include "about.h" +#include "win32_common.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + +//--------------------------------------------------------------------------- +__fastcall TAboutDlg::TAboutDlg( TComponent* Owner ) + : TForm( Owner ) +{ + Image1->Picture->Icon = p_intfGlobal->p_sys->p_window->Icon; + LabelVersion->Caption = "Version " VLC_VERSION; +} +//--------------------------------------------------------------------------- + + diff --git a/modules/gui/win32/about.dfm b/modules/gui/win32/about.dfm new file mode 100644 index 0000000000..76cfa5aa45 --- /dev/null +++ b/modules/gui/win32/about.dfm @@ -0,0 +1,316 @@ +object AboutDlg: TAboutDlg + Left = 442 + Top = 281 + BorderStyle = bsDialog + Caption = 'About' + ClientHeight = 214 + ClientWidth = 286 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Icon.Data = { + 0000010001003030000001001800A81C00001600000028000000300000006000 + 00000100180000000000001B0000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000069375900000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000120E0A4011253E0F18000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000F0B + 084143CA08070016430F08040800000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000003127291203174647E8464AE808010840E54039E6390B0C06 + 0E0A1C0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0070CD0079DD0079DD0070CD0000000000000000000C1008261D6E4647E54547 + E64748E105040039E6393AE53939E63936D33308030100000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000070CD0079DD0079DE007DE40088F9008CFF008CFF0088F9007CE302 + 6EC70B09124641DC4444DF4546E34446E54847E003040040E6403AEA3A3EE33E + 3CE33C39E639080F010801050000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0079DD0077D90070CB0078D8007BDC007BDC007BDC + 007BDC007BDC007BDD007EE32E232D0804084553F14250F34252ED4449DB4844 + DC4645E208010540E5401C78150D18053CE63C3AE63A39EA393CD83C241A2006 + 0402000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0079DD007ADF007BDE007BDC0072 + CC005188004877004876004876004876034976054A760B4D7731434221175B42 + 54EC4253EE4252F60B05104250F44252EB4546DA08010539E6392BAA2B080105 + 3CE63C39E7393AE63A39E93939E839081208181C080000000000000000000000 + 000000000000000000000000000000000000000070CD0079DD0079DD007CE300 + 88F90089F90075D2005188004877005188008CFF008CFF008CFF008CFF008CFF + 1092FF2099FF31A0FF1408294840DB4550E1464EEA0C060B0B05084654F64653 + F64453EF080E033AE63A2BAA2B03030339E33939DF3939E639080F083DDB3D24 + 9C24434B3B000000000000000000000000000000000000000000000000000000 + 0063B60085F3008BFE0088F9007FE90088F90080E8005CA0008CFF008CFF008C + FF008CFF008CFF008CFF008CFF048DFF1594FF259BFF35A2FF0C04103F38C754 + 5AF7505BF10C08100801084352F64652F44253F30813053AE63A39E639030403 + 1C521826A1250812010807032454131558150000000000000000000000000000 + 000000000000000000000000000000000000000070CD007CE30079DD00000000 + 7CE30089FA008CFF0089FA008CFF008CFF008CFF008CFF008CFF008CFF098FFF + 1996FF2A9DFF3AA4FF0804103A2AA34E58F74E58F40B0B120803054652F34548 + E64451F305130532CA323AE23A03070308070307040008040139E63939E43931 + B42F5E1347000000000000000000000000000000000000000000000000000000 + 0000000000000000000061B10000000079DD008CFF008CFF008CFF008CFF008C + FF008CFF008CFF008CFF008CFF0E91FF1E98FF2E9FFF3FA6FF040408382BAF4D + 5AEF555AF70F12250501050F04160804074250F3121A123AE93A39E239080803 + 0D2F08010401268C2539E7393DE63D3FE23E0804100000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 79DD008CFF008CFF008CFF008CFF008CFF008CFF008CFF008CFF028CFF1293FF + 239AFF33A1FF43A8FF0802083A2AA3565BF7555AF71714330501050104000801 + 07424FF12828203AEA3A39E639030703182F1008340801040139E7393DE83D39 + E939080400000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0088F9008CFF008CFF008CFF008C + FF008CFF008CFF008CFF078EFF1795FF279CFF38A3FF48AAFF0808005151F155 + 5AF30804030804000504050800082E358E0E0C1F1D192439E53940E640080400 + 2AA12739E63908020708010539E8393BE93B0804080000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000007CE3008CFF008CFF008CFF058EFD1D96F92398F8269AFA31A0FC42A8FF + 4FAEFF5CB3FF65B7FF0C08084F5AF14E57F50B04080804043639A54647E81C13 + 49363AA70804080F120835953439E7393EE63E39DF3939EA39081105308A2B3F + E73F080601000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000047BDB1D96F92398F82498F83BA0 + F399C1E1B1C9DDBCD4E7CBE0F3D9EDFFDCEEFFDEEFFFCDE8FF080808575BF750 + 58F624125A5057F34845DF4A41E0150E30C55734E3723EC56E33A23D27050105 + 39E43939E63939E6393CE63C14420C3BE03B192A090000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000004 + 04042D88D399C1E1B1C9DDB1C9DCB7CBDBCFD3D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFF9FCFF0C08085D61F15B61EF555AF64A4FE13937BB0E0A12DE74 + 39E1733CDE713CDF753AE67541C36B342C231F17141B3AE63A39E7393DE83D39 + E93939DE39000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000001818186893B8C3CCD2D5D5D6D5D5D6D5D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFFFFFFFFFFFF140C145C5EF668 + 63F75555EA10061CC3673FDF713A0C1104080403080105080007070407D56F36 + DE743EDE72401C200C29452939E63939E73939EA390000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000343434A2B4C2D5D5D6D6D6D6D6D6D6D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFFEFEFF20161C5C5EF6373EAE0E0413E2713DE1763CCD6A3C2A0D + 08A44B2CDE743EBD612F080401030403E1713CDE7239DE713AE1723C22201139 + C13341E641000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001B1B1B99AEBED5D5D6D5D5D6D5D5 + D6CFD3D7B8CBDBBFD5E7CEE2F3DCEFFFDFF0FFE2F1FFE9F4FF10100C3639A46E + 4540DE7239DE713DE1713C07000784261CDE7639E3743E0812001F0407D86E36 + E3753EE57540E57541DE763CDE733DD26637493C387E2F7B0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00001B1B1B99AEBFCED3D7B7CBDBB1C9DD99C1E140A2F339A2FA49AAFC59B2FF + 66B8FF74BEFF92CBFFD9ECFF0F0402C66531DE7139E2733D854B1E0A01084D11 + 0DE3733EE1723CDF713ADF753AE1763C1D0A08290708E57140E1763CDE733DC7 + 6B34080408000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001818187FA5C399C1E13BA0F32498 + F81D96F91091FD1C97FF2C9EFF3CA5FF4DACFF5DB3FF71BBFF8DC8FF9FD0FF08 + 0400080406B95C2EDE7239070B070803014D1615DE723CDE7540E5714030090D + 0504003A120FE67541DE75390808044A0C290000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000707071778C81C92F3058EFD008CFF008CFF1092FF2099FF31A0FF41A7FF + 51AEFF62B5FF72BCFF7BBFFF7BBBF96E9FCD0808080806041D0508E571403E22 + 0C200708080405070407070007080303B05F31DE723967301908010500000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000007CE3008CFF008C + FF048DFF1594FF259BFF35A2FF46A9FF56B0FF66B7FF77BEFF7BBFFF6DAAE300 + 0000000000000000000000080401200C088D4024E17141E57140DF713ADE713E + DE76390801070000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000079DD008CFF008CFF098FFF1996FF2A9DFF3AA4FF4AABFF + 5BB2FF6BB9FF7BBFFF7BBFFF6AA5DD0000000000000000000000000000001D1A + 0C1A0F08110903441912E57140623B1E08020300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000079DD008CFF008C + FF0E91FF1E98FF2E9FFF3FA6FF4FADFF5FB4FF70BBFF7BBFFF78BAF96299CD00 + 00000000000000000000000000000000000000003914100000005A2411000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0088F9078EFD2C9CF940A3F850ACFA60B4FC70BCFF + 7DC2FF87C6FF7EC0FF6DAAE30000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000707071A85DD40A2 + F3A0C3E1B7CBDDC6D8E7D4E5F3E2F1FFE5F2FFD9ECFF9FD0FF7AACDD05050500 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001818187FA5C3B8CBDBD0D4D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFAFCFFE2EDF99FB7CD1C1C1C0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000001B1B1B99AEBFD4D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFEFEFFD1DAE33E3E3E00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001D1D1D7B9BB4CACED1D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFC9D2DD2121210000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000343434A5B5 + C2CFD3D7BFCEDBC9D9E7D7E6F3E6F3FFECF5FFF0F4F9AEBDCD23232300000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000018181887A8C3A6C6E169B3F367B6FA77BEFC88C6FF + 9FD0FFB4CBE33939390000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000040404338C + D749A8F947A9FD54AFFF64B6FF74BDFF7EC0FF76ABDD05050500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000001F7DCD369FF948AAFF58B1FF69B8FF79BFFF + 78BAF96299CD0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003592E34DACFF5DB3FF6DBAFF7BBFFF6DAAE300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003890DD51AEFF62B5FF72BCFF7BBFFF + 6AA5DD0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003B8FD84C9CE3589FDE69A9E375B6F46299CD00000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003376B00000000000000000005788B6 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000006CC61A83DD247FCC00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000006DC71A83DD2686D71F6EB1 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFE1FDFFF0000FFFFE0078FFF0000FFFE + 000007FF0000FFF0000001FF0000FF80000000FF0000FF000000003F0000FF00 + 0000000F0000FE00000000070000F800000000070000F8000000000F0000FC00 + 000000070000FE00000000070000FF80000000070000FFC0000000070000FFE0 + 000000070000FFE0000000070000FFE0000000070000FFE0000000070000FFF0 + 000000070000FFF0000000030000FFF0000000070000FFF00000000F0000FFF0 + 0000003F0000FFF8000E00FF0000FFF8000F01FF0000FFF8000FD7FF0000FFF8 + 001FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC003FFFFF0000FFFC + 003FFFFF0000FFFE003FFFFF0000FFFE007FFFFF0000FFFE007FFFFF0000FFFE + 007FFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF + 01FFFFFF0000FFFF01FFFFFF0000FFFF81FFFFFF0000FFFFC3FFFFFF0000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000} + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 114 + Top = 18 + Width = 132 + Height = 20 + Caption = 'VideoLAN Client' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -16 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + end + object Label2: TLabel + Left = 10 + Top = 64 + Width = 267 + Height = 13 + Caption = '(C) Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002' + end + object Label4: TLabel + Left = 15 + Top = 123 + Width = 253 + Height = 39 + Caption = + 'This is the VideoLAN Client, a DVD, MPEG and DivX player. It can' + + ' play MPEG and MPEG 2 files from a file or from a network source' + + '.' + WordWrap = True + end + object Label3: TLabel + Left = 38 + Top = 80 + Width = 227 + Height = 13 + Caption = 'The VideoLAN Team ' + end + object Image1: TImage + Left = 32 + Top = 8 + Width = 49 + Height = 49 + end + object Label5: TLabel + Left = 82 + Top = 96 + Width = 121 + Height = 13 + Caption = 'http://www.videolan.org/' + end + object LabelVersion: TLabel + Left = 114 + Top = 40 + Width = 59 + Height = 13 + Caption = 'Version x.y.z' + end + object BitBtnOk: TBitBtn + Left = 64 + Top = 178 + Width = 145 + Height = 25 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 0 + end +end diff --git a/modules/gui/win32/about.h b/modules/gui/win32/about.h new file mode 100644 index 0000000000..d08caa9526 --- /dev/null +++ b/modules/gui/win32/about.h @@ -0,0 +1,50 @@ +/***************************************************************************** + * about.h: The "About" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef aboutH +#define aboutH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +//--------------------------------------------------------------------------- +class TAboutDlg : public TForm +{ +__published: // IDE-managed Components + TLabel *Label1; + TLabel *Label2; + TLabel *Label4; + TBitBtn *BitBtnOk; + TLabel *Label3; + TImage *Image1; + TLabel *Label5; + TLabel *LabelVersion; +private: // User declarations +public: // User declarations + __fastcall TAboutDlg( TComponent* Owner ); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/control.cpp b/modules/gui/win32/control.cpp new file mode 100644 index 0000000000..da70656d2c --- /dev/null +++ b/modules/gui/win32/control.cpp @@ -0,0 +1,120 @@ +/***************************************************************************** + * control.cpp: functions to handle stream control buttons. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 + +#include +#include + +#include "win32_common.h" + +extern intf_thread_t *p_intfGlobal; + +/**************************************************************************** + * Control functions: this is where the functions are defined + **************************************************************************** + * These functions are used by toolbuttons callbacks + ****************************************************************************/ +bool ControlBack( TObject *Sender ) +{ + /* FIXME: TODO */ + + return false; +} + + +bool ControlStop( TObject *Sender ) +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return false; + } + + playlist_Stop( p_playlist ); + vlc_object_release( p_playlist ); + + return true; +} + + +bool ControlPlay( TObject *Sender ) +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + p_intfGlobal->p_sys->p_window->MenuOpenFileClick( Sender ); + return false; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + if( p_playlist->i_size ) + { + vlc_mutex_unlock( &p_playlist->object_lock ); + playlist_Play( p_playlist ); + vlc_object_release( p_playlist ); + } + else + { + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + p_intfGlobal->p_sys->p_window->MenuOpenFileClick( Sender ); + } + + return true; +} + + +bool ControlPause( TObject *Sender ) +{ + if( p_intfGlobal->p_sys->p_input != NULL ) + { + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PAUSE ); + } + + return true; +} + + +bool ControlSlow( TObject *Sender ) +{ + if( p_intfGlobal->p_sys->p_input != NULL ) + { + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_SLOWER ); + } + + return true; +} + + +bool ControlFast( TObject *Sender ) +{ + if( p_intfGlobal->p_sys->p_input != NULL ) + { + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_FASTER ); + } + + return true; +} + diff --git a/modules/gui/win32/control.h b/modules/gui/win32/control.h new file mode 100644 index 0000000000..0ee1ebd07a --- /dev/null +++ b/modules/gui/win32/control.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * control.h: prototypes for control functions. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +bool ControlBack ( TObject *Sender ); +bool ControlStop ( TObject *Sender ); +bool ControlPlay ( TObject *Sender ); +bool ControlPause( TObject *Sender ); +bool ControlSlow ( TObject *Sender ); +bool ControlFast ( TObject *Sender ); + diff --git a/modules/gui/win32/disc.cpp b/modules/gui/win32/disc.cpp new file mode 100644 index 0000000000..fff7ca32b0 --- /dev/null +++ b/modules/gui/win32/disc.cpp @@ -0,0 +1,126 @@ +/***************************************************************************** + * disc.cpp: "Open disc" dialog box. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include +#include + +#include "disc.h" +#include "win32_common.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma link "CSPIN" +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + +//--------------------------------------------------------------------------- +__fastcall TDiscDlg::TDiscDlg( TComponent* Owner ) + : TForm( Owner ) +{ + /* Simulate a click to get the correct device name */ + RadioGroupTypeClick( RadioGroupType ); +} +//--------------------------------------------------------------------------- +void __fastcall TDiscDlg::FormShow( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuOpenDisc->Checked = true; + p_intfGlobal->p_sys->p_window->PopupOpenDisc->Checked = true; +} +//--------------------------------------------------------------------------- +void __fastcall TDiscDlg::FormHide( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuOpenDisc->Checked = false; + p_intfGlobal->p_sys->p_window->PopupOpenDisc->Checked = false; +} +//--------------------------------------------------------------------------- +void __fastcall TDiscDlg::BitBtnCancelClick( TObject *Sender ) +{ + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TDiscDlg::BitBtnOkClick( TObject *Sender ) +{ + AnsiString Device, Source, Method, Title, Chapter; + playlist_t * p_playlist; + + p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + Hide(); + + Device = EditDevice->Text; + + /* Check which method was activated */ + if( RadioGroupType->ItemIndex == 0 ) + { + Method = "dvd"; + } + else + { + Method = "vcd"; + } + + /* Select title and chapter */ + Title.sprintf( "%d", SpinEditTitle->Value ); + Chapter.sprintf( "%d", SpinEditChapter->Value ); + + /* Build source name and add it to playlist */ + Source = Method + ":" + Device + "@" + Title + "," + Chapter; + playlist_Add( p_playlist, Source.c_str(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* update the display */ + p_intfGlobal->p_sys->p_playwin->UpdateGrid( p_playlist ); + + vlc_object_release( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TDiscDlg::RadioGroupTypeClick( TObject *Sender ) +{ + TRadioGroup *RadioGroupType = (TRadioGroup *)Sender; + char *psz_device; + + if( RadioGroupType->ItemIndex == 0 ) + { + psz_device = config_GetPsz( p_intfGlobal, "dvd" ); + } + else + { + psz_device = config_GetPsz( p_intfGlobal, "vcd" ); + } + + if( psz_device ) + { + EditDevice->Text = psz_device; + free( psz_device ); + } +} +//--------------------------------------------------------------------------- + diff --git a/modules/gui/win32/disc.dfm b/modules/gui/win32/disc.dfm new file mode 100644 index 0000000000..a86d5303ed --- /dev/null +++ b/modules/gui/win32/disc.dfm @@ -0,0 +1,345 @@ +object DiscDlg: TDiscDlg + Left = 503 + Top = 366 + BorderStyle = bsDialog + Caption = 'Open disc' + ClientHeight = 170 + ClientWidth = 258 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Icon.Data = { + 0000010001003030000001001800A81C00001600000028000000300000006000 + 00000100180000000000001B0000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000069375900000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000120E0A4011253E0F18000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000F0B + 084143CA08070016430F08040800000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000003127291203174647E8464AE808010840E54039E6390B0C06 + 0E0A1C0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0070CD0079DD0079DD0070CD0000000000000000000C1008261D6E4647E54547 + E64748E105040039E6393AE53939E63936D33308030100000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000070CD0079DD0079DE007DE40088F9008CFF008CFF0088F9007CE302 + 6EC70B09124641DC4444DF4546E34446E54847E003040040E6403AEA3A3EE33E + 3CE33C39E639080F010801050000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0079DD0077D90070CB0078D8007BDC007BDC007BDC + 007BDC007BDC007BDD007EE32E232D0804084553F14250F34252ED4449DB4844 + DC4645E208010540E5401C78150D18053CE63C3AE63A39EA393CD83C241A2006 + 0402000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0079DD007ADF007BDE007BDC0072 + CC005188004877004876004876004876034976054A760B4D7731434221175B42 + 54EC4253EE4252F60B05104250F44252EB4546DA08010539E6392BAA2B080105 + 3CE63C39E7393AE63A39E93939E839081208181C080000000000000000000000 + 000000000000000000000000000000000000000070CD0079DD0079DD007CE300 + 88F90089F90075D2005188004877005188008CFF008CFF008CFF008CFF008CFF + 1092FF2099FF31A0FF1408294840DB4550E1464EEA0C060B0B05084654F64653 + F64453EF080E033AE63A2BAA2B03030339E33939DF3939E639080F083DDB3D24 + 9C24434B3B000000000000000000000000000000000000000000000000000000 + 0063B60085F3008BFE0088F9007FE90088F90080E8005CA0008CFF008CFF008C + FF008CFF008CFF008CFF008CFF048DFF1594FF259BFF35A2FF0C04103F38C754 + 5AF7505BF10C08100801084352F64652F44253F30813053AE63A39E639030403 + 1C521826A1250812010807032454131558150000000000000000000000000000 + 000000000000000000000000000000000000000070CD007CE30079DD00000000 + 7CE30089FA008CFF0089FA008CFF008CFF008CFF008CFF008CFF008CFF098FFF + 1996FF2A9DFF3AA4FF0804103A2AA34E58F74E58F40B0B120803054652F34548 + E64451F305130532CA323AE23A03070308070307040008040139E63939E43931 + B42F5E1347000000000000000000000000000000000000000000000000000000 + 0000000000000000000061B10000000079DD008CFF008CFF008CFF008CFF008C + FF008CFF008CFF008CFF008CFF0E91FF1E98FF2E9FFF3FA6FF040408382BAF4D + 5AEF555AF70F12250501050F04160804074250F3121A123AE93A39E239080803 + 0D2F08010401268C2539E7393DE63D3FE23E0804100000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 79DD008CFF008CFF008CFF008CFF008CFF008CFF008CFF008CFF028CFF1293FF + 239AFF33A1FF43A8FF0802083A2AA3565BF7555AF71714330501050104000801 + 07424FF12828203AEA3A39E639030703182F1008340801040139E7393DE83D39 + E939080400000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0088F9008CFF008CFF008CFF008C + FF008CFF008CFF008CFF078EFF1795FF279CFF38A3FF48AAFF0808005151F155 + 5AF30804030804000504050800082E358E0E0C1F1D192439E53940E640080400 + 2AA12739E63908020708010539E8393BE93B0804080000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000007CE3008CFF008CFF008CFF058EFD1D96F92398F8269AFA31A0FC42A8FF + 4FAEFF5CB3FF65B7FF0C08084F5AF14E57F50B04080804043639A54647E81C13 + 49363AA70804080F120835953439E7393EE63E39DF3939EA39081105308A2B3F + E73F080601000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000047BDB1D96F92398F82498F83BA0 + F399C1E1B1C9DDBCD4E7CBE0F3D9EDFFDCEEFFDEEFFFCDE8FF080808575BF750 + 58F624125A5057F34845DF4A41E0150E30C55734E3723EC56E33A23D27050105 + 39E43939E63939E6393CE63C14420C3BE03B192A090000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000004 + 04042D88D399C1E1B1C9DDB1C9DCB7CBDBCFD3D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFF9FCFF0C08085D61F15B61EF555AF64A4FE13937BB0E0A12DE74 + 39E1733CDE713CDF753AE67541C36B342C231F17141B3AE63A39E7393DE83D39 + E93939DE39000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000001818186893B8C3CCD2D5D5D6D5D5D6D5D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFFFFFFFFFFFF140C145C5EF668 + 63F75555EA10061CC3673FDF713A0C1104080403080105080007070407D56F36 + DE743EDE72401C200C29452939E63939E73939EA390000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000343434A2B4C2D5D5D6D6D6D6D6D6D6D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFFEFEFF20161C5C5EF6373EAE0E0413E2713DE1763CCD6A3C2A0D + 08A44B2CDE743EBD612F080401030403E1713CDE7239DE713AE1723C22201139 + C13341E641000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001B1B1B99AEBED5D5D6D5D5D6D5D5 + D6CFD3D7B8CBDBBFD5E7CEE2F3DCEFFFDFF0FFE2F1FFE9F4FF10100C3639A46E + 4540DE7239DE713DE1713C07000784261CDE7639E3743E0812001F0407D86E36 + E3753EE57540E57541DE763CDE733DD26637493C387E2F7B0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00001B1B1B99AEBFCED3D7B7CBDBB1C9DD99C1E140A2F339A2FA49AAFC59B2FF + 66B8FF74BEFF92CBFFD9ECFF0F0402C66531DE7139E2733D854B1E0A01084D11 + 0DE3733EE1723CDF713ADF753AE1763C1D0A08290708E57140E1763CDE733DC7 + 6B34080408000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001818187FA5C399C1E13BA0F32498 + F81D96F91091FD1C97FF2C9EFF3CA5FF4DACFF5DB3FF71BBFF8DC8FF9FD0FF08 + 0400080406B95C2EDE7239070B070803014D1615DE723CDE7540E5714030090D + 0504003A120FE67541DE75390808044A0C290000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000707071778C81C92F3058EFD008CFF008CFF1092FF2099FF31A0FF41A7FF + 51AEFF62B5FF72BCFF7BBFFF7BBBF96E9FCD0808080806041D0508E571403E22 + 0C200708080405070407070007080303B05F31DE723967301908010500000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000007CE3008CFF008C + FF048DFF1594FF259BFF35A2FF46A9FF56B0FF66B7FF77BEFF7BBFFF6DAAE300 + 0000000000000000000000080401200C088D4024E17141E57140DF713ADE713E + DE76390801070000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000079DD008CFF008CFF098FFF1996FF2A9DFF3AA4FF4AABFF + 5BB2FF6BB9FF7BBFFF7BBFFF6AA5DD0000000000000000000000000000001D1A + 0C1A0F08110903441912E57140623B1E08020300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000079DD008CFF008C + FF0E91FF1E98FF2E9FFF3FA6FF4FADFF5FB4FF70BBFF7BBFFF78BAF96299CD00 + 00000000000000000000000000000000000000003914100000005A2411000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0088F9078EFD2C9CF940A3F850ACFA60B4FC70BCFF + 7DC2FF87C6FF7EC0FF6DAAE30000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000707071A85DD40A2 + F3A0C3E1B7CBDDC6D8E7D4E5F3E2F1FFE5F2FFD9ECFF9FD0FF7AACDD05050500 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001818187FA5C3B8CBDBD0D4D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFAFCFFE2EDF99FB7CD1C1C1C0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000001B1B1B99AEBFD4D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFEFEFFD1DAE33E3E3E00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001D1D1D7B9BB4CACED1D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFC9D2DD2121210000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000343434A5B5 + C2CFD3D7BFCEDBC9D9E7D7E6F3E6F3FFECF5FFF0F4F9AEBDCD23232300000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000018181887A8C3A6C6E169B3F367B6FA77BEFC88C6FF + 9FD0FFB4CBE33939390000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000040404338C + D749A8F947A9FD54AFFF64B6FF74BDFF7EC0FF76ABDD05050500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000001F7DCD369FF948AAFF58B1FF69B8FF79BFFF + 78BAF96299CD0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003592E34DACFF5DB3FF6DBAFF7BBFFF6DAAE300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003890DD51AEFF62B5FF72BCFF7BBFFF + 6AA5DD0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003B8FD84C9CE3589FDE69A9E375B6F46299CD00000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003376B00000000000000000005788B6 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000006CC61A83DD247FCC00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000006DC71A83DD2686D71F6EB1 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFE1FDFFF0000FFFFE0078FFF0000FFFE + 000007FF0000FFF0000001FF0000FF80000000FF0000FF000000003F0000FF00 + 0000000F0000FE00000000070000F800000000070000F8000000000F0000FC00 + 000000070000FE00000000070000FF80000000070000FFC0000000070000FFE0 + 000000070000FFE0000000070000FFE0000000070000FFE0000000070000FFF0 + 000000070000FFF0000000030000FFF0000000070000FFF00000000F0000FFF0 + 0000003F0000FFF8000E00FF0000FFF8000F01FF0000FFF8000FD7FF0000FFF8 + 001FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC003FFFFF0000FFFC + 003FFFFF0000FFFE003FFFFF0000FFFE007FFFFF0000FFFE007FFFFF0000FFFE + 007FFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF + 01FFFFFF0000FFFF01FFFFFF0000FFFF81FFFFFF0000FFFFC3FFFFFF0000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000} + OldCreateOrder = False + OnHide = FormHide + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object LabelDevice: TLabel + Left = 8 + Top = 105 + Width = 63 + Height = 13 + Caption = 'Device name' + end + object GroupBoxPosition: TGroupBox + Left = 96 + Top = 8 + Width = 153 + Height = 81 + Caption = 'Starting position' + TabOrder = 1 + object LabelTitle: TLabel + Left = 16 + Top = 24 + Width = 20 + Height = 13 + Caption = 'Title' + end + object LabelChapter: TLabel + Left = 16 + Top = 52 + Width = 37 + Height = 13 + Caption = 'Chapter' + end + object SpinEditTitle: TCSpinEdit + Left = 64 + Top = 19 + Width = 73 + Height = 22 + TabStop = True + MaxValue = 65535 + MinValue = 1 + ParentColor = False + TabOrder = 0 + Value = 1 + end + object SpinEditChapter: TCSpinEdit + Left = 64 + Top = 47 + Width = 73 + Height = 22 + TabStop = True + MaxValue = 65535 + MinValue = 1 + ParentColor = False + TabOrder = 1 + Value = 1 + end + end + object RadioGroupType: TRadioGroup + Left = 8 + Top = 8 + Width = 81 + Height = 81 + Caption = 'Disc type' + ItemIndex = 0 + Items.Strings = ( + 'DVD' + 'VCD') + TabOrder = 0 + OnClick = RadioGroupTypeClick + end + object BitBtnOk: TBitBtn + Left = 8 + Top = 136 + Width = 113 + Height = 25 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 3 + OnClick = BitBtnOkClick + end + object BitBtnCancel: TBitBtn + Left = 136 + Top = 136 + Width = 113 + Height = 25 + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 4 + OnClick = BitBtnCancelClick + end + object EditDevice: TEdit + Left = 88 + Top = 101 + Width = 161 + Height = 21 + TabOrder = 2 + Text = 'F:\' + end +end diff --git a/modules/gui/win32/disc.h b/modules/gui/win32/disc.h new file mode 100644 index 0000000000..1e2646d606 --- /dev/null +++ b/modules/gui/win32/disc.h @@ -0,0 +1,58 @@ +/***************************************************************************** + * disc.h: "Open disc" dialog box. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef discH +#define discH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include "CSPIN.h" +//--------------------------------------------------------------------------- +class TDiscDlg : public TForm +{ +__published: // IDE-managed Components + TLabel *LabelDevice; + TGroupBox *GroupBoxPosition; + TLabel *LabelTitle; + TLabel *LabelChapter; + TRadioGroup *RadioGroupType; + TBitBtn *BitBtnOk; + TBitBtn *BitBtnCancel; + TEdit *EditDevice; + TCSpinEdit *SpinEditTitle; + TCSpinEdit *SpinEditChapter; + void __fastcall FormShow(TObject *Sender); + void __fastcall FormHide(TObject *Sender); + void __fastcall BitBtnCancelClick(TObject *Sender); + void __fastcall BitBtnOkClick(TObject *Sender); + void __fastcall RadioGroupTypeClick(TObject *Sender); +private: // User declarations +public: // User declarations + __fastcall TDiscDlg( TComponent* Owner ); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/intfwin.bpf b/modules/gui/win32/intfwin.bpf new file mode 100644 index 0000000000..24e5c00d88 --- /dev/null +++ b/modules/gui/win32/intfwin.bpf @@ -0,0 +1,16 @@ +USEUNIT("win32.cpp"); +USEUNIT("intf_win32.cpp"); +USEFORM("mainframe.cpp", MainFrameDlg); +USEFORM("network.cpp", NetworkDlg); +USEFORM("playlist.cpp", PlaylistDlg); +USEFORM("preferences.cpp", PreferencesDlg); +USEFORM("about.cpp", AboutDlg); +USEFORM("disc.cpp", DiscDlg); +USEUNIT("control.cpp"); +USE("win32_common.h", File); +USEUNIT("menu.cpp"); +USEFORM("messages.cpp", MessagesDlg); +//--------------------------------------------------------------------------- +This file is used by the project manager only and should be treated like the project file + + DllEntryPoint \ No newline at end of file diff --git a/modules/gui/win32/intfwin.cpp b/modules/gui/win32/intfwin.cpp new file mode 100644 index 0000000000..267d765e22 --- /dev/null +++ b/modules/gui/win32/intfwin.cpp @@ -0,0 +1,239 @@ +/***************************************************************************** + * intfwin.cpp: Win32 interface plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teulière + * + * 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 +#include /* malloc(), free() */ +#include /* ENOMEM */ +#include /* strerror() */ + +#include +#include + +#include "mainframe.h" +#include "menu.h" +#include "win32_common.h" + +intf_thread_t *p_intfGlobal; + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static void intf_Run ( intf_thread_t *p_intf ); + +int Win32Manage( void *p_data ); + +/***************************************************************************** + * Open: initialize interface + *****************************************************************************/ +int E_(Open)( 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 = (intf_sys_t *) malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + }; + + p_intfGlobal = p_intf; + p_intf->pf_run = intf_Run; + + p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + + /* Initialize Win32 thread */ + p_intf->p_sys->b_playing = 0; + p_intf->p_sys->b_popup_changed = 0; + + p_intf->p_sys->p_input = NULL; + p_intf->p_sys->i_playing = -1; + p_intf->p_sys->b_slider_free = 1; + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface + *****************************************************************************/ +void E_(Close)( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + } + + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * intf_Run: main loop + *****************************************************************************/ +static void intf_Run( intf_thread_t *p_intf ) +{ + p_intf->p_sys->p_window = new TMainFrameDlg( NULL ); + p_intf->p_sys->p_playwin = new TPlaylistDlg( NULL ); + p_intf->p_sys->p_messages = new TMessagesDlg( NULL ); + + /* show main window and wait until it is closed */ + p_intf->p_sys->p_window->ShowModal(); + + if( p_intf->p_sys->p_disc ) delete p_intf->p_sys->p_disc; + if( p_intf->p_sys->p_network ) delete p_intf->p_sys->p_network; + if( p_intf->p_sys->p_preferences ) delete p_intf->p_sys->p_preferences; + delete p_intf->p_sys->p_messages; + delete p_intf->p_sys->p_playwin; +} + +/***************************************************************************** + * Win32Manage: manage main thread messages + ***************************************************************************** + * In this function, called approx. 10 times a second, we check what the + * main program wanted to tell us. + *****************************************************************************/ +int Win32Manage( intf_thread_t *p_intf ) +{ + vlc_mutex_lock( &p_intf->change_lock ); + + /* If the "display popup" flag has changed */ + if( p_intf->b_menu_change ) + { + /* FIXME: It would be nice to close the popup when the user left-clicks + elsewhere, or to actualize the position when he right-clicks again, + but i couldn't find a way to close it :-( */ + TPoint MousePos = Mouse->CursorPos; + p_intf->p_sys->p_window->PopupMenuMain->Popup( MousePos.x, MousePos.y ); + p_intf->b_menu_change = 0; + } + + /* Update the log window */ + p_intf->p_sys->p_messages->UpdateLog(); + + /* Update the playlist */ + p_intf->p_sys->p_playwin->Manage( p_intf ); + + /* Update the input */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = (input_thread_t *) + vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + + if( p_intf->p_sys->p_input ) + { + input_thread_t *p_input = p_intf->p_sys->p_input; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( !p_input->b_die ) + { + /* New input or stream map change */ + if( p_input->stream.b_changed ) + { + p_intf->p_sys->p_window->ModeManage(); + SetupMenus( p_intf ); + p_intf->p_sys->b_playing = 1; + } + + /* Manage the slider */ + if( p_input->stream.b_seekable && p_intf->p_sys->b_playing ) + { + TTrackBar * TrackBar = p_intf->p_sys->p_window->TrackBar; + off_t NewValue = TrackBar->Position; + +#define p_area p_input->stream.p_selected_area + /* If the user hasn't touched the slider since the last time, + * then the input can safely change it */ + if( NewValue == p_intf->p_sys->OldValue ) + { + /* Update the value */ + TrackBar->Position = p_intf->p_sys->OldValue = + ( (off_t)SLIDER_MAX_VALUE * p_area->i_tell ) / + p_area->i_size; + } + /* Otherwise, send message to the input if the user has + * finished dragging the slider */ + else if( p_intf->p_sys->b_slider_free ) + { + off_t i_seek = ( NewValue * p_area->i_size ) / + (off_t)SLIDER_MAX_VALUE; + + /* release the lock to be able to seek */ + vlc_mutex_unlock( &p_input->stream.stream_lock ); + input_Seek( p_input, i_seek, INPUT_SEEK_SET ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* Update the old value */ + p_intf->p_sys->OldValue = NewValue; + } + + /* Update the display */ +// TrackBar->Invalidate(); + +# undef p_area + } + + if( p_intf->p_sys->i_part != + p_input->stream.p_selected_area->i_part ) + { +// p_intf->p_sys->b_chapter_update = 1; + SetupMenus( p_intf ); + } + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + else if( p_intf->p_sys->b_playing && !p_intf->b_die ) + { + p_intf->p_sys->p_window->ModeManage(); + p_intf->p_sys->b_playing = 0; + } + + if( p_intf->b_die ) + { + vlc_mutex_unlock( &p_intf->change_lock ); + + /* Prepare to die, young Skywalker */ + p_intf->p_sys->p_window->ModalResult = mrOk; + + /* Just in case */ + return( FALSE ); + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + return( TRUE ); +} + diff --git a/modules/gui/win32/mainframe.cpp b/modules/gui/win32/mainframe.cpp new file mode 100644 index 0000000000..7a8f6a277f --- /dev/null +++ b/modules/gui/win32/mainframe.cpp @@ -0,0 +1,736 @@ +/***************************************************************************** + * mainframe.cpp: Win32 interface plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teulière + * + * 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 +#pragma hdrstop + +#include +#include +#include + +#include "mainframe.h" +#include "menu.h" +#include "control.h" +#include "disc.h" +#include "network.h" +#include "about.h" +#include "preferences.h" +#include "messages.h" +#include "playlist.h" +#include "win32_common.h" + +#include "netutils.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma link "CSPIN" +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; +extern int Win32Manage( intf_thread_t *p_intf ); + +//--------------------------------------------------------------------------- +__fastcall TMainFrameDlg::TMainFrameDlg( TComponent* Owner ) + : TForm( Owner ) +{ + Application->ShowHint = true; + Application->OnHint = DisplayHint; + + TimerManage->Interval = INTF_IDLE_SLEEP / 1000; + + TrackBar->Max = SLIDER_MAX_VALUE; + + /* default height and caption */ + ClientHeight = 37 + ToolBar->Height; + Caption = VOUT_TITLE " (Win32 interface)"; + + StringListPref = new TStringList(); +} +//--------------------------------------------------------------------------- +__fastcall TMainFrameDlg::~TMainFrameDlg() +{ + delete StringListPref; +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Event handlers + ****************************************************************************/ +void __fastcall TMainFrameDlg::TimerManageTimer( TObject *Sender ) +{ + Win32Manage( p_intfGlobal ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::DisplayHint( TObject *Sender ) +{ + StatusBar->SimpleText = GetLongHint( Application->Hint ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::TrackBarChange( TObject *Sender ) +{ + /* This function displays the current date related to the position in + * the stream. It is called whenever the slider changes its value. + * The lock has to be taken before the function is called */ + +// vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + + if( p_intfGlobal->p_sys->p_input != NULL ) + { +#define p_area p_intfGlobal->p_sys->p_input->stream.p_selected_area + char psz_time[ OFFSETTOTIME_MAX_SIZE ]; + off_t Value = TrackBar->Position; + + GroupBoxSlider->Caption = + input_OffsetToTime( p_intfGlobal->p_sys->p_input, psz_time, + ( p_area->i_size * Value ) / (off_t)SLIDER_MAX_VALUE ); +#undef p_area + } + +// vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::FormClose( TObject *Sender, + TCloseAction &Action ) +{ + intf_thread_t *p_intf = p_intfGlobal; + + vlc_mutex_lock( &p_intf->change_lock ); + p_intf->p_vlc->b_die = VLC_TRUE; + vlc_mutex_unlock( &p_intf->change_lock ); + + /* we don't destroy the form immediatly */ + Action = caHide; +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Menu callbacks + ****************************************************************************/ +void __fastcall TMainFrameDlg::MenuOpenFileClick( TObject *Sender ) +{ + AnsiString FileName; + playlist_t * p_playlist; + + p_playlist = (playlist_t *)vlc_object_find( p_intfGlobal, + VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + if( OpenDialog1->Execute() ) + { + /* add the new file to the interface playlist */ + FileName = OpenDialog1->FileName; + playlist_Add( p_playlist, (char*)FileName.c_str(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* update the plugin display */ + p_intfGlobal->p_sys->p_playwin->UpdateGrid( p_playlist ); + }; + + vlc_object_release( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuOpenDiscClick( TObject *Sender ) +{ + TDiscDlg *p_disc = p_intfGlobal->p_sys->p_disc; + if( p_disc == NULL ) + { + p_disc = new TDiscDlg( this ); + p_intfGlobal->p_sys->p_disc = p_disc; + } + p_disc->Show(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuNetworkStreamClick( TObject *Sender ) +{ + TNetworkDlg *p_network = p_intfGlobal->p_sys->p_network; + if( p_network == NULL ) + { + p_network = new TNetworkDlg( this ); + p_intfGlobal->p_sys->p_network = p_network; + } + p_network->Show(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuExitClick( TObject *Sender ) +{ + Close(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuHideinterfaceClick( TObject *Sender ) +{ + this->SendToBack(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuFullscreenClick( TObject *Sender ) +{ + vout_thread_t *p_vout; + + p_vout = (vout_thread_t *)vlc_object_find( p_intfGlobal->p_sys->p_input, + VLC_OBJECT_VOUT, FIND_CHILD ); + if( p_vout == NULL ) + { + return; + } + + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_object_release( p_vout ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuPlaylistClick( TObject *Sender ) +{ + TPlaylistDlg *p_playwin = p_intfGlobal->p_sys->p_playwin; + if( p_playwin->Visible ) + { + p_playwin->Hide(); + } + else + { + playlist_t * p_playlist; + p_playlist = (playlist_t *)vlc_object_find( p_intfGlobal, + VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + p_playwin->UpdateGrid( p_playlist ); + vlc_object_release( p_playlist ); + p_playwin->Show(); + } +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuMessagesClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_messages->Show(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuPreferencesClick( TObject *Sender ) +{ + CreatePreferences( "main" ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::MenuAboutClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_about = new TAboutDlg( this ); + p_intfGlobal->p_sys->p_about->ShowModal(); + delete p_intfGlobal->p_sys->p_about; +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Toolbar callbacks + ****************************************************************************/ +void __fastcall TMainFrameDlg::ToolButtonFileClick( TObject *Sender ) +{ + MenuOpenFileClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonDiscClick( TObject *Sender ) +{ + MenuOpenDiscClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonNetClick( TObject *Sender ) +{ + MenuNetworkStreamClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonPlaylistClick( TObject *Sender ) +{ + MenuPlaylistClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonBackClick( TObject *Sender ) +{ + ControlBack( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonStopClick( TObject *Sender ) +{ + ControlStop( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonPlayClick( TObject *Sender ) +{ + ControlPlay( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonPauseClick( TObject *Sender ) +{ + ControlPause( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonSlowClick( TObject *Sender ) +{ + ControlSlow( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonFastClick( TObject *Sender ) +{ + ControlFast( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonPrevClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_playwin->Previous(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonNextClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_playwin->Next(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ToolButtonEjectClick( TObject *Sender ) +{ + AnsiString Device = ""; + char * psz_current; + playlist_t * p_playlist; + + p_playlist = (playlist_t *)vlc_object_find( p_intfGlobal, + VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + /* + * Get the active input + * Determine whether we can eject a media, ie it's a VCD or DVD + * If it's neither a VCD nor a DVD, then return + */ + + vlc_mutex_lock( &p_playlist->object_lock ); + psz_current = p_playlist->pp_items[ p_playlist->i_index ]->psz_name; + + if( psz_current != NULL ) + { + if( strncmp( psz_current, "dvd", 3 ) + || strncmp( psz_current, "vcd", 3 ) ) + { + /* Determine the device name by omitting the first 4 characters + * and keeping 3 characters */ + Device = strdup( ( psz_current + 4 ) ); + Device = Device.SubString( 1, 2 ); + } + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); + + if( Device == "" ) + { + return; + } + + /* If there's a stream playing, we aren't allowed to eject ! */ + if( p_intfGlobal->p_sys->p_input == NULL ) + { + msg_Dbg( p_intfGlobal, "ejecting %s", Device.c_str() ); + + intf_Eject( p_intfGlobal, Device.c_str() ); + } +} +//-------------------------------------------------------------------------- + + +/***************************************************************************** + * Popup callbacks + ****************************************************************************/ +void __fastcall TMainFrameDlg::PopupCloseClick( TObject *Sender ) +{ + /* We do nothing, we just need a click on a menu item + * to close the popup. Don't ask me why... */ + return; +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupPlayClick( TObject *Sender ) +{ + ToolButtonPlayClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupPauseClick( TObject *Sender ) +{ + ToolButtonPauseClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupStopClick( TObject *Sender ) +{ + ToolButtonStopClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupBackClick( TObject *Sender ) +{ + ToolButtonBackClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupSlowClick( TObject *Sender ) +{ + ToolButtonSlowClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupFastClick( TObject *Sender ) +{ + ToolButtonFastClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupToggleInterfaceClick( TObject *Sender ) +{ + this->BringToFront(); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupFullscreenClick( TObject *Sender ) +{ + MenuFullscreenClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupNextClick( TObject *Sender ) +{ + ToolButtonNextClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupPrevClick( TObject *Sender ) +{ + ToolButtonPrevClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupJumpClick( TObject *Sender ) +{ + // TODO +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupPlaylistClick( TObject *Sender ) +{ + MenuPlaylistClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupPreferencesClick( TObject *Sender ) +{ + MenuPreferencesClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupExitClick( TObject *Sender ) +{ + MenuExitClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupOpenFileClick( TObject *Sender ) +{ + MenuOpenFileClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupOpenDiscClick( TObject *Sender ) +{ + MenuOpenDiscClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::PopupNetworkStreamClick( TObject *Sender ) +{ + MenuNetworkStreamClick( Sender ); +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Callbacks for DVD/VCD navigation + ****************************************************************************/ +void __fastcall TMainFrameDlg::ButtonTitlePrevClick( TObject *Sender ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + int i_id; + + p_intf = p_intfGlobal; + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id - 1; + + /* Disallow area 0 since it is used for video_ts.vob */ + if( i_id > 0 ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_title_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + SetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ButtonTitleNextClick( TObject *Sender ) +{ + intf_thread_t * p_intf; + input_area_t * p_area; + int i_id; + + p_intf = p_intfGlobal; + i_id = p_intf->p_sys->p_input->stream.p_selected_area->i_id + 1; + + if( i_id < p_intf->p_sys->p_input->stream.i_area_nb ) + { + p_area = p_intf->p_sys->p_input->stream.pp_areas[i_id]; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_title_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + SetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ButtonChapterPrevClick( TObject *Sender ) +{ + intf_thread_t * p_intf = p_intfGlobal; + input_area_t * p_area; + + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if( p_area->i_part > 0 ) + { + p_area->i_part--; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_chapter_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + SetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} +//--------------------------------------------------------------------------- +void __fastcall TMainFrameDlg::ButtonChapterNextClick( TObject *Sender ) +{ + intf_thread_t * p_intf = p_intfGlobal; + input_area_t * p_area; + + p_area = p_intf->p_sys->p_input->stream.p_selected_area; + + if( p_area->i_part < p_area->i_part_nb ) + { + p_area->i_part++; + input_ChangeArea( p_intf->p_sys->p_input, (input_area_t*)p_area ); + + input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); + + p_intf->p_sys->b_chapter_update = 1; + vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock ); + SetupMenus( p_intf ); + vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock ); + } +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Callback for the 'go!' button + ****************************************************************************/ +void __fastcall TMainFrameDlg::ButtonGoClick( TObject *Sender ) +{ + intf_thread_t *p_intf = p_intfGlobal; + int i_channel; + + i_channel = SpinEditChannel->Value; + msg_Dbg( p_intf, "joining channel %d", i_channel ); + + vlc_mutex_lock( &p_intf->change_lock ); + network_ChannelJoin( p_intf, i_channel ); + vlc_mutex_unlock( &p_intf->change_lock ); + +// input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY ); +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * ModeManage: actualise the aspect of the interface whenever the input + * changes. + ***************************************************************************** + * The lock has to be taken before you call the function. + *****************************************************************************/ +void __fastcall TMainFrameDlg::ModeManage() +{ + intf_thread_t * p_intf = p_intfGlobal; + TGroupBox * ActiveGB; + int i_Height; + bool b_control; + + /* hide all boxes */ + GroupBoxFile->Visible = false; + GroupBoxNetwork->Visible = false; + GroupBoxDisc->Visible = false; + + /* hide slider */ + GroupBoxSlider->Hide(); + + /* controls unavailable */ + b_control = 0; + + /* show the box related to current input mode */ + if( p_intf->p_sys->p_input != NULL ) + { + switch( p_intf->p_sys->p_input->stream.i_method & 0xf0 ) + { + case INPUT_METHOD_FILE: + GroupBoxFile->Visible = true; + ActiveGB = GroupBoxFile; + LabelFileName->Caption = p_intf->p_sys->p_input->psz_source; + break; + case INPUT_METHOD_DISC: + GroupBoxDisc->Visible = true; + ActiveGB = GroupBoxDisc; + break; + case INPUT_METHOD_NETWORK: + GroupBoxNetwork->Visible = true; + ActiveGB = GroupBoxNetwork; + LabelServer->Caption = p_intf->p_sys->p_input->psz_source; + if( config_GetInt( p_intf, "network-channel" ) ) + { + LabelChannel->Visible = true; + } + else + { + LabelChannel->Visible = false; + } + break; + default: + msg_Warn( p_intf, "cannot determine input method" ); + GroupBoxFile->Visible = true; + ActiveGB = GroupBoxFile; + LabelFileName->Caption = p_intf->p_sys->p_input->psz_source; + break; + } + + i_Height = StatusBar->Height + ActiveGB->Height + ToolBar->Height + 54; + + /* initialize and show slider for seekable streams */ + if( p_intf->p_sys->p_input->stream.b_seekable ) + { + TrackBar->Position = p_intf->p_sys->OldValue = 0; + GroupBoxSlider->Show(); + i_Height += GroupBoxSlider->Height; + } + + /* control buttons for free pace streams */ + b_control = p_intf->p_sys->p_input->stream.b_pace_control; + + /* get ready for menu regeneration */ + p_intf->p_sys->b_program_update = 1; + p_intf->p_sys->b_title_update = 1; + p_intf->p_sys->b_chapter_update = 1; + p_intf->p_sys->b_audio_update = 1; + p_intf->p_sys->b_spu_update = 1; + p_intf->p_sys->i_part = 0; + + p_intf->p_sys->p_input->stream.b_changed = 0; + msg_Dbg( p_intf, "stream has changed, refreshing interface" ); + } + else + { + i_Height = StatusBar->Height + ToolBar->Height + 47; + + if( config_GetInt( p_intf, "network-channel" ) ) + { + GroupBoxNetwork->Visible = true; + LabelChannel->Visible = true; + i_Height += GroupBoxNetwork->Height + 7; + } + else + { + /* add space between tolbar and statusbar when + * nothing is displayed; isn't it nicer ? :) */ + i_Height += 17; + } + + /* unsensitize menus */ + MenuProgram->Enabled = false; + MenuTitle->Enabled = false; + MenuChapter->Enabled = false; + MenuAudio->Enabled = false; + MenuSubtitles->Enabled = false; + PopupNavigation->Enabled = false; + PopupAudio->Enabled = false; + PopupSubtitles->Enabled = false; + } + + /* resize main window */ + this->Height = i_Height; + + /* set control items */ + ToolButtonBack->Enabled = false; + ToolButtonStop->Enabled = true; + ToolButtonEject->Enabled = !b_control; + ToolButtonPause->Enabled = b_control; + ToolButtonSlow->Enabled = b_control; + ToolButtonFast->Enabled = b_control; + PopupBack->Enabled = false; + PopupPause->Enabled = b_control; + PopupSlow->Enabled = b_control; + PopupFast->Enabled = b_control; +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * CreateConfig: create a configuration dialog and save it for further use + ***************************************************************************** + * Check if the dialog box is already opened, if so this will save us + * quite a bit of work. (the interface will be destroyed when you actually + * close the main window, but remember that it is only hidden if you + * clicked on the action buttons). This trick also allows us not to + * duplicate identical dialog windows. + *****************************************************************************/ +void __fastcall TMainFrameDlg::CreatePreferences( AnsiString Name ) +{ + TPreferencesDlg *Preferences; + int i_index, i_pos; + + i_index = StringListPref->IndexOf( Name ); + if( i_index != -1 ) + { + /* config dialog already exists */ + Preferences = (TPreferencesDlg *)StringListPref->Objects[i_index]; + } + else + { + /* create the config dialog */ + Preferences = new TPreferencesDlg( this ); + Preferences->CreateConfigDialog( Name.c_str() ); + + /* save it */ + i_pos = StringListPref->Add( Name ); + StringListPref->Objects[i_pos] = Preferences; + } + + /* display the dialog */ + Preferences->Show(); +} +//--------------------------------------------------------------------------- + diff --git a/modules/gui/win32/mainframe.dfm b/modules/gui/win32/mainframe.dfm new file mode 100644 index 0000000000..e797238c91 --- /dev/null +++ b/modules/gui/win32/mainframe.dfm @@ -0,0 +1,2438 @@ +object MainFrameDlg: TMainFrameDlg + Left = 314 + Top = 198 + Width = 541 + Height = 306 + BorderIcons = [biSystemMenu, biMinimize] + Caption = 'VideoLAN Client (win32 interface)' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Icon.Data = { + 0000010001003030000001000800A80E00001600000028000000300000006000 + 00000100080000000000800A0000000000000000000000010000000000000402 + 04002486D4009CC2E4007CA6C400E4E2E40004528C003CA2F4001C82DC0054B2 + FC003C8EDC00B4CADC00046EC4001C92F40034363400D4D6D400FFFFFF006CAA + E4006CB2F4000476DC0044AAFC009CD2FC00A4B6C4001C6EB4001C9AFC00548A + B4007CC2FC000486F400B4CAE4001416140034A2FC00CCD2D400147ACC006CBA + FC006CA6DC00CCE2F400045EA400349EFC00044A7400FCFEFC0064BAFC005C9E + DC00C4CED4000C92FC00BCD6E400F4F2F4007C9AB4008CCAFC0044A2FC007CBA + FC00CCEAFC001C5E8C000482EC0064B6FC000472D400047EEC002C9EFC00048E + FC001C1E1C001C96FC00CCDAE4000C0A0C00348ED400A4C6E4009CAEBC00248A + E4005CB6FC003492E400BCCEDC003C3E3C00047EE4004CAEFC00ACBECC00447A + A400249EFC008CC6FC003CA6FC00247ECC0074BEFC007CAEDC001C5674001496 + FC00ECF6FC00649ACC00DCEEFC00040604002C8AD400A4C2E40084AAC400145A + 8C0044A2F4001C86DC005CB2FC003C92DC00BCCADC000472CC003C3A3C00E4F2 + FC0054AEFC0074B6F400047ADC004CAAFC009CB6CC00249AFC006C92BC0084C6 + FC00048AFC001C1A1C003CA2FC00CCD2DC001C7ECC0074BAFC0074AADC00D4E6 + F4000462B4000C4E74004C9EE400CCCED4001492FC00C4DAE40094CAFC0044A6 + FC007CBEFC002C628C000476D4000C8EFC0024222400D4DAE4003476B400F4F6 + FC006C9ECC00E4EEFC0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000008383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 838383831C1C1C1C838383838383838383838383838383838383838383838383 + 838383838383838383838383838383831C1C1C1C5E12635E1C1C1C8383838383 + 838383838383838383838383838383838383838383838383838383831C1C1C1C + 5E6312456969691A455E1C1C1C83838383838383838383838383838383838383 + 8383838383838383831C1C1C5E127B5E7B63636363636345691A45125E1C1C83 + 8383838383838383838383838383838383838383831C1C1C1C5E126363635E05 + 25252525252572585E6345691A455E1C1C838383838383838383838383838383 + 8383831C1C5E1263451A697B05250569696969692A17244B584F7A5E69696963 + 5E1C83838383838383838383838383838383831C711A69694525252369696969 + 3869383875661D785B344D4825694569695E1C1C838383838383838383838383 + 838383831C5E45121C45696969383869386938383A376B645B206E795B250045 + 691A711C83838383838383838383838383838383831C1C231C63696938696938 + 6938692A17374B46412079796E520012455E1C83838383838383838383838383 + 838383838383831C1C1238386938386938693875661D1361344D7919101C230B + 1C1C838383838383838383838383838383838383838383831C5E696938693869 + 38693850666B135B20797979211C1C1C83838383838383838383838383838383 + 83838383838383831C1C45693869383A17662413465B34342079796E521C8383 + 838383838383838383838383838383838383838383838383831C633A663A0602 + 0A2B22535382312E684A19101C83838383838383838383838383838383838383 + 8383838383838383831C01020A0A0A1E1E042C26262626606053146F54838383 + 838383838383838383838383838383838383838383838383831C67290E1E0E0E + 0E042C2626262626262682656A83838383838383838383838383838383838383 + 8383838383838383831C0D3F0E0E0E0E0E042C262626262626267E4483838383 + 83838383838383838383838383838383838383838383838383836A3F0E0E0E6C + 5D2B22538260602626266C7D8383838383838383838383838383838383838383 + 838383838383838383836A3F6C5D1B025924645B274D77536080477D83838383 + 83838383838383838383838383838383838383838383838383831C0302590C3A + 753A376B465B6E4A141B0D838383838383838383838383838383838383838383 + 83838383838383838383541F0C3838382A661D4B61344D7930813C8383838383 + 8383838383838383838383838383838383838383838383838383831C45386938 + 75661D1308344D7910101C838383838383838383838383838383838383838383 + 83838383838383838383831C126938383A376B645B207979211C838383838383 + 8383838383838383838383838383838383838383838383838383831C6338692A + 17374B463420796E521C83838383838383838383838383838383838383838383 + 83838383838383838383831C5E6938662F615B4D19681910101C838383838383 + 838383838383838383838383838383838383838383838383838383835407593E + 5D2B70608253144E1C8383838383838383838383838383838383838383838383 + 8383838383838383838383831C030A1E0E042C26262682656A83838383838383 + 838383838383838383838383838383838383838383838383838383836A3F0E0E + 0E042C2626267E446A8383838383838383838383838383838383838383838383 + 838383838383838383838383392D740E0E042C2626266C7D8383838383838383 + 838383838383838383838383838383838383838383838383838383831C0D156C + 433B70606080477D838383838383838383838383838383838383838383838383 + 838383838383838383838383831C573E1134794A141B5F6A8383838383838383 + 83838383838383838383838383838383838383838383838383838383831C3D78 + 6461344D796F1C83838383838383838383838383838383838383838383838383 + 838383838383838383838383831C4C24645B347930521C838383838383838383 + 8383838383838383838383838383838383838383838383838383838383831C42 + 465B2079101C8383838383838383838383838383838383838383838383838383 + 83838383838383838383838383831C0946344D79211C83838383838383838383 + 8383838383838383838383838383838383838383838383838383838383831C3D + 73731062521C8383838383838383838383838383838383838383838383838383 + 83838383838383838383838383831C7F0000001C1C8383838383838383838383 + 838383838383838383838383838383838383838383838383838383838383831C + 0B074C4C1C838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383831C0B0701161C8383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 1C1C1C1C83838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 8383838383838383838383838383838383838383838383838383838383838383 + 838383838383838383838383838383838383838383838383838383838383FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFF + FFFFFFFF0000FFFFFC3FFFFF0000FFFFC007FFFF0000FFFC0001FFFF0000FFE0 + 00007FFF0000FE0000001FFF0000F80000000FFF0000F800000003FF0000FC00 + 000003FF0000FE00000007FF0000FF8000000FFF0000FFC000003FFF0000FFC0 + 0000FFFF0000FFE00001FFFF0000FFE00001FFFF0000FFE00001FFFF0000FFE0 + 0003FFFF0000FFF00003FFFF0000FFF00003FFFF0000FFF00007FFFF0000FFF0 + 0007FFFF0000FFF80007FFFF0000FFF8000FFFFF0000FFF8000FFFFF0000FFF8 + 000FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC + 003FFFFF0000FFFC003FFFFF0000FFFE003FFFFF0000FFFE007FFFFF0000FFFE + 007FFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF + 01FFFFFF0000FFFF81FFFFFF0000FFFF81FFFFFF0000FFFFC3FFFFFF0000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000} + Menu = MainMenu1 + OldCreateOrder = False + PopupMenu = PopupMenuMain + ShowHint = True + OnClose = FormClose + PixelsPerInch = 96 + TextHeight = 13 + object ToolBar: TToolBar + Left = 0 + Top = 0 + Width = 533 + Height = 50 + ButtonHeight = 46 + ButtonWidth = 39 + Caption = 'ToolBar' + EdgeBorders = [ebTop, ebBottom] + Flat = True + Images = ImageListToolbar + ShowCaptions = True + TabOrder = 0 + object ToolButtonFile: TToolButton + Left = 0 + Top = 0 + Hint = 'Open a file' + Caption = 'File' + ImageIndex = 0 + OnClick = ToolButtonFileClick + end + object ToolButtonDisc: TToolButton + Left = 39 + Top = 0 + Hint = 'Open a DVD or VCD' + Caption = 'Disc' + ImageIndex = 1 + OnClick = ToolButtonDiscClick + end + object ToolButtonNet: TToolButton + Left = 78 + Top = 0 + Hint = 'Open a network stream' + Caption = 'Net' + ImageIndex = 2 + OnClick = ToolButtonNetClick + end + object ToolButtonSep1: TToolButton + Left = 117 + Top = 0 + Width = 8 + Caption = 'ToolButtonSep1' + ImageIndex = 3 + Style = tbsSeparator + end + object ToolButtonBack: TToolButton + Left = 125 + Top = 0 + Caption = 'Back' + Enabled = False + ImageIndex = 3 + OnClick = ToolButtonBackClick + end + object ToolButtonPlay: TToolButton + Left = 164 + Top = 0 + Hint = 'Play stream' + Caption = 'Play' + ImageIndex = 5 + OnClick = ToolButtonPlayClick + end + object ToolButtonPause: TToolButton + Left = 203 + Top = 0 + Hint = 'Pause stream' + Caption = 'Pause' + Enabled = False + ImageIndex = 6 + OnClick = ToolButtonPauseClick + end + object ToolButtonStop: TToolButton + Left = 242 + Top = 0 + Hint = 'Stop stream' + Caption = 'Stop' + Enabled = False + ImageIndex = 4 + OnClick = ToolButtonStopClick + end + object ToolButtonEject: TToolButton + Left = 281 + Top = 0 + Hint = 'Eject disc' + Caption = 'Eject' + Enabled = False + ImageIndex = 7 + OnClick = ToolButtonEjectClick + end + object ToolButton1: TToolButton + Left = 320 + Top = 0 + Width = 8 + Caption = 'ToolButton1' + ImageIndex = 13 + Style = tbsSeparator + end + object ToolButtonSlow: TToolButton + Left = 328 + Top = 0 + Hint = 'Play slower' + Caption = 'Slow' + Enabled = False + ImageIndex = 8 + OnClick = ToolButtonSlowClick + end + object ToolButtonFast: TToolButton + Left = 367 + Top = 0 + Hint = 'Play faster' + Caption = 'Fast' + Enabled = False + ImageIndex = 9 + OnClick = ToolButtonFastClick + end + object ToolButtonSep2: TToolButton + Left = 406 + Top = 0 + Width = 8 + Caption = 'ToolButtonSep2' + ImageIndex = 9 + Style = tbsSeparator + end + object ToolButtonPlaylist: TToolButton + Left = 414 + Top = 0 + Hint = 'Open playlist' + Caption = 'Playlist' + ImageIndex = 10 + Style = tbsCheck + OnClick = ToolButtonPlaylistClick + end + object ToolButtonPrev: TToolButton + Left = 453 + Top = 0 + Hint = 'Previous file' + Caption = 'Prev' + ImageIndex = 11 + OnClick = ToolButtonPrevClick + end + object ToolButtonNext: TToolButton + Left = 492 + Top = 0 + Hint = 'Next file' + Caption = 'Next' + ImageIndex = 12 + OnClick = ToolButtonNextClick + end + end + object StatusBar: TStatusBar + Left = 0 + Top = 241 + Width = 533 + Height = 19 + Panels = <> + ParentShowHint = False + ShowHint = False + SimplePanel = True + end + object GroupBoxFile: TGroupBox + Left = 0 + Top = 90 + Width = 533 + Height = 32 + Align = alTop + TabOrder = 2 + Visible = False + object LabelFileName: TLabel + Left = 2 + Top = 15 + Width = 529 + Height = 15 + Align = alClient + Alignment = taCenter + Caption = 'File read' + end + end + object GroupBoxNetwork: TGroupBox + Left = 0 + Top = 154 + Width = 533 + Height = 40 + Align = alTop + TabOrder = 3 + Visible = False + object LabelChannel: TLabel + Left = 288 + Top = 16 + Width = 42 + Height = 13 + Caption = 'Channel:' + end + object LabelServer: TLabel + Left = 64 + Top = 16 + Width = 49 + Height = 13 + Caption = 'No server!' + end + object ButtonGo: TButton + Left = 384 + Top = 10 + Width = 25 + Height = 25 + Caption = 'Go!' + TabOrder = 0 + OnClick = ButtonGoClick + end + object SpinEditChannel: TCSpinEdit + Left = 336 + Top = 11 + Width = 41 + Height = 22 + TabStop = True + MaxValue = 99 + ParentColor = False + TabOrder = 1 + end + end + object GroupBoxDisc: TGroupBox + Left = 0 + Top = 122 + Width = 533 + Height = 32 + Align = alTop + TabOrder = 4 + Visible = False + object LabelDisc: TLabel + Left = 32 + Top = 11 + Width = 21 + Height = 13 + Caption = 'Disc' + end + object LabelTitle: TLabel + Left = 96 + Top = 11 + Width = 23 + Height = 13 + Caption = 'Title:' + end + object LabelChapter: TLabel + Left = 296 + Top = 11 + Width = 40 + Height = 13 + Caption = 'Chapter:' + end + object LabelTitleCurrent: TLabel + Left = 126 + Top = 11 + Width = 9 + Height = 13 + Caption = '---' + end + object LabelChapterCurrent: TLabel + Left = 342 + Top = 11 + Width = 9 + Height = 13 + Caption = '---' + end + object ButtonTitlePrev: TButton + Left = 152 + Top = 8 + Width = 33 + Height = 19 + Hint = 'Jump to previous title' + Caption = 'Prev' + TabOrder = 0 + OnClick = ButtonTitlePrevClick + end + object ButtonTitleNext: TButton + Left = 184 + Top = 8 + Width = 33 + Height = 19 + Hint = 'Jump to next title' + Caption = 'Next' + TabOrder = 1 + OnClick = ButtonTitleNextClick + end + object ButtonChapterPrev: TButton + Left = 368 + Top = 8 + Width = 33 + Height = 19 + Hint = 'Jump to previous chapter' + Caption = 'Prev' + TabOrder = 2 + OnClick = ButtonChapterPrevClick + end + object ButtonChapterNext: TButton + Left = 400 + Top = 8 + Width = 33 + Height = 19 + Hint = 'Jump to next chapter' + Caption = 'Next' + TabOrder = 3 + OnClick = ButtonChapterNextClick + end + end + object GroupBoxSlider: TGroupBox + Left = 0 + Top = 50 + Width = 533 + Height = 40 + Align = alTop + Caption = '0:00:00' + TabOrder = 5 + Visible = False + object TrackBar: TTrackBar + Left = 2 + Top = 15 + Width = 529 + Height = 21 + Align = alTop + Orientation = trHorizontal + Frequency = 1 + Position = 0 + SelEnd = 0 + SelStart = 0 + TabOrder = 0 + TickMarks = tmBottomRight + TickStyle = tsNone + OnChange = TrackBarChange + end + end + object MainMenu1: TMainMenu + Left = 40 + Top = 208 + object MenuFile: TMenuItem + Caption = '&File' + object MenuOpenFile: TMenuItem + Caption = '&Open file...' + Hint = 'Open a file' + ShortCut = 114 + OnClick = MenuOpenFileClick + end + object MenuOpenDisc: TMenuItem + Caption = 'Open &disc...' + Hint = 'Open a DVD or VCD' + ShortCut = 115 + OnClick = MenuOpenDiscClick + end + object MenuNetworkStream: TMenuItem + Caption = '&Network stream...' + Hint = 'Select a network stream' + ShortCut = 116 + OnClick = MenuNetworkStreamClick + end + object N8: TMenuItem + Caption = '-' + Visible = False + end + object MenuEjectDisc: TMenuItem + Caption = '&Eject Disc' + Hint = 'Eject disc' + Visible = False + OnClick = ToolButtonEjectClick + end + object N1: TMenuItem + Caption = '-' + end + object MenuExit: TMenuItem + Caption = 'E&xit' + Hint = 'Exit the program' + ShortCut = 16465 + OnClick = MenuExitClick + end + end + object MenuView: TMenuItem + Caption = '&View' + object MenuHideinterface: TMenuItem + Caption = '&Hide interface' + Hint = 'Hide the main interface window' + OnClick = MenuHideinterfaceClick + end + object MenuFullscreen: TMenuItem + Caption = '&Fullscreen' + Hint = 'Toggle fullscreen' + OnClick = MenuFullscreenClick + end + object N2: TMenuItem + Caption = '-' + end + object MenuProgram: TMenuItem + Caption = 'Progr&am' + Enabled = False + Hint = 'Select program' + end + object MenuTitle: TMenuItem + Caption = '&Title' + Enabled = False + Hint = 'Select title' + end + object MenuChapter: TMenuItem + Caption = '&Chapter' + Enabled = False + Hint = 'Select chapter' + end + object MenuAngle: TMenuItem + Caption = 'An&gle' + Enabled = False + Hint = 'Select angle' + end + object N3: TMenuItem + Caption = '-' + end + object MenuPlaylist: TMenuItem + Caption = '&Playlist...' + Hint = 'Open the playlist window' + OnClick = MenuPlaylistClick + end + object MenuModules: TMenuItem + Caption = '&Modules...' + Enabled = False + Hint = 'Open the modules window' + end + object MenuMessages: TMenuItem + Caption = 'Me&ssages...' + Hint = 'Open the messages window' + OnClick = MenuMessagesClick + end + end + object MenuSettings: TMenuItem + Caption = '&Settings' + object MenuAudio: TMenuItem + Caption = '&Audio' + Enabled = False + Hint = 'Select audio language' + end + object MenuSubtitles: TMenuItem + Caption = '&Subtitles' + Enabled = False + Hint = 'Select subtitles language' + end + object N4: TMenuItem + Caption = '-' + end + object MenuPreferences: TMenuItem + Caption = '&Preferences...' + Hint = 'Configure the application' + OnClick = MenuPreferencesClick + end + end + object MenuHelp: TMenuItem + Caption = '&Help' + object MenuAbout: TMenuItem + Caption = '&About...' + Hint = 'About this application' + OnClick = MenuAboutClick + end + end + end + object OpenDialog1: TOpenDialog + Filter = 'All Files (*.*)|*.*' + Left = 8 + Top = 208 + end + object ImageListToolbar: TImageList + Height = 26 + Width = 32 + Left = 104 + Top = 208 + Bitmap = { + 494C01010D000E00040020001A00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 00000000000036000000280000008000000068000000010020000000000000D0 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000034653F00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000034653F0034653F000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000007AA9830054855D00325B + 3A00000000000000000000000000000000000000000000000000000000000000 + 000000000000000000007AA983007AA983000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000080AC88007AA983006B9A + 7400497C5300325B3A0000000000000000000000000000000000000000000000 + 000000000000000000008CB896008CB896000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000090BB9D007AA983007AA9 + 83007AA983006B9A7400497C530040704B000000000000000000000000000000 + 0000000000000000000090BB9D008CB896000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000090BB9D007AA983007AA9 + 83007AA983007AA983007AA983006B9A7400497C530040584400000000000000 + 0000000000000000000090BB9D0090BB9D000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000090BB9D0080AC88007AA9 + 830080AC88007AA983007AA9830076A47E007AA983006B9A740054855D00325B + 3A00000000000000000090BB9D0090BB9D000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCFDFC00EFF4F000EFF4 + F000EFF4F000ECF2ED00D7E4D900D7E4D900D7E4D900D7E4D900EFF4F000ACC7 + B1000000000000000000FCFDFC00FCFDFC000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCFDFC00EFF4F000EFF4 + F000ECF2ED00ECF2ED00ECF2ED00E2EBE400EFF4F000C7DACB00181818000000 + 00000000000000000000FCFDFC00FCFDFC000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCFDFC00FCFDFC00EFF4 + F000EFF4F000ECF2ED00EFF4F000C7DACB000000000000000000000000000000 + 00000000000000000000FCFDFC00FCFDFC000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCFDFC00EFF4F000ECF2 + ED00EFF4F000C7DACB0000000000000000000000000000000000000000000000 + 00000000000000000000FCFDFC00FCFDFC000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCFDFC00EFF4F000D7E4 + D900000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000FCFDFC00FCFDFC000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E2EBE400000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000DFEAE100E2EBE4000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000084A8B40091B1BB009BB8C1009BB8 + C10084A8B40084A8B40043555C00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000006B63 + C0003D359000000000000000000000000000463DA40000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000006986900091B1BB009BB8C1009BB8C10091B1 + BB0084A8B40084A8B400546B7300000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00006158BC003D3590000000000000000000463DA40000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000004861490000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000546B730084A8B40084A8B4009BB8C1009BB8C1009BB8 + C10084A8B40084A8B4006986900043555C000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000006158BC004E44B5004E44B5000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000005977 + 5A0059775A0059775A0059775A0059775A006D926E0059775A00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000698690009BB8C1009BB8C1009BB8C1009BB8C10091B1 + BB0084A8B40084A8B40069869000546B73000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000004E44B5004E44B5000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000006D92 + 6E006D926E006D926E006D926E006D926E008E9594006D926E00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E00000000000546B730084A8B40091B1BB009BB8C1009BB8C10091B1BB009BB8 + C10084A8B40084A8B40084A8B400698690000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000B3B5B500B3B5B500B3B5B500B3B5B5007A7A7A0000000000000000000000 + 000000000000000000004E44B5006158BC003D35900000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000B2B5B500B2B5B500B2B5B500B2B5B5007A7A7A0000000000000000000000 + 0000000000000000000000000000000000006D926E0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000000000006986900084A8B4009BB8C1009BB8C1009BB8C1009BB8C10091B1 + BB0084A8B40084A8B40084A8B400698690003342460000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000003059370030593700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000030593700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B3B5B500E5E8 + E800D5D7D700FDFDFD00FDFDFD00E5E8E800D5D7D700ABB3B200939796000000 + 0000000000004E44B50000000000000000006158BC00362F8100000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B2B5B500E5E8 + E800D5D7D700FDFDFD00FDFDFD00E5E8E800D5D7D700ABB3B200939796000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E0000000 + 000069869000708F990091B1BB009BB8C1009BB8C1009BB8C10091B1BB009BB8 + C10091B1BB0084A8B40084A8B40084A8B40043555C0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000051885B0051885B00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00003D73470063A76F0051885B00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B9C0BF00D5D7D700FDFD + FD00BCC4C200BCC4C200BCC4C200BCC4C200D5D7D700D5D7D700D5D7D700ABB3 + B2000C0B1500443C9F000000000000000000000000004E44B500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B9C0BF00D5D7D700FDFD + FD00BCC4C200BCC4C200BCC4C200BCC4C200D5D7D700D5D7D700D5D7D700ABB3 + B200000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000084A8B4000000000084A8B4009BB8C1009BB8C10091B1BB009BB8C10084A8 + B40084A8B40084A8B40084A8B40084A8B400546B730000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000568C6000568C6000000000000000 + 00000000000000000000000000000000000000000000000000003D734700447C + 4E00679A710079A98200568C6000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ABB3B200D5D7D700E5E8E800ABB3 + B200B9C0BF00B9C0BF00BCC4C200CCD4D200BCC4C200CCD4D200D5D7D700D5D7 + D7004F4F4F000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ABB3B200D5D7D700E5E8E800ABB3 + B200B9C0BF00B9C0BF00BCC4C200CCD4D200BCC4C200CCD4D200D5D7D700D5D7 + D700B2B5B5000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E0000000 + 000084A8B400000000009BB8C1009BB8C1009BB8C10091B1BB0091B1BB0084A8 + B40084A8B40084A8B40084A8B40084A8B400546B730000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000005C9267005C926700000000000000 + 00000000000000000000000000000000000030593700447C4E00679A710079A9 + 820073A47D0079A982005C926700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CCD4D200FDFDFD00A3ABA900ABB3 + B200BCC4C200BCC4C200BCC4C200CCD4D200CCD4D200CCD4D200CCD4D200CCD4 + D200D5D7D7000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CCD4D200FDFDFD00A3ABA900ABB3 + B200BCC4C200BCC4C200BCC4C200CCD4D200CCD4D200CCD4D200CCD4D200CCD4 + D200D5D7D7000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E0000000 + 0000698690000000000091B1BB0091B1BB006986900084A8B40084A8B4006986 + 900084A8B40084A8B40084A8B40084A8B4006986900000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000005C9267005C926700000000000000 + 000000000000000000004A6F5100447C4E00679A710079A9820079A9820079A9 + 820079A9820079A982005C926700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000B3B5B500D5D7D700BCC4C200A3ABA900B3B5 + B500BCC4C200CCD4D200ABB3B200D5D7D700D5D7D700D5D7D700CCD4D200E5E8 + E800D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000B2B5B500D5D7D700BCC4C200A3ABA900B2B5 + B500BCC4C200CCD4D200ABB3B200D5D7D700D5D7D700D5D7D700CCD4D200E5E8 + E800D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E0000000 + 0000546B7300000000009BB8C100698690000000000084A8B400698690000000 + 000084A8B400698690000000000069869000546B730000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000005C9267005C926700000000000000 + 00003059370049815400679A710079A9820073A47D0079A9820079A9820079A9 + 820079A9820079A98200679A7100000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD00A3ABA900A3ABA900B3B5 + B500C3CBC9008E9594000000000093979600D5D7D700D5D7D700D5D7D700D5D7 + D700D5D7D7009397960000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD00A3ABA900A3ABA900B2B5 + B500C3CBC9008E9594000000000093979600D5D7D700D5D7D700D5D7D700D5D7 + D700D5D7D7009397960000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000091B1BB00698690000000000084A8B4005A737A000000 + 0000708F9900546B730000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 0000ACC7B100F8FAF800E4ECE500DAE6DC00DAE6DC00E4ECE500ECF2ED00ECF2 + ED00ECF2ED00ECF2ED00C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD0093979600A3ABA900B3B5 + B500C3CBC900000000000000000000000000CCD4D200CCD4D200CCD4D200CCD4 + D200D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD0093979600A3ABA900B2B5 + B500C3CBC900000000000000000000000000CCD4D200CCD4D200CCD4D200CCD4 + D200D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E00000000000AAC3CA0069869000000000005A737A00334246000000 + 000000000000000000008C9C9400E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 000000000000121B1200E4ECE500F8FAF800ECF2ED00E4ECE500ECF2ED00ECF2 + ED00ECF2ED00ECF2ED00C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD0099A09F009BA3A100B3B5 + B5000000000000000000C9D0CF000000000000000000C9D0CF00C3CBC900C9D0 + CF00D5D7D7009397960000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000D5D7D700FDFDFD0099A09F009BA3A100B2B5 + B5000000000000000000C9D0CF000000000000000000C9D0CF00C3CBC900C9D0 + CF00D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E00000000000AAC3CA0069869000000000000000000000000000A3A5 + A300E0E4E000E0E4E000E0E4E000E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 000000000000000000000000000000000000DAE6DC00F8FAF800F8FAF800ECF2 + ED00ECF2ED00F8FAF800C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000B3B5B500D5D7D700ABB3B2009BA3A1000000 + 000000000000BCC4C200C9D0CF00C3CBC9000000000000000000BCC4C200E5E8 + E800D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000B2B5B500D5D7D700ABB3B2009BA3A1000000 + 000000000000BCC4C200C9D0CF00C3CBC9000000000000000000BCC4C200E5E8 + E800D5D7D7008E95940000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E00000000000B8CDD30069869000000000008C9C9400E0E4E000E0E4 + E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 0000000000000000000000000000000000000000000000000000E4ECE500F8FA + F800F8FAF800ECF2ED00C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000D5D7D700E5E8E800939796009BA3 + A100ABB3B200B3B5B500B9C0BF00B9C0BF00C3CBC9000000000000000000C9D0 + CF00D5D7D7000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000D5D7D700E5E8E800939796009BA3 + A100ABB3B200B2B5B500B9C0BF00B9C0BF00C3CBC9000000000000000000C9D0 + CF00D5D7D7000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000AAC3CA00698690000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000E4ECE500F8FAF800C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ABB3B200FDFDFD00CCD4D2009397 + 960099A09F00A3ABA900A3ABA900ABB3B200B3B5B500B3B5B5000F111100D5D7 + D700B3B5B5000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000ABB3B200FDFDFD00CCD4D2009397 + 960099A09F00A3ABA900A3ABA900ABB3B200B2B5B500B2B5B5000F111100D5D7 + D700B2B5B5000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E0000000000069869000546B7300000000008C9C9400E0E4E000E0E4 + E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000C3D7C600C3D7C600000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000C3D7C600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000D5D7D700FDFDFD00E5E8 + E800B3B5B5009BA3A1009BA3A100A3ABA900C3CBC900FDFDFD00D5D7D700D5D7 + D700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000D5D7D700FDFDFD00E5E8 + E800B2B5B5009BA3A1009BA3A100A3ABA900C3CBC900FDFDFD00D5D7D700D5D7 + D700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E000E0E4E00000000000000000008C9C9400E0E4E000E0E4E000E0E4 + E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000D5D7D700FDFD + FD00FDFDFD00FDFDFD00FDFDFD00FDFDFD00FDFDFD00CCD4D200ABB3B2000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000D5D7D700FDFD + FD00FDFDFD00FDFDFD00FDFDFD00FDFDFD00FDFDFD00CCD4D200ABB3B2000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000E0E4E000E0E4E000E0E4 + E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4 + E000E0E4E000E0E4E000E0E4E000E0E4E000E0E4E00000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000D5D7D700FDFDFD00FDFDFD00D5D7D700ABB3B20000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000D5D7D700FDFDFD00FDFDFD00D5D7D700ABB3B20000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000060616000A0927000A0927000A0927000D0D31000D0D31000A0927000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000B4BEBD00B4BE + BD00BDC2BD00BDC2C500BDC2BD00BDC2BD006493750064937500649375006493 + 75005A8568005A85680000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000060616000A09 + 27006E6DA0008B89B8008B89B8007E7CB2006E6DA0004F4E82003F3E63000A09 + 2700060616000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000003465 + 3F00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000002E5836002E58 + 36002E583600000000000000000000000000000000002E5836002E5836002E58 + 3600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000D8D9 + DA00EEEEF600EBE7EB00EEEEF600EBE7EB0083AB8B0078A8870078A8870078A8 + 87005A8568000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000060616007775A6009A99 + C400A09FC7009A99C4009A99C4009A99C4009A99C4007775A6007775A6005F5E + 9000484775000A09270000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000080AC + 880054855D00325B3A0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000051885B005188 + 5B0051885B000000000000000000000000000000000051885B0051885B005188 + 5B00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000EBE7 + EB00EBE7EB00F6F2F600F6F2F600F6F2F60078A8870078A8870083AB8B00739D + 7B005A8568000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000060616008B89B8009A99 + C400B6B5CC00B9B7D700A9A7C900B9B7D700A9A7C9009A99C4008B89B8006968 + 9F00484775000A09270000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000008CB8 + 96007AA883006B9A7400497C5300325B3A000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000568C6000568C + 6000568C600000000000000000000000000000000000568C6000568C6000568C + 6000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000EBE7EB00F6EEF600F6F2F600F6F2F60078A8870078A88700739D83006493 + 7500000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000606160071719900A9A7C900B9B7 + D700C7C7DB0006061600C8C7E000C8C7E000B0AFC9000A0927008B89B8009A99 + C4006E6DA000484775000A092700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000008CB8 + 960080AC88007AA883007AA883006B9A7400497C530040704B00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000005C9267005C92 + 67005C926700000000000000000000000000000000005C9267005C9267005C92 + 6700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000EBE7EB00EBE7EB00F6F2F600F6F2F60078A8870078A88700739D83005A85 + 6800000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000060616008D8CAD00C7C7DB00D1D1 + DE00060616000606160006061600DBDBE60006061600060616000A0927009A99 + C4007E7CB20069689F000A092700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000090BB + 9D007AA883007AA883007AA883007AA883007AA883006B9A7400497C53004058 + 4400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000005C9267005C92 + 67005C926700000000000000000000000000000000005C9267005C9267005C92 + 6700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000EBE7EB00EEEEF600F6F2F60078A88700739D8300739D7B000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000A092700B0AFC900DBDBE600DBDB + E600DBDBE6000000000000000000060616000000000006061600B6B5CC00A9A7 + C9009B9AB8006E6DA0000D0D3100000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000090BB + 9D0080AC88007AA883007AA883007AA883007AA883007AA883007AA883006B9A + 74004F815900325B3A0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000005C9267005C92 + 67005C926700000000000000000000000000000000005C9267005C9267005C92 + 6700000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000EBE7EB00EEEEF600F6F2F60083AB8B00739D7B005A8568000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000006061600B6B5CC00DBDBE600DBDB + E600E1E1ED00D1D1DE00060616000000000006061600D1D1DE00D1D1DE00B0AF + C900A9A7C9008B89B8000A092700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000002B2B2B00F9FB + F900ECF2ED00ECF2ED00ECF2ED00ECF2ED00E2EBE400D7E4D900D7E4D900D7E4 + D900EFF4F000ACC7B10000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000EBE7EB00EBE7EB0083AB8B0064937500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000006061600C7C7DB00E1E1ED00DBDB + E600E1E1ED000606160000000000060616000000000006061600A5A5B500C7C7 + DB00A9A7C9008B89B8000A092700000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F9FB + F900ECF2ED00EFF4F000EFF4F000ECF2ED00ECF2ED00E2EBE400EFF4F000C7DA + CB00181818000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000EBE7EB00EBE7EB0078A887005A856800000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000B0AFC900E8E8F200E1E1 + ED00060616000606160006061600E1E1ED00000000000606160006061600B3B2 + BF00A9A7C9007775A6000D0D3100000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F9FB + F900F9FBF900EFF4F000ECF2ED00ECF2ED00EFF4F000C7DACB00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000010101000D8D9DA0078A8870000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000009797A200E8E8F200E1E1 + ED00DBDBE60006061600DBDBE600DBDBE600DBDBE60000000000B6B5CC00C7C7 + DB008B89B800403F700006061600000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F9FB + F900EFF4F000ECF2ED00ECF2ED00C7DACB000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000010101000D8D9DA00739D830000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000DBDBE600E8E8 + F200E8E8F200DBDBE600DBDBE600DBDBE600DBDBE600DBDBE600B9B7D700B9B7 + D700717199000D0D310000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000F9FB + F900ECF2ED00D7E4D90000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000009797A200D1D1 + DE00E8E8F200E1E1ED00DBDBE600DBDBE600DBDBE600D1D1DE00C8C7E0007E7C + B2003F3E63000D0D310000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000E2EB + E400000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000C3D7C600C3D7 + C600C3D7C60000000000000000000000000000000000C3D7C600C3D7C600C3D7 + C600000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000101010000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000A5A5B500B6B5CC00C7C7DB00C8C7E000B6B5CC009B9AB800615E7D000606 + 16000A0927000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000CDD2CD00D8D9 + DA00D8D9DA00D8D9DA00D8D9DA00D8D9DA0078A8870078A88700739D7B0078A8 + 8700649375006493750000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000006061600060616000606160006061600060616000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000CDD2CD00D8D9 + DA00D8D9DA00D8D9DA00D8D9DA00D8D9DA0087B2940087B2940087B2940087B2 + 940078A887006493750000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000007B909900000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000007B9099007B9099007B90990000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000AAA7A700B4C2BD00B4D6D500B5D6E600AABBE700ACB9DA000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00007B909900000000007B9099007B9099007B9099007B9099007B9099000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000ACAE + CD00B7B6C800B6B6B800A8B8B600B4D6D500B5D6E600AABBE700ACB9DA009C91 + DE00AA8AC6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000003C604C0035554300000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00007B909900000000007B9099007B9099007B9099007B9099007B9099007B90 + 9900000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000A8B8B600ACB9 + DA00B7B6C800B7B6C800A8B8B600B4D2CD00B5D6E600AABBE700A4A7E600AC89 + D500A47DB400A885BD0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000416752004167520047725B00416752003C604C00416752000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000305937000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000007B90 + 99007B909900000000007B9099007B9099007B9099007B9099007B9099007B90 + 99007B9099007B90990000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000009CA8A400A8B8B600ACAE + CD00ACCED500ACAECD00B6B6B800ABC8C800B5D6E600B4CAEB009C91DE00A885 + BD00AA8AC600B491CD00B489C500000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000003555 + 43003C604C000000000000000000000000004167520035554300000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000003D73470063A7 + 6F0051885B000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000007B90 + 9900F7FEFF00000000007B9099007B9099007B9099007B9099007B9099007B90 + 99007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000009C9D9C009CA79C00A7B4 + AA00A8B8B600ACB9DA00B7B6C800A7B4AA00B5D6E600ACB9DA00AA8AC600AA8A + C600B491CD00B48DD500CD95D500000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000003555 + 4300000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000003D73470049815400679A710079A9 + 8200568C60000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000007B9099007B90 + 9900F7FEFF00000000007B9099007B9099007B9099007B9099007B9099007B90 + 99007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000AAA7A700AAA7A700AAA7A7009C9D + 9C00AAA7A700A8B8B6006A696A0000000000000000006A696A00B491CD00B491 + CD00CD95D500DEA1D500E6AAD500DEA5CD000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000355543000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000030593700447C4E00679A710079A9820079A9820079A9 + 82005C9267000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000007B909900F7FE + FF00F7FEFF00000000007B9099007B9099007B9099007B9099007B9099007B90 + 99007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000D5CACD00CDC8C500C7BBBA00C7BB + BA00B4B2AC006A696A00000000000000000000000000000000006A696A00F6BE + DE00EEB6DE00EEB6DE00F6BEDE00F6BEDE000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00004A6F5100447C4E00679A710079A9820073A47D0079A9820079A9820079A9 + 82005C9267000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000007B9099007B909900F7FE + FF00F7FEFF00F7FEFF0000000000000000007B9099007B9099007B9099007B90 + 99007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000F6DAEB00F6DAEB00F6DAEB00F6DA + EB00F6DAEB00000000000000000000000000000000000000000000000000F6DA + EB00F6BEDE00EED2EA00F6DAEB00F6DAEB000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000305937004981 + 5400679A710079A9820073A47D0079A9820079A9820079A9820079A9820079A9 + 82005C9267000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000007B9099007B909900F7FE + FF00F7FEFF00F7FEFF00F7FEFF00F7FEFF0000000000000000007B9099007B90 + 99007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000E8C8E900EED2EA00EED2EA00EED2 + EA00E8C8E900000000000000000000000000000000000000000000000000AAA7 + A700B4AEA800C7BBBA00C7BBBA00D5BEBD000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000002B45370000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000ACC7B100F8FA + F800ECF2ED00DAE6DC00DAE6DC00E4ECE500ECF2ED00ECF2ED00ECF2ED00F8FA + F800C3D7C6002132240000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000007B9099007B9099007B9099007B90 + 99007B909900F7FEFF00F7FEFF00F7FEFF00F7FEFF00F7FEFF00000000000000 + 00007B9099007B9099007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000E8C8E900E8C8E900E8C8E900CDB2 + E600CDB2E6006A696A00000000000000000000000000000000006A696A00A7B4 + AA0094938B0094938B00A49D9400AAA7A7000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00002B4537000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000121B + 1200DAE6DC00F8FAF800ECF2ED00ECF2ED00ECF2ED00ECF2ED00ECF2ED00ECF2 + ED00C3D7C6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000007B9099007B909900000000000000 + 00007B9099007B9099007B9099007B909900F7FEFF00F7FEFF00F7FEFF00F7FE + FF0000000000000000007B9099007B9099000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CDB2E600CDB2E600CDB2E600B7AA + E600AABBE700ABC8C8006A696A0000000000000000006A696A00B5D6E600B4D6 + D500A7B4AA00A49D940094938B0083857B000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000041675200416752000000000000000000000000003555 + 4300355543000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000DAE6DC00F8FAF800ECF2ED00ECF2ED00ECF2ED00ECF2 + ED00C3D7C6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000007B9099007B9099007B9099007B909900F7FE + FF00F7FEFF00F7FEFF0000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000C5ACE600A4A7E600ACB9 + DA00ABC8C800ACC2BD00A7B4AA00CDC8C500F6DAEB00D8B9E600B7AAE600B5D6 + E600ABC8C800A7B4AA009CA79C00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000004167520047725B0041675200416752003C604C00355543000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000E4ECE500F8FAF800F8FAF800F8FA + F800C3D7C6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000007B9099007B90 + 9900000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000009CA5DE00ACB9DA00ABC8 + C800ACC2BD00A7B4AA00B4C2BD00D5CACD00F6DAEB00E8C8E900C5ACE600B4CA + EB00B5D6E600ABC8C8009CA8A400000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000416752003C604C000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000E4ECE500F8FA + F800C3D7C6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000ACB9DA00ABC8 + C800ACC2BD00B4B2AC00C5C2BD00DED3D500F6DAEB00E8C8E900CDB2E600B7AA + E600B5D6E600ACCED50000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000C3D7C6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000A8B8 + B600ACC2BD00B6B6B800CDC8C500DED3D500F6DAEB00EED2EA00D8B9E600C5AC + E600A4A7E6000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000B4B2AC00CDC8C500DED3D500F6DAEB00E8C8E900D5B6DE000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000424D3E000000000000003E000000 + 2800000080000000680000000100010000000000800600000000000000000000 + 000000000000000000000000FFFFFF00FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FF3FF87F000000000000000000000000 + FF0FF87F000000000000000000000000FF03F87F000000000000000000000000 + FF00F87F000000000000000000000000FF00387F000000000000000000000000 + FF00087F000000000000000000000000FF00007F000000000000000000000000 + FF00007F000000000000000000000000FF00087F000000000000000000000000 + FF00387F000000000000000000000000FF00F87F000000000000000000000000 + FF03F87F000000000000000000000000FF0FF87F000000000000000000000000 + FF3FF87F000000000000000000000000FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 + FFFFFFFF000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC73FFFFFFEFFFFFE00FFFFFFFFFF + FFFFC23FFFFFFE7FFFFC00FFFFFFFFFFFFFFE03FFFFFC03FFFF8007FFFFFFFFF + FFFFF07FFFFFC01FFF00007FFFFFFFFFFFF0787FFFF0401FFF00007FFE1FFCFF + FFC0183FFFC0003FFF00003FFE1FF0FFFF80001FFF800E7FFF00003FFE1FC0FF + FF00011FFF0006FFFF00003FFE1F00FFFE00039FFE0003FFFF00003FFE1C00FF + FE0003FFFE0003FFFF00003FFE1000FFFC0001FFFC0001FFFF00003FFE0000FF + FC0001FFFC0001FFFF00003FFE0000FFFC0001FFFC0001FFFF00003FFE1000FF + FC0001FFFC0001FFFF00003FFE1C00FFFC0001FFFC0001FFFF00003FFE1F00FF + FE0003FFFE0003FFFF00003FFE1FC0FFFE0003FFFE0003FFFF00003FFE1FF0FF + FF0007FFFF0007FFFF00003FFE1FFCFFFF800FFFFF800FFFFF00003FFFFFFFFF + FFC01FFFFFC01FFFFF00003FFFFFFFFFFFF07FFFFFF07FFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFF8001FFFFF01FFFFFCFFFFFFF8307FFFF8001FF + FFC007FFFFC3FFFFFF8307FFFFC003FFFF8003FFFFC0FFFFFF8307FFFFC003FF + FF8003FFFFC03FFFFF8307FFFFE007FFFF0001FFFFC00FFFFF8307FFFFE007FF + FF0001FFFFC003FFFF8307FFFFF00FFFFF0001FFFFC000FFFF8307FFFFF00FFF + FF0001FFFFC000FFFF8307FFFFF81FFFFF0001FFFFC003FFFF8307FFFFF81FFF + FF0001FFFFC00FFFFF8307FFFFFC3FFFFF0001FFFFC03FFFFF8307FFFFFC3FFF + FF8003FFFFC0FFFFFF8307FFFFFE7FFFFF8003FFFFC3FFFFFF8307FFFF8001FF + FFC007FFFFCFFFFFFF8307FFFF8001FFFFF01FFFFFFFFFFFFFFFFFFFFF8001FF + FFFFFFFFFFFFFFFFFFFFFFFFFF8001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFF07FFFFFF81FFFFFFF7FFFFFFFFFFFFFF01FFFFFE007FFFFFF3FFFFFFFFFFF + FFE00FFFFFC003FFFFF81FFFFFFFF3FFFFE003FFFF8001FFFFE00FFFFFFFC3FF + FFC000FFFF0000FFFFC01FFFFFFF03FFFFC0007FFF0000FFFFC737FFFFFC03FF + FF80007FFE00007FFF8F7BFFFFF003FFFF80007FFE01807FFF9FF9FFFFC003FF + FF00007FFE03C07FFF9FF9FFFF0003FFFF00007FFE03C07FFFDEF1FFFF0003FF + FE00007FFE01807FFFECE3FFFFC003FFFE00007FFE00007FFFF803FFFFF003FF + FF30007FFF0000FFFFF007FFFFFC03FFFFFE07FFFF0000FFFFF81FFFFFFF03FF + FFFFCFFFFF8001FFFFFCFFFFFFFFC3FFFFFFFFFFFFC003FFFFFEFFFFFFFFF3FF + FFFFFFFFFFE007FFFFFFFFFFFFFFFFFFFFFFFFFFFFF81FFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 + 000000000000} + end + object PopupMenuMain: TPopupMenu + AutoPopup = False + Left = 72 + Top = 208 + object PopupClose: TMenuItem + Caption = '&Close this popup' + OnClick = PopupCloseClick + end + object N9: TMenuItem + Caption = '-' + end + object PopupPlay: TMenuItem + Caption = '&Play' + OnClick = PopupPlayClick + end + object PopupPause: TMenuItem + Caption = 'Pause' + OnClick = PopupPauseClick + end + object PopupStop: TMenuItem + Caption = 'Stop' + OnClick = PopupStopClick + end + object PopupBack: TMenuItem + Caption = 'Back' + OnClick = PopupBackClick + end + object PopupSlow: TMenuItem + Caption = 'Slow' + OnClick = PopupSlowClick + end + object PopupFast: TMenuItem + Caption = 'Fast' + OnClick = PopupFastClick + end + object N5: TMenuItem + Caption = '-' + end + object PopupToggleInterface: TMenuItem + Caption = 'Toggle &Interface' + OnClick = PopupToggleInterfaceClick + end + object PopupFullscreen: TMenuItem + Caption = '&Fullscreen' + OnClick = PopupFullscreenClick + end + object N6: TMenuItem + Caption = '-' + end + object PopupNext: TMenuItem + Caption = 'Next' + OnClick = PopupNextClick + end + object PopupPrev: TMenuItem + Caption = 'Prev' + OnClick = PopupPrevClick + end + object PopupJump: TMenuItem + Caption = '&Jump...' + OnClick = PopupJumpClick + end + object PopupProgram: TMenuItem + Caption = 'Program' + end + object PopupNavigation: TMenuItem + Caption = 'Navigation' + end + object PopupAudio: TMenuItem + Caption = 'Audio' + end + object PopupSubtitles: TMenuItem + Caption = 'Subtitles' + end + object PopupFile: TMenuItem + Caption = 'File' + object PopupOpenFile: TMenuItem + Caption = 'Open file...' + OnClick = PopupOpenFileClick + end + object PopupOpenDisc: TMenuItem + Caption = 'Open disc...' + OnClick = PopupOpenDiscClick + end + object PopupNetworkStream: TMenuItem + Caption = 'Network stream...' + OnClick = PopupNetworkStreamClick + end + end + object PopupPlaylist: TMenuItem + Caption = 'Playlist...' + OnClick = PopupPlaylistClick + end + object PopupPreferences: TMenuItem + Caption = 'Preferences...' + OnClick = PopupPreferencesClick + end + object N7: TMenuItem + Caption = '-' + end + object PopupExit: TMenuItem + Caption = 'E&xit' + OnClick = PopupExitClick + end + end + object TimerManage: TTimer + OnTimer = TimerManageTimer + Left = 136 + Top = 208 + end +end diff --git a/modules/gui/win32/mainframe.h b/modules/gui/win32/mainframe.h new file mode 100644 index 0000000000..15b41118ce --- /dev/null +++ b/modules/gui/win32/mainframe.h @@ -0,0 +1,207 @@ +/***************************************************************************** + * mainframe.h: Prototype for main window + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + + +#ifndef mainframeH +#define mainframeH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CSPIN.h" +//--------------------------------------------------------------------------- +class TMainFrameDlg : public TForm +{ +__published: // IDE-managed Components + TToolBar *ToolBar; + TToolButton *ToolButtonFile; + TToolButton *ToolButtonDisc; + TToolButton *ToolButtonNet; + TToolButton *ToolButtonSep1; + TToolButton *ToolButtonBack; + TToolButton *ToolButtonStop; + TToolButton *ToolButtonEject; + TToolButton *ToolButtonPlay; + TToolButton *ToolButtonPause; + TToolButton *ToolButtonSlow; + TToolButton *ToolButtonFast; + TToolButton *ToolButtonSep2; + TToolButton *ToolButtonPlaylist; + TToolButton *ToolButtonPrev; + TToolButton *ToolButtonNext; + TMainMenu *MainMenu1; + TMenuItem *MenuFile; + TMenuItem *MenuOpenFile; + TMenuItem *MenuOpenDisc; + TMenuItem *MenuNetworkStream; + TMenuItem *N1; + TMenuItem *MenuExit; + TMenuItem *MenuView; + TMenuItem *MenuHideinterface; + TMenuItem *MenuFullscreen; + TMenuItem *N2; + TMenuItem *MenuTitle; + TMenuItem *MenuChapter; + TMenuItem *MenuAngle; + TMenuItem *N3; + TMenuItem *MenuPlaylist; + TMenuItem *MenuModules; + TMenuItem *MenuMessages; + TMenuItem *MenuSettings; + TMenuItem *MenuAudio; + TMenuItem *MenuSubtitles; + TMenuItem *N4; + TMenuItem *MenuPreferences; + TMenuItem *MenuHelp; + TMenuItem *MenuAbout; + TOpenDialog *OpenDialog1; + TImageList *ImageListToolbar; + TPopupMenu *PopupMenuMain; + TMenuItem *PopupPlay; + TMenuItem *PopupPause; + TMenuItem *PopupStop; + TMenuItem *PopupBack; + TMenuItem *PopupSlow; + TMenuItem *PopupFast; + TMenuItem *N5; + TMenuItem *PopupToggleInterface; + TMenuItem *PopupFullscreen; + TMenuItem *N6; + TMenuItem *PopupNext; + TMenuItem *PopupPrev; + TMenuItem *PopupJump; + TMenuItem *PopupNavigation; + TMenuItem *PopupProgram; + TMenuItem *PopupAudio; + TMenuItem *PopupSubtitles; + TMenuItem *PopupFile; + TMenuItem *PopupPlaylist; + TMenuItem *PopupPreferences; + TMenuItem *N7; + TMenuItem *PopupExit; + TStatusBar *StatusBar; + TGroupBox *GroupBoxFile; + TLabel *LabelFileName; + TGroupBox *GroupBoxNetwork; + TLabel *LabelChannel; + TLabel *LabelServer; + TGroupBox *GroupBoxDisc; + TMenuItem *N8; + TMenuItem *MenuEjectDisc; + TMenuItem *MenuProgram; + TLabel *LabelDisc; + TLabel *LabelTitle; + TButton *ButtonTitlePrev; + TButton *ButtonTitleNext; + TButton *ButtonChapterPrev; + TButton *ButtonChapterNext; + TLabel *LabelChapter; + TLabel *LabelTitleCurrent; + TLabel *LabelChapterCurrent; + TButton *ButtonGo; + TGroupBox *GroupBoxSlider; + TTrackBar *TrackBar; + TTimer *TimerManage; + TMenuItem *PopupOpenFile; + TMenuItem *PopupOpenDisc; + TMenuItem *PopupNetworkStream; + TMenuItem *PopupClose; + TMenuItem *N9; + TCSpinEdit *SpinEditChannel; + TToolButton *ToolButton1; + void __fastcall TimerManageTimer( TObject *Sender ); + void __fastcall TrackBarChange( TObject *Sender ); + void __fastcall FormClose( TObject *Sender, TCloseAction &Action ); + void __fastcall MenuOpenFileClick( TObject *Sender ); + void __fastcall MenuOpenDiscClick( TObject *Sender ); + void __fastcall MenuNetworkStreamClick( TObject *Sender ); + void __fastcall MenuExitClick( TObject *Sender ); + void __fastcall MenuHideinterfaceClick( TObject *Sender ); + void __fastcall MenuFullscreenClick( TObject *Sender ); + void __fastcall MenuPlaylistClick( TObject *Sender ); + void __fastcall MenuMessagesClick( TObject *Sender ); + void __fastcall MenuPreferencesClick( TObject *Sender ); + void __fastcall MenuAboutClick( TObject *Sender ); + void __fastcall ToolButtonFileClick( TObject *Sender ); + void __fastcall ToolButtonDiscClick( TObject *Sender ); + void __fastcall ToolButtonNetClick( TObject *Sender ); + void __fastcall ToolButtonPlaylistClick( TObject *Sender ); + void __fastcall ToolButtonBackClick( TObject *Sender ); + void __fastcall ToolButtonStopClick( TObject *Sender ); + void __fastcall ToolButtonPlayClick( TObject *Sender ); + void __fastcall ToolButtonPauseClick( TObject *Sender ); + void __fastcall ToolButtonSlowClick( TObject *Sender ); + void __fastcall ToolButtonFastClick( TObject *Sender ); + void __fastcall ToolButtonPrevClick( TObject *Sender ); + void __fastcall ToolButtonNextClick( TObject *Sender ); + void __fastcall ToolButtonEjectClick( TObject *Sender ); + void __fastcall PopupCloseClick( TObject *Sender ); + void __fastcall PopupPlayClick( TObject *Sender ); + void __fastcall PopupPauseClick( TObject *Sender ); + void __fastcall PopupStopClick( TObject *Sender ); + void __fastcall PopupBackClick( TObject *Sender ); + void __fastcall PopupSlowClick( TObject *Sender ); + void __fastcall PopupFastClick( TObject *Sender ); + void __fastcall PopupToggleInterfaceClick( TObject *Sender ); + void __fastcall PopupFullscreenClick( TObject *Sender ); + void __fastcall PopupNextClick( TObject *Sender ); + void __fastcall PopupPrevClick( TObject *Sender ); + void __fastcall PopupJumpClick( TObject *Sender ); + void __fastcall PopupPlaylistClick( TObject *Sender ); + void __fastcall PopupPreferencesClick( TObject *Sender ); + void __fastcall PopupExitClick( TObject *Sender ); + void __fastcall PopupOpenFileClick( TObject *Sender ); + void __fastcall PopupOpenDiscClick( TObject *Sender ); + void __fastcall PopupNetworkStreamClick( TObject *Sender ); + void __fastcall ButtonTitlePrevClick( TObject *Sender ); + void __fastcall ButtonTitleNextClick( TObject *Sender ); + void __fastcall ButtonChapterPrevClick( TObject *Sender ); + void __fastcall ButtonChapterNextClick( TObject *Sender ); + void __fastcall ButtonGoClick( TObject *Sender ); +private: // User declarations +public: // User declarations + TStringList *StringListPref; /* stores config dialogs */ + __fastcall TMainFrameDlg( TComponent* Owner ); + virtual __fastcall ~TMainFrameDlg(); + void __fastcall DisplayHint( TObject *Sender ); + void __fastcall ModeManage(); + void __fastcall CreatePreferences( AnsiString Name ); + void __fastcall MenuProgramClick( TObject *Sender ); + void __fastcall MenuAudioClick( TObject *Sender ); + void __fastcall MenuSubtitleClick( TObject *Sender ); + void __fastcall MenuTitleClick( TObject *Sender ); + void __fastcall MenuChapterClick( TObject *Sender ); + void __fastcall PopupProgramClick( TObject *Sender ); + void __fastcall PopupAudioClick( TObject *Sender ); + void __fastcall PopupSubtitleClick( TObject *Sender ); + void __fastcall PopupNavigationClick( TObject *Sender ); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/menu.cpp b/modules/gui/win32/menu.cpp new file mode 100644 index 0000000000..1de6140c6c --- /dev/null +++ b/modules/gui/win32/menu.cpp @@ -0,0 +1,816 @@ +/***************************************************************************** + * menu.cpp: functions to handle menu items + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +//#pragma hdrstop + +#include +#include + +#include "menu.h" +#include "win32_common.h" + + +/**************************************************************************** + * Local Prototypes + ****************************************************************************/ +extern intf_thread_t *p_intfGlobal; + +static TMenuItem *Index2Item( TMenuItem *, int, bool ); +static int Item2Index( TMenuItem *, TMenuItem * ); +static void __fastcall LangChange( TMenuItem *, TMenuItem *, TMenuItem *, int ); +static void __fastcall ProgramChange( TMenuItem *, TMenuItem * ); + +static void __fastcall RadioMenu( TMenuItem *, AnsiString, + int, int, TNotifyEvent ); +static void __fastcall ProgramMenu( TMenuItem *, pgrm_descriptor_t *, + TNotifyEvent ); +static void __fastcall LanguageMenu( TMenuItem *t, es_descriptor_t *, + int, TNotifyEvent ); +static void __fastcall NavigationMenu( TMenuItem *, TNotifyEvent ); + + +static TMenuItem *Index2Item( TMenuItem *Root, int i_index, bool SingleColumn ) +{ + if( SingleColumn || ( i_index < 20 ) ) + { + return Root->Items[i_index]; + } + else + { + return Root->Items[i_index / 10]->Items[i_index % 10]; + } +} + +static int Item2Index( TMenuItem *Root, TMenuItem *Item ) +{ + if( Item->Parent == Root ) + { + return Item->MenuIndex; + } + else + { + return( 10 * Item->Parent->MenuIndex + Item->MenuIndex ); + } +} + + +/**************************************************************************** + * LangChange: change audio or subtitles languages + **************************************************************************** + * Toggle the language, and update the selected menuitems. + ****************************************************************************/ +static void __fastcall LangChange( TMenuItem *RootCurrent, TMenuItem *Item, + TMenuItem *RootOther, int i_cat ) +{ + intf_thread_t * p_intf = p_intfGlobal; + es_descriptor_t * p_es; + es_descriptor_t * p_es_old; + int i_index; + int i_es; + + /* find the selected ES */ + i_es = Item->Tag; + + /* find selected menu item */ + i_index = Item2Index( RootCurrent, Item ) - 1; + if( i_index < 0 ) + { + /* 'None' was selected */ + p_es = NULL; + } + else + { + vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + p_es = p_intfGlobal->p_sys->p_input->stream.pp_es[i_es]; + vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + } + + /* find the current ES */ + if( i_cat == AUDIO_ES ) + { + p_es_old = p_intf->p_sys->p_audio_es_old; + p_intf->p_sys->p_audio_es_old = p_es; + } + else + { + p_es_old = p_intf->p_sys->p_spu_es_old; + p_intf->p_sys->p_spu_es_old = p_es; + } + + /* exchange them */ + input_ToggleES( p_intfGlobal->p_sys->p_input, p_es_old, false ); + input_ToggleES( p_intfGlobal->p_sys->p_input, p_es, true ); + + Item->Checked = true; + Index2Item( RootOther, i_index + 1, true )->Checked = true; +} + + +/**************************************************************************** + * ProgramChange: change the program + **************************************************************************** + * Toggle the program, and update the selected menuitems. + ****************************************************************************/ +static void __fastcall ProgramChange( TMenuItem *Item, TMenuItem *RootOther ) +{ + intf_thread_t * p_intf = p_intfGlobal; + int i_program = Item->Tag; + + /* toggle the program */ + input_ChangeProgram( p_intfGlobal->p_sys->p_input, (u16)i_program ); + + /* check selected menu items */ + Item->Checked = true; + Index2Item( RootOther, i_program - 1, true )->Checked = true; + + /* update audio/subtitles menus */ + p_intf->p_sys->b_audio_update = 1; + p_intf->p_sys->b_spu_update = 1; + vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + SetupMenus( p_intf ); + vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + p_intf->p_sys->b_audio_update = 0; + p_intf->p_sys->b_spu_update = 0; + + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY ); +} + + +/**************************************************************************** + * TMainFrameDlg::*Click: callbacks for the menuitems + **************************************************************************** + * These functions need to be in a class, or we won't be able to pass them + * as arguments (since TNotifyEvent uses __closure) + ****************************************************************************/ + + /* + * Audio + */ + +void __fastcall TMainFrameDlg::MenuAudioClick( TObject *Sender ) +{ + LangChange( MenuAudio, (TMenuItem *)Sender, PopupAudio, AUDIO_ES ); +} + +void __fastcall TMainFrameDlg::PopupAudioClick( TObject *Sender ) +{ + LangChange( PopupAudio, (TMenuItem *)Sender, MenuAudio, AUDIO_ES ); +} + +/* + * Subtitles + */ + +void __fastcall TMainFrameDlg::MenuSubtitleClick( TObject *Sender ) +{ + LangChange( MenuSubtitles, (TMenuItem *)Sender, PopupSubtitles, SPU_ES ); +} + +void __fastcall TMainFrameDlg::PopupSubtitleClick( TObject *Sender ) +{ + LangChange( PopupSubtitles, (TMenuItem *)Sender, MenuSubtitles, SPU_ES ); +} + +/* + * Program + */ + +void __fastcall TMainFrameDlg::MenuProgramClick( TObject *Sender ) +{ + ProgramChange( (TMenuItem *)Sender, PopupProgram ); +} + +void __fastcall TMainFrameDlg::PopupProgramClick( TObject *Sender ) +{ + ProgramChange( (TMenuItem *)Sender, MenuProgram ); +} + +/* + * Navigation + */ + +void __fastcall TMainFrameDlg::PopupNavigationClick( TObject *Sender ) +{ + TMenuItem * Item = (TMenuItem *)Sender; + TMenuItem * ItemTitle; + input_area_t * p_area; + int i_title = DATA2TITLE( Item->Tag ); + int i_chapter = DATA2CHAPTER( Item->Tag ); + + p_area = p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]; + p_area->i_part = i_chapter; + + input_ChangeArea( p_intfGlobal->p_sys->p_input, (input_area_t*)p_area ); + + Item->Checked = true; + ItemTitle = Index2Item( MenuTitle, i_title - 1, false ); + if( ItemTitle->Checked ) + { + /* same title, new chapter */ + Index2Item( MenuChapter, i_chapter - 1, false )->Checked = true; + } + else + { + /* new title => we must rebuild the chapter menu */ + vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + RadioMenu( MenuChapter, "Chapter", + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part_nb, + i_chapter, MenuChapterClick ); + vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + } + + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY ); +} + +/* + * Title + */ + +void __fastcall TMainFrameDlg::MenuTitleClick( TObject *Sender ) +{ + TMenuItem * Item = (TMenuItem *)Sender; + TMenuItem * ItemTitle; + int i_title = Item->Tag; + + input_ChangeArea( p_intfGlobal->p_sys->p_input, + p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title] ); + Item->Checked = true; + ItemTitle = Index2Item( PopupNavigation, i_title - 1, false ); + Index2Item( ItemTitle, 0, false )->Checked = true; + + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY ); +} + +/* + * Chapter + */ + +void __fastcall TMainFrameDlg::MenuChapterClick( TObject *Sender ) +{ + TMenuItem * Item = (TMenuItem *)Sender; + TMenuItem * ItemTitle; + input_area_t * p_area; + int i_title; + int i_chapter = Item->Tag; + + p_area = p_intfGlobal->p_sys->p_input->stream.p_selected_area; + p_area->i_part = i_chapter; + + input_ChangeArea( p_intfGlobal->p_sys->p_input, (input_area_t*)p_area ); + + i_title = p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id; + ItemTitle = Index2Item( PopupNavigation, i_title - 1, false ); + Index2Item( ItemTitle, i_chapter - 1, false )->Checked = true; + + input_SetStatus( p_intfGlobal->p_sys->p_input, INPUT_STATUS_PLAY ); +} + + +/**************************************************************************** + * Functions to generate menus + ****************************************************************************/ + +/***************************************************************************** + * RadioMenu: update interactive menus of the interface + ***************************************************************************** + * Sets up menus with information from input + * Warning: since this function is designed to be called by management + * function, the interface lock has to be taken + *****************************************************************************/ +static void __fastcall RadioMenu( TMenuItem * Root, AnsiString ItemName, + int i_nb, int i_selected, + TNotifyEvent MenuItemClick ) +{ + TMenuItem * ItemGroup; + TMenuItem * Item; + TMenuItem * ItemActive; + AnsiString Name; + int i_item; + + /* remove previous menu */ + Root->Enabled = false; + Root->Clear(); + + ItemActive = NULL; + + for( i_item = 0; i_item < i_nb; i_item++ ) + { + /* we group titles/chapters in packets of ten for small screens */ + if( ( i_item % 10 == 0 ) && ( i_nb > 20 ) ) + { + if( i_item != 0 ) + { + Root->Add( ItemGroup ); + } + + Name.sprintf( "%ss %d to %d", ItemName, i_item + 1, i_item + 10 ); + ItemGroup = new TMenuItem( Root ); + ItemGroup->Hint = Name; + + /* set the accelerator character */ + Name.Insert( "&", Name.Length() - 1 ); + ItemGroup->Caption = Name; + } + + Name.sprintf( "%s %d", ItemName, i_item + 1 ); + Item = new TMenuItem( Root ); + Item->RadioItem = true; + Item->Hint = Name; + + /* set the accelerator character */ + Name.Insert( "&", Name.Length() ); + Item->Caption = Name; + + /* FIXME: temporary hack to save i_item with the Item + * It will be used in the callback. */ + Item->Tag = i_item + 1; + + if( i_selected == i_item + 1 ) + { + ItemActive = Item; + } + + /* setup signal handling */ + Item->OnClick = MenuItemClick; + + if( i_nb > 20 ) + { + ItemGroup->Add( Item ); + } + else + { + Root->Add( Item ); + } + } + +// if( ( i_nb > 20 ) && ( i_item % 10 ) ) ? + if( i_nb > 20 ) + { + Root->Add( ItemGroup ); + } + + /* check currently selected chapter */ + if( ItemActive != NULL ) + { + ItemActive->Checked = true; + } + + /* be sure that menu is enabled, if there are several items */ + if( i_nb > 1 ) + { + Root->Enabled = true; + } +} + + +/***************************************************************************** + * ProgramMenu: update the programs menu of the interface + ***************************************************************************** + * Builds the program menu according to what have been found in the PAT + * by the input. Useful for multi-programs streams such as DVB ones. + *****************************************************************************/ +static void __fastcall ProgramMenu( TMenuItem * Root, + pgrm_descriptor_t * p_pgrm, + TNotifyEvent MenuItemClick ) +{ + TMenuItem * Item; + TMenuItem * ItemActive; + AnsiString Name; + int i; + + /* remove previous menu */ + Root->Clear(); + Root->Enabled = false; + + ItemActive = NULL; + + /* create a set of program buttons and append them to the container */ + for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_pgrm_number; i++ ) + { + Name.sprintf( "id %d", + p_intfGlobal->p_sys->p_input->stream.pp_programs[i]->i_number ); + + Item = new TMenuItem( Root ); + Item->Caption = Name; + Item->Hint = Name; + Item->RadioItem = true; + Item->OnClick = MenuItemClick; + + /* FIXME: temporary hack to save the program id with the Item + * It will be used in the callback. */ + Item->Tag = i + 1; + + if( p_pgrm == p_intfGlobal->p_sys->p_input->stream.pp_programs[i] ) + { + /* don't lose Item when we append into menu */ + ItemActive = Item; + } + + /* Add the item to the submenu */ + Root->Add( Item ); + } + + /* check currently selected program */ + if( ItemActive != NULL ) + { + ItemActive->Checked = true; + } + + /* be sure that menu is enabled if more than 1 program */ + if( p_intfGlobal->p_sys->p_input->stream.i_pgrm_number > 1 ) + { + Root->Enabled = true; + } +} + + +/***************************************************************************** + * LanguageMenus: update interactive menus of the interface + ***************************************************************************** + * Sets up menus with information from input: + * - languages + * - sub-pictures + * Warning: since this function is designed to be called by management + * function, the interface lock has to be taken + *****************************************************************************/ +static void __fastcall LanguageMenu( TMenuItem * Root, es_descriptor_t * p_es, + int i_cat, TNotifyEvent MenuItemClick ) +{ + TMenuItem * Separator; + TMenuItem * Item; + TMenuItem * ItemActive; + AnsiString Name; + int i_item; + int i; + + /* remove previous menu */ + Root->Clear(); + Root->Enabled = false; + + /* special case for "off" item */ + Name = "None"; + Item = new TMenuItem( Root ); + Item->RadioItem = true; + Item->Hint = Name; + Item->Caption = Name; + Item->OnClick = MenuItemClick; + Item->Tag = -1; + Root->Add( Item ); + + /* separator item */ + Separator = new TMenuItem( Root ); + Separator->Caption = "-"; + Root->Add( Separator ); + + ItemActive = NULL; + i_item = 0; + + vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + +#define ES p_intfGlobal->p_sys->p_input->stream.pp_es[i] + /* create a set of language buttons and append them to the Root */ + for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_es_number; i++ ) + { + if( ( ES->i_cat == i_cat ) && + ( !ES->p_pgrm || + ES->p_pgrm == + p_intfGlobal->p_sys->p_input->stream.p_selected_program ) ) + { + i_item++; + Name = p_intfGlobal->p_sys->p_input->stream.pp_es[i]->psz_desc; + if( Name.IsEmpty() ) + { + Name.sprintf( "Language %d", i_item ); + } + + Item = new TMenuItem( Root ); + Item->RadioItem = true; + Item->Hint = Name; + Item->Caption = Name; + Item->Tag = i; + + if( p_es == p_intfGlobal->p_sys->p_input->stream.pp_es[i] ) + { + /* don't lose Item when we append into menu */ + ItemActive = Item; + } + + /* setup signal hanling */ + Item->OnClick = MenuItemClick; + Root->Add( Item ); + } + } +#undef ES + + vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + + /* check currently selected item */ + if( ItemActive != NULL ) + { + ItemActive->Checked = true; + } + + /* be sure that menu is enabled if non empty */ + if( i_item > 0 ) + { + Root->Enabled = true; + } +} + + +/***************************************************************************** + * NavigationMenu: sets menus for titles and chapters selection + ***************************************************************************** + * Generates two types of menus: + * -simple list of titles + * -cascaded lists of chapters for each title + *****************************************************************************/ +static void __fastcall NavigationMenu( TMenuItem * Root, + TNotifyEvent MenuItemClick ) +{ + TMenuItem * TitleGroup; + TMenuItem * TitleItem; + TMenuItem * ItemActive; + TMenuItem * ChapterGroup; + TMenuItem * ChapterItem; + AnsiString Name; + int i_title; + int i_chapter; + int i_title_nb; + int i_chapter_nb; + + + /* remove previous menu */ + Root->Enabled = false; + Root->Clear(); + + ItemActive = NULL; + i_title_nb = p_intfGlobal->p_sys->p_input->stream.i_area_nb; + + /* loop on titles */ + for( i_title = 1; i_title < i_title_nb; i_title++ ) + { + /* we group titles in packets of ten for small screens */ + if( ( i_title % 10 == 1 ) && ( i_title_nb > 20 ) ) + { + if( i_title != 1 ) + { + Root->Add( TitleGroup ); + } + + Name.sprintf( "%d - %d", i_title, i_title + 9 ); + TitleGroup = new TMenuItem( Root ); + TitleGroup->RadioItem = true; + TitleGroup->Hint = Name; + TitleGroup->Caption = Name; + } + + Name.sprintf( "Title %d (%d)", i_title, + p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb ); + + { + TitleItem = new TMenuItem( Root ); + TitleItem->RadioItem = true; + TitleItem->Hint = Name; + TitleItem->Caption = Name; + + i_chapter_nb = + p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb; + + /* loop on chapters */ + for( i_chapter = 0; i_chapter < i_chapter_nb; i_chapter++ ) + { + /* we group chapters in packets of ten for small screens */ + if( ( i_chapter % 10 == 0 ) && ( i_chapter_nb > 20 ) ) + { + if( i_chapter != 0 ) + { + TitleItem->Add( ChapterGroup ); + } + + Name.sprintf( "%d - %d", i_chapter + 1, i_chapter + 10 ); + ChapterGroup = new TMenuItem( TitleItem ); + ChapterGroup->RadioItem = true; + ChapterGroup->Hint = Name; + ChapterGroup->Caption = Name; + } + + Name.sprintf( "Chapter %d", i_chapter + 1 ); + + ChapterItem = new TMenuItem( TitleItem ); + ChapterItem->RadioItem = true; + ChapterItem->Hint = Name; + ChapterItem->Caption = Name; + + /* FIXME: temporary hack to save i_title and i_chapter with + * ChapterItem, since we will need them in the callback */ + ChapterItem->Tag = (int)POS2DATA( i_title, i_chapter + 1 ); + +#define p_area p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title] + if( ( p_area == + p_intfGlobal->p_sys->p_input->stream.p_selected_area ) && + ( p_area->i_part == i_chapter + 1 ) ) + { + ItemActive = ChapterItem; + } +#undef p_area + + /* setup signal hanling */ + ChapterItem->OnClick = MenuItemClick; + + if( i_chapter_nb > 20 ) + { + ChapterGroup->Add( ChapterItem ); + } + else + { + TitleItem->Add( ChapterItem ); + } + } + + if( i_chapter_nb > 20 ) + { + TitleItem->Add( ChapterGroup ); + } + + if( p_intfGlobal->p_sys->p_input->stream.pp_areas[i_title]->i_part_nb + > 1 ) + { + /* be sure that menu is sensitive */ + Root->Enabled = true; + } + } + + if( i_title_nb > 20 ) + { + TitleGroup->Add( TitleItem ); + } + else + { + Root->Add( TitleItem ); + } + } + + if( i_title_nb > 20 ) + { + Root->Add( TitleGroup ); + } + + /* Default selected chapter */ + if( ItemActive != NULL ) + { + ItemActive->Checked = true; + } + + /* be sure that menu is sensitive */ + Root->Enabled = true; +} + + +/***************************************************************************** + * SetupMenus: function that generates title/chapter/audio/subpic + * menus with help from preceding functions + *****************************************************************************/ +int __fastcall SetupMenus( intf_thread_t * p_intf ) +{ + TMainFrameDlg * p_window = p_intf->p_sys->p_window; + es_descriptor_t * p_audio_es; + es_descriptor_t * p_spu_es; + int i; + + p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update; + p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update | + p_intf->p_sys->b_program_update; + + if( p_intf->p_sys->b_program_update ) + { + pgrm_descriptor_t * p_pgrm; + + if( p_intfGlobal->p_sys->p_input->stream.p_new_program ) + { + p_pgrm = p_intfGlobal->p_sys->p_input->stream.p_new_program; + } + else + { + p_pgrm = p_intfGlobal->p_sys->p_input->stream.p_selected_program; + } + + ProgramMenu( p_window->MenuProgram, p_pgrm, + p_window->MenuProgramClick ); + ProgramMenu( p_window->PopupProgram, p_pgrm, + p_window->PopupProgramClick ); + + p_intf->p_sys->b_program_update = 0; + } + + if( p_intf->p_sys->b_title_update ) + { + RadioMenu( p_window->MenuTitle, "Title", +//why "-1" ? + p_intfGlobal->p_sys->p_input->stream.i_area_nb - 1, + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id, + p_window->MenuTitleClick ); + + AnsiString CurrentTitle; + CurrentTitle.sprintf( "%d", + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_id ); + p_window->LabelTitleCurrent->Caption = CurrentTitle; + + p_intf->p_sys->b_title_update = 0; + } + + if( p_intf->p_sys->b_chapter_update ) + { + RadioMenu( p_window->MenuChapter, "Chapter", + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part_nb, + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part, + p_window->MenuChapterClick ); + + NavigationMenu( p_window->PopupNavigation, + p_window->PopupNavigationClick ); + + AnsiString CurrentChapter; + CurrentChapter.sprintf( "%d", + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part ); + p_window->LabelChapterCurrent->Caption = CurrentChapter; + + p_intf->p_sys->i_part = + p_intfGlobal->p_sys->p_input->stream.p_selected_area->i_part; + + p_intf->p_sys->b_chapter_update = 0; + } + + /* look for selected ES */ + p_audio_es = NULL; + p_spu_es = NULL; + + for( i = 0; i < p_intfGlobal->p_sys->p_input->stream.i_selected_es_number; i++ ) + { + if( p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]->i_cat + == AUDIO_ES ) + { + p_audio_es = p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]; + p_intfGlobal->p_sys->p_audio_es_old = p_audio_es; + } + + if( p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]->i_cat + == SPU_ES ) + { + p_spu_es = p_intfGlobal->p_sys->p_input->stream.pp_selected_es[i]; + p_intfGlobal->p_sys->p_spu_es_old = p_spu_es; + } + } + + vlc_mutex_unlock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + + /* audio menus */ + if( p_intf->p_sys->b_audio_update ) + { + LanguageMenu( p_window->MenuAudio, p_audio_es, AUDIO_ES, + p_window->MenuAudioClick ); + LanguageMenu( p_window->PopupAudio, p_audio_es, AUDIO_ES, + p_window->PopupAudioClick ); + + p_intf->p_sys->b_audio_update = 0; + } + + /* sub picture menus */ + if( p_intf->p_sys->b_spu_update ) + { + LanguageMenu( p_window->PopupSubtitles, p_spu_es, SPU_ES, + p_window->PopupSubtitleClick ); + LanguageMenu( p_window->MenuSubtitles, p_spu_es, SPU_ES, + p_window->MenuSubtitleClick ); + + p_intf->p_sys->b_spu_update = 0; + } + + vlc_mutex_lock( &p_intfGlobal->p_sys->p_input->stream.stream_lock ); + + return true; +} + + + diff --git a/modules/gui/win32/menu.h b/modules/gui/win32/menu.h new file mode 100644 index 0000000000..5c4ca32c8d --- /dev/null +++ b/modules/gui/win32/menu.h @@ -0,0 +1,32 @@ +/***************************************************************************** + * menu.h: prototypes for menu functions + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 __fastcall SetupMenus( intf_thread_t * ); + +/***************************************************************************** + * Convert user_data structures to title and chapter information + *****************************************************************************/ +#define DATA2TITLE( data ) ( (int)((long)(data)) >> 16 ) +#define DATA2CHAPTER( data ) ( (int)((long)(data)) & 0xffff ) +#define POS2DATA( title, chapter ) ( NULL + ( ((title) << 16) \ + | ((chapter) & 0xffff)) ) + diff --git a/modules/gui/win32/messages.cpp b/modules/gui/win32/messages.cpp new file mode 100644 index 0000000000..ef723ea77a --- /dev/null +++ b/modules/gui/win32/messages.cpp @@ -0,0 +1,113 @@ +/***************************************************************************** + * messages.cpp: log window. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include +#include + +#include "win32_common.h" +#include "messages.h" + +//--------------------------------------------------------------------------- +#pragma package(smart_init) +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + +//--------------------------------------------------------------------------- +__fastcall TMessagesDlg::TMessagesDlg( TComponent* Owner ) + : TForm( Owner ) +{ + Icon = p_intfGlobal->p_sys->p_window->Icon; +} +//--------------------------------------------------------------------------- +void __fastcall TMessagesDlg::ButtonOKClick( TObject *Sender ) +{ + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TMessagesDlg::FormHide( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuMessages->Checked = false; +} +//--------------------------------------------------------------------------- +void __fastcall TMessagesDlg::FormShow( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuMessages->Checked = true; +} +//--------------------------------------------------------------------------- +void __fastcall TMessagesDlg::UpdateLog() +{ + msg_subscription_t *p_sub = p_intfGlobal->p_sys->p_sub; + int i_start, i_stop, i_del, i_count; + int i_max_lines; + + vlc_mutex_lock( p_sub->p_lock ); + i_stop = *p_sub->pi_stop; + vlc_mutex_unlock( p_sub->p_lock ); + + if( p_sub->i_start != i_stop ) + { + for( i_start = p_sub->i_start; + i_start != i_stop; + i_start = (i_start+1) % VLC_MSG_QSIZE ) + { + /* Append all messages to log window */ + switch( p_sub->p_msg[i_start].i_type ) + { + case VLC_MSG_ERR: + RichEditMessages->SelAttributes->Color = clRed; + break; + case VLC_MSG_WARN: + RichEditMessages->SelAttributes->Color = clBlack; + break; + default: + RichEditMessages->SelAttributes->Color = clBlue; + break; + } + + /* Limit log size */ + i_count = RichEditMessages->Lines->Count; + i_max_lines = config_GetInt( p_intfGlobal, "intfwin-max-lines" ); + if( i_max_lines > 0 ) + { + for( i_del = 0; i_del <= i_count - i_max_lines; i_del++ ) + { + RichEditMessages->Lines->Delete( 0 ); + } + } + + /* Add message */ + if( i_max_lines ) + { + RichEditMessages->Lines->Add( p_sub->p_msg[i_start].psz_msg ); + } + } + + vlc_mutex_lock( p_sub->p_lock ); + p_sub->i_start = i_start; + vlc_mutex_unlock( p_sub->p_lock ); + } +} +//--------------------------------------------------------------------------- diff --git a/modules/gui/win32/messages.dfm b/modules/gui/win32/messages.dfm new file mode 100644 index 0000000000..dbe1734b33 --- /dev/null +++ b/modules/gui/win32/messages.dfm @@ -0,0 +1,46 @@ +object MessagesDlg: TMessagesDlg + Left = 325 + Top = 160 + Width = 440 + Height = 502 + Caption = 'Messages' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clPurple + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + OnHide = FormHide + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object RichEditMessages: TRichEdit + Left = 0 + Top = 0 + Width = 432 + Height = 424 + Align = alTop + Anchors = [akLeft, akTop, akRight, akBottom] + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + WantReturns = False + end + object ButtonOK: TButton + Left = 144 + Top = 437 + Width = 145 + Height = 25 + Anchors = [akBottom] + Caption = 'OK' + TabOrder = 1 + OnClick = ButtonOKClick + end +end diff --git a/modules/gui/win32/messages.h b/modules/gui/win32/messages.h new file mode 100644 index 0000000000..74bbc9a68b --- /dev/null +++ b/modules/gui/win32/messages.h @@ -0,0 +1,47 @@ +/***************************************************************************** + * messages.h: log window + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef messagesH +#define messagesH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +//--------------------------------------------------------------------------- +class TMessagesDlg : public TForm +{ +__published: // IDE-managed Components + TRichEdit *RichEditMessages; + TButton *ButtonOK; + void __fastcall ButtonOKClick( TObject *Sender ); + void __fastcall FormHide( TObject *Sender ); + void __fastcall FormShow( TObject *Sender ); +private: // User declarations +public: // User declarations + __fastcall TMessagesDlg( TComponent* Owner ); + void __fastcall UpdateLog(); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/network.cpp b/modules/gui/win32/network.cpp new file mode 100644 index 0000000000..eb499f6524 --- /dev/null +++ b/modules/gui/win32/network.cpp @@ -0,0 +1,235 @@ +/***************************************************************************** + * network.cpp: the "network" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include +#include + +#include "network.h" +#include "win32_common.h" + +#include "netutils.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma link "CSPIN" +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + +//--------------------------------------------------------------------------- +__fastcall TNetworkDlg::TNetworkDlg( TComponent* Owner ) + : TForm( Owner ) +{ + char *psz_channel_server; + + OldRadioValue = 0; + + /* server port */ + SpinEditUDPPort->Value = config_GetInt( p_intfGlobal, "server-port" ); + SpinEditMulticastPort->Value = config_GetInt( p_intfGlobal, "server-port" ); + + /* channel server */ + if( config_GetInt( p_intfGlobal, "network-channel" ) ) + { + RadioButtonCS->Checked = true; + RadioButtonCSEnter( RadioButtonCS ); + } + + psz_channel_server = config_GetPsz( p_intfGlobal, "channel-server" ); + if( psz_channel_server ) + { + ComboBoxCSAddress->Text = psz_channel_server; + free( psz_channel_server ); + } + + SpinEditCSPort->Value = config_GetInt( p_intfGlobal, "channel-port" ); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::FormShow( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuNetworkStream->Checked = true; + p_intfGlobal->p_sys->p_window->PopupNetworkStream->Checked = true; +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::FormHide( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuNetworkStream->Checked = false; + p_intfGlobal->p_sys->p_window->PopupNetworkStream->Checked = false; +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::BitBtnCancelClick( TObject *Sender ) +{ + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::BitBtnOkClick( TObject *Sender ) +{ + AnsiString Source, Address; + AnsiString Channel = ComboBoxCSAddress->Text; + unsigned int i_channel_port = SpinEditCSPort->Value; + unsigned int i_port; + playlist_t * p_playlist; + + p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + Hide(); + + /* Check which option was chosen */ + switch( OldRadioValue ) + { + /* UDP */ + case 0: + config_PutInt( p_intfGlobal, "network-channel", FALSE ); + i_port = SpinEditUDPPort->Value; + + /* Build source name */ + Source = "udp:@:" + IntToStr( i_port ); + + playlist_Add( p_playlist, Source.c_str(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* update the display */ + p_intfGlobal->p_sys->p_playwin->UpdateGrid( p_playlist ); + break; + + /* UDP Multicast */ + case 1: + config_PutInt( p_intfGlobal, "network-channel", FALSE ); + Address = ComboBoxMulticastAddress->Text; + i_port = SpinEditMulticastPort->Value; + + /* Build source name */ + Source = "udp:@" + Address + ":" + IntToStr( i_port ); + + playlist_Add( p_playlist, Source.c_str(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* update the display */ + p_intfGlobal->p_sys->p_playwin->UpdateGrid( p_playlist ); + break; + + /* Channel server */ + case 2: + config_PutInt( p_intfGlobal, "network-channel", TRUE ); + config_PutPsz( p_intfGlobal, "channel-server", Channel.c_str() ); + config_PutInt( p_intfGlobal, "channel-port", i_channel_port ); + + if( p_intfGlobal->p_vlc->p_channel == NULL ) + { + network_ChannelCreate( p_intfGlobal ); + } + + p_intfGlobal->p_sys->b_playing = 1; + break; + + /* HTTP */ + case 3: + config_PutInt( p_intfGlobal, "network-channel", FALSE ); + Address = EditHTTPURL->Text; + + /* Build source name with a basic test */ + if( Address.SubString( 1, 4 ) == "http" ) + { + Source = Address; + } + else + { + Source = "http://" + Address; + } + + playlist_Add( p_playlist, Source.c_str(), + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + + /* update the display */ + p_intfGlobal->p_sys->p_playwin->UpdateGrid( p_playlist ); + break; + } + + vlc_object_release( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::ChangeEnabled( int i_selected ) +{ + switch( i_selected ) + { + case 0: + LabelUDPPort->Enabled = NOT( LabelUDPPort->Enabled ); + SpinEditUDPPort->Enabled = NOT( SpinEditUDPPort->Enabled ); + break; + case 1: + LabelMulticastAddress->Enabled = + NOT( LabelMulticastAddress->Enabled ); + ComboBoxMulticastAddress->Enabled = + NOT( ComboBoxMulticastAddress->Enabled ); + LabelMulticastPort->Enabled = NOT( LabelMulticastPort->Enabled ); + SpinEditMulticastPort->Enabled = NOT( SpinEditMulticastPort->Enabled ); + break; + case 2: + LabelCSAddress->Enabled = NOT( LabelCSAddress->Enabled ); + ComboBoxCSAddress->Enabled = NOT( ComboBoxCSAddress->Enabled ); + LabelCSPort->Enabled = NOT( LabelCSPort->Enabled ); + SpinEditCSPort->Enabled = NOT( SpinEditCSPort->Enabled ); + break; + case 3: + LabelHTTPURL->Enabled = NOT( LabelHTTPURL->Enabled ); + EditHTTPURL->Enabled = NOT( EditHTTPURL->Enabled ); + break; + } +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::RadioButtonUDPEnter( TObject *Sender ) +{ + ChangeEnabled( OldRadioValue ); + OldRadioValue = 0; + ChangeEnabled( OldRadioValue ); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::RadioButtonMulticastEnter( TObject *Sender ) +{ + ChangeEnabled( OldRadioValue ); + OldRadioValue = 1; + ChangeEnabled( OldRadioValue ); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::RadioButtonCSEnter( TObject *Sender ) +{ + ChangeEnabled( OldRadioValue ); + OldRadioValue = 2; + ChangeEnabled( OldRadioValue ); +} +//--------------------------------------------------------------------------- +void __fastcall TNetworkDlg::RadioButtonHTTPEnter( TObject *Sender ) +{ + ChangeEnabled( OldRadioValue ); + OldRadioValue = 3; + ChangeEnabled( OldRadioValue ); +} +//--------------------------------------------------------------------------- + diff --git a/modules/gui/win32/network.dfm b/modules/gui/win32/network.dfm new file mode 100644 index 0000000000..02f6cd6f5f --- /dev/null +++ b/modules/gui/win32/network.dfm @@ -0,0 +1,425 @@ +object NetworkDlg: TNetworkDlg + Left = 369 + Top = 301 + BorderStyle = bsDialog + Caption = 'Open network' + ClientHeight = 206 + ClientWidth = 482 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Icon.Data = { + 0000010001003030000001001800A81C00001600000028000000300000006000 + 00000100180000000000001B0000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000069375900000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000120E0A4011253E0F18000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000F0B + 084143CA08070016430F08040800000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000003127291203174647E8464AE808010840E54039E6390B0C06 + 0E0A1C0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0070CD0079DD0079DD0070CD0000000000000000000C1008261D6E4647E54547 + E64748E105040039E6393AE53939E63936D33308030100000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000070CD0079DD0079DE007DE40088F9008CFF008CFF0088F9007CE302 + 6EC70B09124641DC4444DF4546E34446E54847E003040040E6403AEA3A3EE33E + 3CE33C39E639080F010801050000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0079DD0077D90070CB0078D8007BDC007BDC007BDC + 007BDC007BDC007BDD007EE32E232D0804084553F14250F34252ED4449DB4844 + DC4645E208010540E5401C78150D18053CE63C3AE63A39EA393CD83C241A2006 + 0402000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0079DD007ADF007BDE007BDC0072 + CC005188004877004876004876004876034976054A760B4D7731434221175B42 + 54EC4253EE4252F60B05104250F44252EB4546DA08010539E6392BAA2B080105 + 3CE63C39E7393AE63A39E93939E839081208181C080000000000000000000000 + 000000000000000000000000000000000000000070CD0079DD0079DD007CE300 + 88F90089F90075D2005188004877005188008CFF008CFF008CFF008CFF008CFF + 1092FF2099FF31A0FF1408294840DB4550E1464EEA0C060B0B05084654F64653 + F64453EF080E033AE63A2BAA2B03030339E33939DF3939E639080F083DDB3D24 + 9C24434B3B000000000000000000000000000000000000000000000000000000 + 0063B60085F3008BFE0088F9007FE90088F90080E8005CA0008CFF008CFF008C + FF008CFF008CFF008CFF008CFF048DFF1594FF259BFF35A2FF0C04103F38C754 + 5AF7505BF10C08100801084352F64652F44253F30813053AE63A39E639030403 + 1C521826A1250812010807032454131558150000000000000000000000000000 + 000000000000000000000000000000000000000070CD007CE30079DD00000000 + 7CE30089FA008CFF0089FA008CFF008CFF008CFF008CFF008CFF008CFF098FFF + 1996FF2A9DFF3AA4FF0804103A2AA34E58F74E58F40B0B120803054652F34548 + E64451F305130532CA323AE23A03070308070307040008040139E63939E43931 + B42F5E1347000000000000000000000000000000000000000000000000000000 + 0000000000000000000061B10000000079DD008CFF008CFF008CFF008CFF008C + FF008CFF008CFF008CFF008CFF0E91FF1E98FF2E9FFF3FA6FF040408382BAF4D + 5AEF555AF70F12250501050F04160804074250F3121A123AE93A39E239080803 + 0D2F08010401268C2539E7393DE63D3FE23E0804100000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 79DD008CFF008CFF008CFF008CFF008CFF008CFF008CFF008CFF028CFF1293FF + 239AFF33A1FF43A8FF0802083A2AA3565BF7555AF71714330501050104000801 + 07424FF12828203AEA3A39E639030703182F1008340801040139E7393DE83D39 + E939080400000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0088F9008CFF008CFF008CFF008C + FF008CFF008CFF008CFF078EFF1795FF279CFF38A3FF48AAFF0808005151F155 + 5AF30804030804000504050800082E358E0E0C1F1D192439E53940E640080400 + 2AA12739E63908020708010539E8393BE93B0804080000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000007CE3008CFF008CFF008CFF058EFD1D96F92398F8269AFA31A0FC42A8FF + 4FAEFF5CB3FF65B7FF0C08084F5AF14E57F50B04080804043639A54647E81C13 + 49363AA70804080F120835953439E7393EE63E39DF3939EA39081105308A2B3F + E73F080601000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000047BDB1D96F92398F82498F83BA0 + F399C1E1B1C9DDBCD4E7CBE0F3D9EDFFDCEEFFDEEFFFCDE8FF080808575BF750 + 58F624125A5057F34845DF4A41E0150E30C55734E3723EC56E33A23D27050105 + 39E43939E63939E6393CE63C14420C3BE03B192A090000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000004 + 04042D88D399C1E1B1C9DDB1C9DCB7CBDBCFD3D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFF9FCFF0C08085D61F15B61EF555AF64A4FE13937BB0E0A12DE74 + 39E1733CDE713CDF753AE67541C36B342C231F17141B3AE63A39E7393DE83D39 + E93939DE39000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000001818186893B8C3CCD2D5D5D6D5D5D6D5D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFFFFFFFFFFFF140C145C5EF668 + 63F75555EA10061CC3673FDF713A0C1104080403080105080007070407D56F36 + DE743EDE72401C200C29452939E63939E73939EA390000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000343434A2B4C2D5D5D6D6D6D6D6D6D6D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFFEFEFF20161C5C5EF6373EAE0E0413E2713DE1763CCD6A3C2A0D + 08A44B2CDE743EBD612F080401030403E1713CDE7239DE713AE1723C22201139 + C13341E641000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001B1B1B99AEBED5D5D6D5D5D6D5D5 + D6CFD3D7B8CBDBBFD5E7CEE2F3DCEFFFDFF0FFE2F1FFE9F4FF10100C3639A46E + 4540DE7239DE713DE1713C07000784261CDE7639E3743E0812001F0407D86E36 + E3753EE57540E57541DE763CDE733DD26637493C387E2F7B0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00001B1B1B99AEBFCED3D7B7CBDBB1C9DD99C1E140A2F339A2FA49AAFC59B2FF + 66B8FF74BEFF92CBFFD9ECFF0F0402C66531DE7139E2733D854B1E0A01084D11 + 0DE3733EE1723CDF713ADF753AE1763C1D0A08290708E57140E1763CDE733DC7 + 6B34080408000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001818187FA5C399C1E13BA0F32498 + F81D96F91091FD1C97FF2C9EFF3CA5FF4DACFF5DB3FF71BBFF8DC8FF9FD0FF08 + 0400080406B95C2EDE7239070B070803014D1615DE723CDE7540E5714030090D + 0504003A120FE67541DE75390808044A0C290000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000707071778C81C92F3058EFD008CFF008CFF1092FF2099FF31A0FF41A7FF + 51AEFF62B5FF72BCFF7BBFFF7BBBF96E9FCD0808080806041D0508E571403E22 + 0C200708080405070407070007080303B05F31DE723967301908010500000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000007CE3008CFF008C + FF048DFF1594FF259BFF35A2FF46A9FF56B0FF66B7FF77BEFF7BBFFF6DAAE300 + 0000000000000000000000080401200C088D4024E17141E57140DF713ADE713E + DE76390801070000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000079DD008CFF008CFF098FFF1996FF2A9DFF3AA4FF4AABFF + 5BB2FF6BB9FF7BBFFF7BBFFF6AA5DD0000000000000000000000000000001D1A + 0C1A0F08110903441912E57140623B1E08020300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000079DD008CFF008C + FF0E91FF1E98FF2E9FFF3FA6FF4FADFF5FB4FF70BBFF7BBFFF78BAF96299CD00 + 00000000000000000000000000000000000000003914100000005A2411000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0088F9078EFD2C9CF940A3F850ACFA60B4FC70BCFF + 7DC2FF87C6FF7EC0FF6DAAE30000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000707071A85DD40A2 + F3A0C3E1B7CBDDC6D8E7D4E5F3E2F1FFE5F2FFD9ECFF9FD0FF7AACDD05050500 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001818187FA5C3B8CBDBD0D4D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFAFCFFE2EDF99FB7CD1C1C1C0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000001B1B1B99AEBFD4D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFEFEFFD1DAE33E3E3E00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001D1D1D7B9BB4CACED1D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFC9D2DD2121210000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000343434A5B5 + C2CFD3D7BFCEDBC9D9E7D7E6F3E6F3FFECF5FFF0F4F9AEBDCD23232300000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000018181887A8C3A6C6E169B3F367B6FA77BEFC88C6FF + 9FD0FFB4CBE33939390000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000040404338C + D749A8F947A9FD54AFFF64B6FF74BDFF7EC0FF76ABDD05050500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000001F7DCD369FF948AAFF58B1FF69B8FF79BFFF + 78BAF96299CD0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003592E34DACFF5DB3FF6DBAFF7BBFFF6DAAE300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003890DD51AEFF62B5FF72BCFF7BBFFF + 6AA5DD0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003B8FD84C9CE3589FDE69A9E375B6F46299CD00000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003376B00000000000000000005788B6 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000006CC61A83DD247FCC00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000006DC71A83DD2686D71F6EB1 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFE1FDFFF0000FFFFE0078FFF0000FFFE + 000007FF0000FFF0000001FF0000FF80000000FF0000FF000000003F0000FF00 + 0000000F0000FE00000000070000F800000000070000F8000000000F0000FC00 + 000000070000FE00000000070000FF80000000070000FFC0000000070000FFE0 + 000000070000FFE0000000070000FFE0000000070000FFE0000000070000FFF0 + 000000070000FFF0000000030000FFF0000000070000FFF00000000F0000FFF0 + 0000003F0000FFF8000E00FF0000FFF8000F01FF0000FFF8000FD7FF0000FFF8 + 001FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC003FFFFF0000FFFC + 003FFFFF0000FFFE003FFFFF0000FFFE007FFFFF0000FFFE007FFFFF0000FFFE + 007FFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF + 01FFFFFF0000FFFF01FFFFFF0000FFFF81FFFFFF0000FFFFC3FFFFFF0000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000} + OldCreateOrder = False + OnHide = FormHide + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object BitBtnOk: TBitBtn + Left = 40 + Top = 168 + Width = 177 + Height = 25 + TabOrder = 0 + OnClick = BitBtnOkClick + Kind = bkOK + end + object BitBtnCancel: TBitBtn + Left = 256 + Top = 168 + Width = 177 + Height = 25 + TabOrder = 1 + OnClick = BitBtnCancelClick + Kind = bkCancel + end + object GroupBoxMode: TGroupBox + Left = 8 + Top = 8 + Width = 465 + Height = 145 + Caption = 'Network mode' + TabOrder = 2 + object LabelUDPPort: TLabel + Left = 148 + Top = 26 + Width = 22 + Height = 13 + Caption = 'Port:' + end + object LabelMulticastPort: TLabel + Left = 364 + Top = 54 + Width = 22 + Height = 13 + Caption = 'Port:' + Enabled = False + end + object LabelCSPort: TLabel + Left = 364 + Top = 82 + Width = 22 + Height = 13 + Caption = 'Port:' + Enabled = False + end + object LabelMulticastAddress: TLabel + Left = 139 + Top = 54 + Width = 41 + Height = 13 + Caption = 'Address:' + Enabled = False + end + object LabelCSAddress: TLabel + Left = 139 + Top = 82 + Width = 41 + Height = 13 + Caption = 'Address:' + Enabled = False + end + object LabelHTTPURL: TLabel + Left = 147 + Top = 110 + Width = 25 + Height = 13 + Caption = 'URL:' + Enabled = False + end + object RadioButtonUDP: TRadioButton + Left = 16 + Top = 24 + Width = 97 + Height = 17 + Caption = 'UDP' + Checked = True + TabOrder = 0 + TabStop = True + OnEnter = RadioButtonUDPEnter + end + object RadioButtonMulticast: TRadioButton + Left = 16 + Top = 52 + Width = 97 + Height = 17 + Caption = 'UDP Multicast' + TabOrder = 1 + OnEnter = RadioButtonMulticastEnter + end + object RadioButtonCS: TRadioButton + Left = 16 + Top = 80 + Width = 97 + Height = 17 + Caption = 'Channel Server' + TabOrder = 2 + OnEnter = RadioButtonCSEnter + end + object RadioButtonHTTP: TRadioButton + Left = 16 + Top = 108 + Width = 97 + Height = 17 + Caption = 'HTTP' + TabOrder = 3 + OnEnter = RadioButtonHTTPEnter + end + object ComboBoxMulticastAddress: TComboBox + Left = 184 + Top = 50 + Width = 161 + Height = 21 + Enabled = False + ItemHeight = 13 + TabOrder = 5 + end + object ComboBoxCSAddress: TComboBox + Left = 184 + Top = 78 + Width = 161 + Height = 21 + Enabled = False + ItemHeight = 13 + TabOrder = 7 + Text = 'vlcs' + Items.Strings = ( + 'vlcs') + end + object EditHTTPURL: TEdit + Left = 184 + Top = 106 + Width = 265 + Height = 21 + Enabled = False + TabOrder = 9 + end + object SpinEditUDPPort: TCSpinEdit + Left = 184 + Top = 21 + Width = 57 + Height = 22 + TabStop = True + MaxValue = 65535 + ParentColor = False + TabOrder = 4 + Value = 1234 + end + object SpinEditMulticastPort: TCSpinEdit + Left = 392 + Top = 49 + Width = 57 + Height = 22 + TabStop = True + Enabled = False + MaxValue = 65535 + ParentColor = False + TabOrder = 6 + Value = 1234 + end + object SpinEditCSPort: TCSpinEdit + Left = 392 + Top = 77 + Width = 57 + Height = 22 + TabStop = True + Enabled = False + MaxValue = 65535 + ParentColor = False + TabOrder = 8 + Value = 6010 + end + end +end diff --git a/modules/gui/win32/network.h b/modules/gui/win32/network.h new file mode 100644 index 0000000000..45c50572b4 --- /dev/null +++ b/modules/gui/win32/network.h @@ -0,0 +1,75 @@ +/***************************************************************************** + * network.h: the "network" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef networkH +#define networkH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include "CSPIN.h" +//--------------------------------------------------------------------------- + +#define NOT( var ) ( (var) ? false : true ) + +class TNetworkDlg : public TForm +{ +__published: // IDE-managed Components + TBitBtn *BitBtnOk; + TBitBtn *BitBtnCancel; + TGroupBox *GroupBoxMode; + TRadioButton *RadioButtonUDP; + TRadioButton *RadioButtonMulticast; + TRadioButton *RadioButtonCS; + TRadioButton *RadioButtonHTTP; + TLabel *LabelUDPPort; + TLabel *LabelMulticastPort; + TLabel *LabelCSPort; + TLabel *LabelMulticastAddress; + TComboBox *ComboBoxMulticastAddress; + TLabel *LabelCSAddress; + TComboBox *ComboBoxCSAddress; + TEdit *EditHTTPURL; + TLabel *LabelHTTPURL; + TCSpinEdit *SpinEditUDPPort; + TCSpinEdit *SpinEditMulticastPort; + TCSpinEdit *SpinEditCSPort; + void __fastcall FormShow( TObject *Sender ); + void __fastcall FormHide( TObject *Sender ); + void __fastcall BitBtnCancelClick( TObject *Sender ); + void __fastcall BitBtnOkClick( TObject *Sender ); + void __fastcall RadioButtonUDPEnter( TObject *Sender ); + void __fastcall RadioButtonMulticastEnter( TObject *Sender ); + void __fastcall RadioButtonCSEnter( TObject *Sender ); + void __fastcall RadioButtonHTTPEnter( TObject *Sender ); +private: // User declarations + int OldRadioValue; + void __fastcall ChangeEnabled( int i_selected ); +public: // User declarations + __fastcall TNetworkDlg( TComponent* Owner ); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/playlist.cpp b/modules/gui/win32/playlist.cpp new file mode 100644 index 0000000000..a3a2c4955f --- /dev/null +++ b/modules/gui/win32/playlist.cpp @@ -0,0 +1,387 @@ +/***************************************************************************** + * playlist.cpp: Interface for the playlist dialog + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include +#include + +#include "playlist.h" +#include "win32_common.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + +//--------------------------------------------------------------------------- +__fastcall TPlaylistDlg::TPlaylistDlg( TComponent* Owner ) + : TForm( Owner ) +{ + Icon = p_intfGlobal->p_sys->p_window->Icon; +} +//--------------------------------------------------------------------------- +char * __fastcall TPlaylistDlg::rindex( char *s, char c ) +{ + char *ref = s; + + s = s + strlen( s ) - 2; + while( ( s > ref ) && ( *s != c ) ) + { + s--; + } + if( *s == c ) + { + return( s ); + } + else + { + return( NULL ); + } +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Event handlers + ****************************************************************************/ +void __fastcall TPlaylistDlg::FormShow( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuPlaylist->Checked = true; + p_intfGlobal->p_sys->p_window->PopupPlaylist->Checked = true; + p_intfGlobal->p_sys->p_window->ToolButtonPlaylist->Down = true; +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::FormHide( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuPlaylist->Checked = false; + p_intfGlobal->p_sys->p_window->PopupPlaylist->Checked = false; + p_intfGlobal->p_sys->p_window->ToolButtonPlaylist->Down = false; +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::BitBtnOkClick( TObject *Sender ) +{ + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::ListViewPlaylistDblClick( TObject *Sender ) +{ + TListItem *Item; + TListItem *ItemStart; + TItemStates Focused; + + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + /* search the selected item */ + if( ListViewPlaylist->SelCount > 0 ) + { + if( ListViewPlaylist->SelCount == 1 ) + { + Item = ListViewPlaylist->Selected; + } + else + { + Focused << isFocused; + ItemStart = ListViewPlaylist->Items->Item[0]; + + Item = ListViewPlaylist->GetNextItem( ItemStart, sdAll, Focused ); + } + + playlist_Goto( p_playlist, Item->Index - 1 ); + } + + vlc_object_release( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::ListViewPlaylistKeyDown( TObject *Sender, + WORD &Key, TShiftState Shift ) +{ + /* 'suppr' or 'backspace' */ + if( ( Key == VK_DELETE ) || ( Key == VK_BACK ) ) + { + MenuDeleteSelectedClick( Sender ); + } + + /* 'enter' */ + if( Key == VK_RETURN ) + { + PopupPlayClick( Sender ); + } +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::ListViewPlaylistCustomDrawItem( + TCustomListView *Sender, TListItem *Item, TCustomDrawState State, + bool &DefaultDraw) +{ + TRect Rect = Item->DisplayRect( drBounds ); + + /* set the background color */ + if( Item->Index == p_intfGlobal->p_sys->i_playing ) + { + Sender->Canvas->Brush->Color = clRed; + } + else + { + Sender->Canvas->Brush->Color = clWhite; + } + + Sender->Canvas->FillRect( Rect ); +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Menu callbacks + ****************************************************************************/ +void __fastcall TPlaylistDlg::MenuAddFileClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuOpenFileClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuAddDiscClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuOpenDiscClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuAddNetClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window->MenuNetworkStreamClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuAddUrlClick( TObject *Sender ) +{ + /* TODO */ +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuDeleteSelectedClick( TObject *Sender ) +{ +#if 0 /* PLAYLIST TARASS */ + /* user wants to delete a file in the queue */ + int i_pos; + playlist_t *p_playlist = p_intfGlobal->p_vlc->p_playlist; + + /* lock the struct */ + vlc_mutex_lock( &p_intfGlobal->change_lock ); + + /* delete the items from the last to the first */ + for( i_pos = p_playlist->i_size - 1; i_pos >= 0; i_pos-- ) + { + if( ListViewPlaylist->Items->Item[i_pos]->Selected ) + { + DeleteItem( i_pos ); + } + } + + /* Rebuild the ListView */ + UpdateGrid( p_playlist ); + + vlc_mutex_unlock( &p_intfGlobal->change_lock ); +#endif +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuDeleteAllClick( TObject *Sender ) +{ +#if 0 /* PLAYLIST TARASS */ + int i_pos; + playlist_t *p_playlist = p_intfGlobal->p_vlc->p_playlist; + + /* lock the struct */ + vlc_mutex_lock( &p_intfGlobal->change_lock ); + + /* delete the items from the last to the first */ + for( i_pos = p_playlist->i_size - 1; i_pos >= 0; i_pos-- ) + { + DeleteItem( i_pos ); + } + + /* Rebuild the ListView */ + UpdateGrid( p_playlist ); + + vlc_mutex_unlock( &p_intfGlobal->change_lock ); +#endif +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuSelectionInvertClick( TObject *Sender ) +{ +#if 0 /* PLAYLIST TARASS */ +#define NOT( var ) ( (var) ? false : true ) + int i_pos; + playlist_t *p_playlist = p_intfGlobal->p_vlc->p_playlist; + TListItems *Items = ListViewPlaylist->Items; + + /* delete the items from the last to the first */ + for( i_pos = p_playlist->i_size - 1; i_pos >= 0; i_pos-- ) + { + Items->Item[i_pos]->Selected = NOT( Items->Item[i_pos]->Selected ); + } +#undef NOT +#endif +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::MenuSelectionCropClick( TObject *Sender ) +{ + MenuSelectionInvertClick( Sender ); + MenuDeleteSelectedClick( Sender ); +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Popup callbacks + ****************************************************************************/ +void __fastcall TPlaylistDlg::PopupPlayClick( TObject *Sender ) +{ + ListViewPlaylistDblClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::PopupInvertSelectionClick( TObject *Sender ) +{ + MenuSelectionInvertClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::PopupCropSelectionClick( TObject *Sender ) +{ + MenuSelectionCropClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::PopupDeleteSelectedClick( TObject *Sender ) +{ + MenuDeleteSelectedClick( Sender ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::PopupDeleteAllClick( TObject *Sender ) +{ + MenuDeleteAllClick( Sender ); +} +//--------------------------------------------------------------------------- + + +/***************************************************************************** + * Useful functions, needed by the event handlers + ****************************************************************************/ +void __fastcall TPlaylistDlg::UpdateGrid( playlist_t * p_playlist ) +{ + int i_dummy; + char *FileName; + TListItem *Item; + + ListViewPlaylist->Items->BeginUpdate(); + + /* Clear the list... */ + ListViewPlaylist->Items->Clear(); + + /* ...and rebuild it */ + for( i_dummy = 0; i_dummy < p_playlist->i_size; i_dummy++ ) + { +#ifdef WIN32 + /* Position of the last '\' in the string */ + FileName = rindex( p_playlist->pp_items[i_dummy]->psz_name, '\\' ); +#else + /* Position of the last '/' in the string */ + FileName = rindex( p_playlist->pp_items[i_dummy]->psz_name, '/' ); +#endif + if( ( FileName == NULL ) || ( *(FileName + 1) == '\0' ) ) + { + FileName = p_playlist->pp_items[i_dummy]->psz_name; + } + else + { + /* Skip leading '\' or '/' */ + FileName++; + } + + Item = ListViewPlaylist->Items->Add(); + Item->Caption = FileName; + Item->SubItems->Add( "no info" ); + } + /* TODO: Set background color ? */ + + ListViewPlaylist->Items->EndUpdate(); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::Manage( intf_thread_t * p_intf ) +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + vlc_mutex_lock( &p_playlist->object_lock ); + + if( p_intf->p_sys->i_playing != p_playlist->i_index ) + { + p_intf->p_sys->i_playing = p_playlist->i_index; + + /* update the background color */ + UpdateGrid( p_playlist ); + } + + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::DeleteItem( int i_pos ) +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Delete( p_playlist, i_pos ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::Previous() +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Prev( p_playlist ); +} +//--------------------------------------------------------------------------- +void __fastcall TPlaylistDlg::Next() +{ + playlist_t * p_playlist = (playlist_t *) + vlc_object_find( p_intfGlobal, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + return; + } + + playlist_Next( p_playlist ); +} +//--------------------------------------------------------------------------- + diff --git a/modules/gui/win32/playlist.dfm b/modules/gui/win32/playlist.dfm new file mode 100644 index 0000000000..0e8c535f36 --- /dev/null +++ b/modules/gui/win32/playlist.dfm @@ -0,0 +1,133 @@ +object PlaylistDlg: TPlaylistDlg + Left = 447 + Top = 197 + Width = 335 + Height = 436 + Caption = 'Playlist' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Menu = MainMenuPlaylist + OldCreateOrder = False + OnHide = FormHide + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object BitBtnOk: TBitBtn + Left = 76 + Top = 356 + Width = 176 + Height = 25 + Anchors = [akBottom] + Caption = 'OK' + ModalResult = 1 + TabOrder = 0 + OnClick = BitBtnOkClick + end + object ListViewPlaylist: TListView + Left = 11 + Top = 10 + Width = 305 + Height = 331 + Anchors = [akTop, akBottom] + Columns = < + item + Caption = 'Filename' + Width = 200 + end + item + Alignment = taCenter + Caption = 'Duration' + Width = 100 + end> + HideSelection = False + MultiSelect = True + ReadOnly = True + RowSelect = True + PopupMenu = PopupMenuPlaylist + TabOrder = 1 + ViewStyle = vsReport + OnCustomDrawItem = ListViewPlaylistCustomDrawItem + OnDblClick = ListViewPlaylistDblClick + OnKeyDown = ListViewPlaylistKeyDown + end + object MainMenuPlaylist: TMainMenu + Left = 24 + Top = 352 + object MenuAdd: TMenuItem + Caption = '&Add' + object MenuAddFile: TMenuItem + Caption = '&File' + OnClick = MenuAddFileClick + end + object MenuAddDisc: TMenuItem + Caption = '&Disc' + OnClick = MenuAddDiscClick + end + object MenuAddNet: TMenuItem + Caption = '&Network' + OnClick = MenuAddNetClick + end + object MenuAddUrl: TMenuItem + Caption = '&Url' + Enabled = False + OnClick = MenuAddUrlClick + end + end + object MenuDelete: TMenuItem + Caption = '&Delete' + object MenuDeleteAll: TMenuItem + Caption = '&All' + OnClick = MenuDeleteAllClick + end + object MenuDeleteSelected: TMenuItem + Caption = '&Selected' + OnClick = MenuDeleteSelectedClick + end + end + object MenuSelection: TMenuItem + Caption = '&Selection' + object MenuSelectionCrop: TMenuItem + Caption = '&Crop' + OnClick = MenuSelectionCropClick + end + object MenuSelectionInvert: TMenuItem + Caption = '&Invert' + OnClick = MenuSelectionInvertClick + end + end + end + object PopupMenuPlaylist: TPopupMenu + Left = 272 + Top = 352 + object PopupPlay: TMenuItem + Caption = '&Play' + OnClick = PopupPlayClick + end + object N1: TMenuItem + Caption = '-' + end + object PopupInvertSelection: TMenuItem + Caption = '&Invert selection' + OnClick = PopupInvertSelectionClick + end + object PopupCropSelection: TMenuItem + Caption = '&Crop selection' + OnClick = PopupCropSelectionClick + end + object N2: TMenuItem + Caption = '-' + end + object PopupDeleteSelected: TMenuItem + Caption = '&Delete selected' + OnClick = PopupDeleteSelectedClick + end + object PopupDeleteAll: TMenuItem + Caption = 'Delete &all' + OnClick = PopupDeleteAllClick + end + end +end diff --git a/modules/gui/win32/playlist.h b/modules/gui/win32/playlist.h new file mode 100644 index 0000000000..d5fc114737 --- /dev/null +++ b/modules/gui/win32/playlist.h @@ -0,0 +1,93 @@ +/***************************************************************************** + * playlist.h: Interface for the playlist dialog + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef playlistH +#define playlistH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------- +class TPlaylistDlg : public TForm +{ +__published: // IDE-managed Components + TBitBtn *BitBtnOk; + TMainMenu *MainMenuPlaylist; + TMenuItem *MenuAdd; + TMenuItem *MenuAddFile; + TMenuItem *MenuAddDisc; + TMenuItem *MenuAddNet; + TMenuItem *MenuAddUrl; + TMenuItem *MenuDelete; + TMenuItem *MenuDeleteAll; + TMenuItem *MenuDeleteSelected; + TMenuItem *MenuSelection; + TMenuItem *MenuSelectionCrop; + TMenuItem *MenuSelectionInvert; + TListView *ListViewPlaylist; + TPopupMenu *PopupMenuPlaylist; + TMenuItem *PopupPlay; + TMenuItem *N1; + TMenuItem *PopupDeleteAll; + TMenuItem *PopupDeleteSelected; + TMenuItem *N2; + TMenuItem *PopupInvertSelection; + TMenuItem *PopupCropSelection; + void __fastcall FormShow( TObject *Sender ); + void __fastcall FormHide( TObject *Sender ); + void __fastcall BitBtnOkClick( TObject *Sender ); + void __fastcall ListViewPlaylistDblClick( TObject *Sender ); + void __fastcall ListViewPlaylistKeyDown( TObject *Sender, WORD &Key, + TShiftState Shift ); + void __fastcall ListViewPlaylistCustomDrawItem( TCustomListView *Sender, + TListItem *Item, TCustomDrawState State, bool &DefaultDraw ); + void __fastcall MenuAddFileClick( TObject *Sender ); + void __fastcall MenuAddDiscClick( TObject *Sender ); + void __fastcall MenuAddNetClick( TObject *Sender ); + void __fastcall MenuAddUrlClick( TObject *Sender ); + void __fastcall MenuDeleteSelectedClick( TObject *Sender ); + void __fastcall MenuDeleteAllClick( TObject *Sender ); + void __fastcall MenuSelectionInvertClick( TObject *Sender ); + void __fastcall MenuSelectionCropClick( TObject *Sender ); + void __fastcall PopupPlayClick( TObject *Sender ); + void __fastcall PopupInvertSelectionClick( TObject *Sender ); + void __fastcall PopupCropSelectionClick( TObject *Sender ); + void __fastcall PopupDeleteSelectedClick( TObject *Sender ); + void __fastcall PopupDeleteAllClick( TObject *Sender ); +private: // User declarations + char * __fastcall rindex( char *s, char c ); +public: // User declarations + __fastcall TPlaylistDlg( TComponent* Owner ); + void __fastcall UpdateGrid( playlist_t * p_playlist ); + void __fastcall Manage( intf_thread_t * p_intf ); + void __fastcall DeleteItem( int i_pos ); + void __fastcall Previous(); + void __fastcall Next(); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/preferences.cpp b/modules/gui/win32/preferences.cpp new file mode 100644 index 0000000000..8cceece5d3 --- /dev/null +++ b/modules/gui/win32/preferences.cpp @@ -0,0 +1,560 @@ +/***************************************************************************** + * preferences.cpp: the "Preferences" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 +#pragma hdrstop + +#include /* malloc(), free() */ +#include /* strcmp */ + +#include +#include + +#include "preferences.h" +#include "win32_common.h" + +//--------------------------------------------------------------------------- +//#pragma package(smart_init) +#pragma link "CSPIN" +#pragma resource "*.dfm" + +extern intf_thread_t *p_intfGlobal; + + +/**************************************************************************** + * Functions to help components creation + ****************************************************************************/ +__fastcall TGroupBoxPref::TGroupBoxPref( TComponent* Owner, + module_config_t *p_config_arg ) : TGroupBox( Owner ) +{ + p_config = p_config_arg; + Caption = p_config->psz_text; +} +//--------------------------------------------------------------------------- +TListView * __fastcall TGroupBoxPref::CreateListView( TWinControl *Parent, + int Left, int Width, int Top, int Height, TViewStyle ViewStyle ) +{ + TListView *ListView = new TListView( Parent ); + ListView->Parent = Parent; + ListView->ViewStyle = ViewStyle; + ListView->Left = Left; + ListView->Width = Width; + ListView->Top = Top; + ListView->Height = Height; + return ListView; +} +//--------------------------------------------------------------------------- +TButton * __fastcall TGroupBoxPref::CreateButton( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption ) +{ + TButton *Button = new TButton( Parent ); + Button->Parent = Parent; + Button->Left = Left; + Button->Width = Width; + Button->Top = Top; + Button->Height = Height; + Button->Caption = Caption; + return Button; +} +//--------------------------------------------------------------------------- +TCheckBox * __fastcall TGroupBoxPref::CreateCheckBox( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption ) +{ + TCheckBox *CheckBox = new TCheckBox( Parent ); + CheckBox->Parent = Parent; + CheckBox->Left = Left; + CheckBox->Width = Width; + CheckBox->Top = Top; + CheckBox->Height = Height; + CheckBox->Caption = Caption; + return CheckBox; +} +//--------------------------------------------------------------------------- +TLabel * __fastcall TGroupBoxPref::CreateLabel( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption, + bool WordWrap ) +{ + TLabel *Label = new TLabel( Parent ); + Label->Parent = Parent; + Label->Caption = Caption; + Label->Left = Left; + Label->Width = Width; + Label->Top = Top; + Label->Height = Height; + Label->WordWrap = WordWrap; + return Label; +} +//--------------------------------------------------------------------------- +TEdit * __fastcall TGroupBoxPref::CreateEdit( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Text ) +{ + TEdit *Edit = new TEdit( Parent ); + Edit->Parent = Parent; + Edit->Left = Left; + Edit->Width = Width; + Edit->Top = Top; + Edit->Height = Height; + Edit->Text = Text; + return Edit; +} +//--------------------------------------------------------------------------- +TCSpinEdit * __fastcall TGroupBoxPref::CreateSpinEdit( TWinControl *Parent, + int Left, int Width, int Top, int Height, + long Min, long Max, long Value ) +{ + TCSpinEdit *SpinEdit = new TCSpinEdit( Parent ); + SpinEdit->Parent = Parent; + SpinEdit->Left = Left; + SpinEdit->Width = Width; + SpinEdit->Top = Top; + SpinEdit->Height = Height; + SpinEdit->MinValue = Min; + SpinEdit->MaxValue = Max; + SpinEdit->Value = Value; + return SpinEdit; +} +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxPref::UpdateChanges() +{ +} + + +/**************************************************************************** + * GroupBox for module management + ****************************************************************************/ +__fastcall TGroupBoxPlugin::TGroupBoxPlugin( TComponent* Owner, + module_config_t *p_config ) : TGroupBoxPref( Owner, p_config ) +{ + /* init listview */ + ListView = CreateListView( this, 16, 164, 24, 160, vsReport ); + ListView->ReadOnly = true; + ListView->Columns->Add(); + ListView->Columns->Items[0]->Width = 160; + ListView->Columns->Items[0]->Caption = "Name";//p_config->psz_text; + ListView->OnSelectItem = ListViewSelectItem; + + /* init description label */ + LabelDesc = CreateLabel( this, 230, 225, 50, 52, + p_config->psz_longtext, true ); + + /* init hint label */ + LabelHint = CreateLabel( this, 230, 225, 135, 13, "", false ); + + /* init configure button */ + ButtonConfig = CreateButton( this, 16, 70, 192, 25, "Configure" ); + ButtonConfig->Enabled = false; + ButtonConfig->OnClick = ButtonConfigClick; + + /* init select button */ + ButtonSelect = CreateButton( this, 110, 70, 192, 25, "Select" ); + ButtonSelect->OnClick = ButtonSelectClick; + + /* init 'Selected' label */ + LabelSelected = CreateLabel( this, 230, 45, 198, 13, "Selected", false ); + + /* init 'Selected' edit */ + Edit = CreateEdit( this, 280, 164, 194, 21, "" ); + vlc_mutex_lock( p_config->p_lock ); + Edit->Text = p_config->psz_value ? p_config->psz_value : ""; + vlc_mutex_unlock( p_config->p_lock ); + + Height = 233; +}; +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxPlugin::ListViewSelectItem( TObject *Sender, + TListItem *Item, bool Selected ) +{ + module_t *p_module; + AnsiString Name; + + Name = Item->Caption; + if( Name != "" ) + { + /* look for module 'Name' */ + for( p_module = p_intfGlobal->p_vlc->p_module_bank->first ; + p_module != NULL ; + p_module = p_module->next ) + { + if( strcmp( p_module->psz_object_name, Name.c_str() ) == 0 ) + { + ModuleSelected = p_module; + LabelHint->Caption = p_module->psz_longname ? + p_module->psz_longname : ""; + ButtonConfig->Enabled = p_module->i_config_items ? true : false; + + break; + } + } + } +} +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxPlugin::ButtonSelectClick( TObject *Sender ) +{ + if( !ModuleSelected ) return; + Edit->Text = ModuleSelected->psz_object_name; +} +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxPlugin::ButtonConfigClick( TObject *Sender ) +{ + p_intfGlobal->p_sys->p_window-> + CreatePreferences( ModuleSelected->psz_object_name ); +} +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxPlugin::UpdateChanges() +{ + /* XXX: Necessary, since c_str() returns only a temporary pointer... */ + free( p_config->psz_value ); + p_config->psz_value = (char *)malloc( Edit->Text.Length() + 1 ); + strcpy( p_config->psz_value, Edit->Text.c_str() ); +} + + +/**************************************************************************** + * GroupBox for string management + ****************************************************************************/ +__fastcall TGroupBoxString::TGroupBoxString( TComponent* Owner, + module_config_t *p_config ) : TGroupBoxPref( Owner, p_config ) +{ + /* init description label */ + LabelDesc = CreateLabel( this, 230, 225, 24, 26, + p_config->psz_longtext, true ); + + /* init edit */ + Edit = CreateEdit( this, 16, 164, 24, 21, "" ); + vlc_mutex_lock( p_config->p_lock ); + Edit->Text = p_config->psz_value ? p_config->psz_value : ""; + vlc_mutex_unlock( p_config->p_lock ); + + /* vertical alignment */ + Height = LabelDesc->Height + 24; + LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4; + Edit->Top = Top + ( Height - Edit->Height ) / 2 + 4; +}; +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxString::UpdateChanges() +{ + /* XXX: Necessary, since c_str() returns only a temporary pointer... */ + free( p_config->psz_value ); + p_config->psz_value = (char *)malloc( Edit->Text.Length() + 1 ); + strcpy( p_config->psz_value, Edit->Text.c_str() ); +} + + +/**************************************************************************** + * GroupBox for integer management + ****************************************************************************/ +__fastcall TGroupBoxInteger::TGroupBoxInteger( TComponent* Owner, + module_config_t *p_config ) : TGroupBoxPref( Owner, p_config ) +{ + /* init description label */ + LabelDesc = CreateLabel( this, 230, 225, 19, 26, + p_config->psz_longtext, true ); + + /* init spinedit */ + SpinEdit = CreateSpinEdit( this, 16, 164, 24, 21, + -1, 100000, p_config->i_value ); + + /* vertical alignment */ + Height = LabelDesc->Height + 24; + LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4; + SpinEdit->Top = Top + ( Height - SpinEdit->Height ) / 2 + 4; +}; +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxInteger::UpdateChanges() +{ + /* Warning: we're casting from long to int */ + p_config->i_value = (int)SpinEdit->Value; +} + + +/**************************************************************************** + * GroupBox for boolean management + ****************************************************************************/ +__fastcall TGroupBoxBool::TGroupBoxBool( TComponent* Owner, + module_config_t *p_config ) : TGroupBoxPref( Owner, p_config ) +{ + /* init description label */ + LabelDesc = CreateLabel( this, 230, 225, 19, 26, + p_config->psz_longtext, true ); + + /* init checkbox */ + CheckBox = CreateCheckBox( this, 16, 184, 28, 17, p_config->psz_text ); + CheckBox->Checked = p_config->i_value; + + /* vertical alignment */ + Height = LabelDesc->Height + 24; + LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4; + CheckBox->Top = Top + ( Height - CheckBox->Height ) / 2 + 4; +}; +//--------------------------------------------------------------------------- +void __fastcall TGroupBoxBool::UpdateChanges() +{ + p_config->i_value = CheckBox->Checked ? 1 : 0; +} + + +/**************************************************************************** + * Callbacks for the dialog + ****************************************************************************/ +//--------------------------------------------------------------------------- +__fastcall TPreferencesDlg::TPreferencesDlg( TComponent* Owner ) + : TForm( Owner ) +{ + Icon = p_intfGlobal->p_sys->p_window->Icon; +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::FormClose( TObject *Sender, + TCloseAction &Action ) +{ + Action = caHide; +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::FormShow( TObject *Sender ) +{ +/* + p_intfGlobal->p_sys->p_window->MenuPreferences->Checked = true; + p_intfGlobal->p_sys->p_window->PopupPreferences->Checked = true; +*/ +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::FormHide( TObject *Sender ) +{ +/* + p_intfGlobal->p_sys->p_window->MenuPreferences->Checked = false; + p_intfGlobal->p_sys->p_window->PopupPreferences->Checked = false; +*/ +} + + +/**************************************************************************** + * CreateConfigDialog: dynamically creates the configuration dialog + * box from all the configuration data provided by the selected module. + ****************************************************************************/ +#define ADD_PANEL \ +{ \ + Panel = new TPanel( this ); \ + Panel->Parent = ScrollBox; \ + Panel->Caption = ""; \ + Panel->BevelOuter = bvNone; \ + Panel->Height = 12; \ +} + +void __fastcall TPreferencesDlg::CreateConfigDialog( char *psz_module_name ) +{ + module_t *p_module, *p_module_plugins; + module_config_t *p_item; + int i_pages, i_ctrl; + + TTabSheet *TabSheet; + TScrollBox *ScrollBox; + TPanel *Panel; + TGroupBoxPlugin *GroupBoxPlugin; + TGroupBoxString *GroupBoxString; + TGroupBoxInteger *GroupBoxInteger; + TGroupBoxBool *GroupBoxBool; + TListItem *ListItem; + + /* Look for the selected module */ + for( p_module = p_intfGlobal->p_vlc->p_module_bank->first ; p_module != NULL ; + p_module = p_module->next ) + { + if( psz_module_name + && !strcmp( psz_module_name, p_module->psz_object_name ) ) + { + break; + } + } + if( !p_module ) return; + + /* + * We found it, now we can start building its configuration interface + */ + + /* Enumerate config options and add corresponding config boxes */ + p_item = p_module->p_config; + do + { + switch( p_item->i_type ) + { + case CONFIG_HINT_CATEGORY: + + /* create a new tabsheet. */ + TabSheet = new TTabSheet( this ); + TabSheet->PageControl = PageControlPref; + TabSheet->Caption = p_item->psz_text; + TabSheet->Visible = true; + + /* pack a scrollbox into the tabsheet */ + ScrollBox = new TScrollBox( this ); + ScrollBox->Parent = TabSheet; + ScrollBox->Align = alClient; + ScrollBox->BorderStyle = bsNone; + ScrollBox->HorzScrollBar->Tracking = true; + ScrollBox->VertScrollBar->Tracking = true; + + break; + + case CONFIG_ITEM_MODULE: + + /* add new groupbox for the config option */ + GroupBoxPlugin = new TGroupBoxPlugin( this, p_item ); + GroupBoxPlugin->Parent = ScrollBox; + + /* add panel as separator */ + ADD_PANEL; + +#if 0 /* FIXME */ + /* build a list of available plugins */ + for( p_module_plugins = p_intfGlobal->p_vlc->p_module_bank->first ; + p_module_plugins != NULL ; + p_module_plugins = p_module_plugins->next ) + { + if( p_module_plugins->i_capabilities & + ( 1 << p_item->i_value ) ) + { + ListItem = GroupBoxPlugin->ListView->Items->Add(); + ListItem->Caption = p_module_plugins->psz_object_name; + } + } +#endif + + break; + + case CONFIG_ITEM_FILE: + + case CONFIG_ITEM_STRING: + + /* add new groupbox for the config option */ + GroupBoxString = new TGroupBoxString( this, p_item ); + GroupBoxString->Parent = ScrollBox; + + /* add panel as separator */ + ADD_PANEL; + + break; + + case CONFIG_ITEM_INTEGER: + + /* add new groupbox for the config option */ + GroupBoxInteger = new TGroupBoxInteger( this, p_item ); + GroupBoxInteger->Parent = ScrollBox; + + /* add panel as separator */ + ADD_PANEL; + + break; + + case CONFIG_ITEM_BOOL: + + /* add new groupbox for the config option */ + GroupBoxBool = new TGroupBoxBool( this, p_item ); + GroupBoxBool->Parent = ScrollBox; + + /* add panel as separator */ + ADD_PANEL; + + break; + } + + p_item++; + } + while( p_item->i_type != CONFIG_HINT_END ); + + /* Reorder groupboxes inside the tabsheets */ + for( i_pages = 0; i_pages < PageControlPref->PageCount; i_pages++ ) + { + /* get scrollbox from the tabsheet */ + ScrollBox = (TScrollBox *)PageControlPref->Pages[i_pages]->Controls[0]; + + for( i_ctrl = ScrollBox->ControlCount - 1; i_ctrl >= 0 ; i_ctrl-- ) + { + ScrollBox->Controls[i_ctrl]->Align = alTop; + } + } + + /* set active tabsheet + * FIXME: i don't know why, but both lines are necessary */ + PageControlPref->ActivePageIndex = 1; + PageControlPref->ActivePageIndex = 0; +} +#undef ADD_PANEL +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::ButtonOkClick( TObject *Sender ) +{ + ButtonApplyClick( Sender ); + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::ButtonApplyClick( TObject *Sender ) +{ + TScrollBox *ScrollBox; + TGroupBoxPref *GroupBox; + int i, j; + + for( i = 0; i < PageControlPref->PageCount; i++ ) + { + /* get scrollbox from the tabsheet */ + ScrollBox = (TScrollBox *)PageControlPref->Pages[i]->Controls[0]; + + for( j = 0; j < ScrollBox->ControlCount ; j++ ) + { + /* skip the panels */ + if( ScrollBox->Controls[j]->InheritsFrom( __classid( TGroupBoxPref ) ) ) + { + GroupBox = (TGroupBoxPref *)ScrollBox->Controls[j]; + GroupBox->UpdateChanges(); + SaveValue( GroupBox->p_config ); + } + } + } +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::ButtonSaveClick( TObject *Sender ) +{ + ButtonApplyClick( Sender ); + config_SaveConfigFile( p_intfGlobal, NULL ); +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::ButtonCancelClick( TObject *Sender ) +{ + Hide(); +} +//--------------------------------------------------------------------------- +void __fastcall TPreferencesDlg::SaveValue( module_config_t *p_config ) +{ + switch( p_config->i_type ) + { + case CONFIG_ITEM_STRING: + case CONFIG_ITEM_FILE: + case CONFIG_ITEM_MODULE: + config_PutPsz( p_intfGlobal, p_config->psz_name, + *p_config->psz_value ? p_config->psz_value : NULL ); + break; + case CONFIG_ITEM_INTEGER: + case CONFIG_ITEM_BOOL: + config_PutInt( p_intfGlobal, p_config->psz_name, + p_config->i_value ); + break; + } +} +//--------------------------------------------------------------------------- + diff --git a/modules/gui/win32/preferences.dfm b/modules/gui/win32/preferences.dfm new file mode 100644 index 0000000000..54dc0dad39 --- /dev/null +++ b/modules/gui/win32/preferences.dfm @@ -0,0 +1,294 @@ +object PreferencesDlg: TPreferencesDlg + Left = 309 + Top = 124 + Width = 522 + Height = 582 + Caption = 'Preferences' + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + Icon.Data = { + 0000010001003030000001001800A81C00001600000028000000300000006000 + 00000100180000000000001B0000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000069375900000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000120E0A4011253E0F18000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000F0B + 084143CA08070016430F08040800000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000003127291203174647E8464AE808010840E54039E6390B0C06 + 0E0A1C0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0070CD0079DD0079DD0070CD0000000000000000000C1008261D6E4647E54547 + E64748E105040039E6393AE53939E63936D33308030100000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000070CD0079DD0079DE007DE40088F9008CFF008CFF0088F9007CE302 + 6EC70B09124641DC4444DF4546E34446E54847E003040040E6403AEA3A3EE33E + 3CE33C39E639080F010801050000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0079DD0077D90070CB0078D8007BDC007BDC007BDC + 007BDC007BDC007BDD007EE32E232D0804084553F14250F34252ED4449DB4844 + DC4645E208010540E5401C78150D18053CE63C3AE63A39EA393CD83C241A2006 + 0402000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0079DD007ADF007BDE007BDC0072 + CC005188004877004876004876004876034976054A760B4D7731434221175B42 + 54EC4253EE4252F60B05104250F44252EB4546DA08010539E6392BAA2B080105 + 3CE63C39E7393AE63A39E93939E839081208181C080000000000000000000000 + 000000000000000000000000000000000000000070CD0079DD0079DD007CE300 + 88F90089F90075D2005188004877005188008CFF008CFF008CFF008CFF008CFF + 1092FF2099FF31A0FF1408294840DB4550E1464EEA0C060B0B05084654F64653 + F64453EF080E033AE63A2BAA2B03030339E33939DF3939E639080F083DDB3D24 + 9C24434B3B000000000000000000000000000000000000000000000000000000 + 0063B60085F3008BFE0088F9007FE90088F90080E8005CA0008CFF008CFF008C + FF008CFF008CFF008CFF008CFF048DFF1594FF259BFF35A2FF0C04103F38C754 + 5AF7505BF10C08100801084352F64652F44253F30813053AE63A39E639030403 + 1C521826A1250812010807032454131558150000000000000000000000000000 + 000000000000000000000000000000000000000070CD007CE30079DD00000000 + 7CE30089FA008CFF0089FA008CFF008CFF008CFF008CFF008CFF008CFF098FFF + 1996FF2A9DFF3AA4FF0804103A2AA34E58F74E58F40B0B120803054652F34548 + E64451F305130532CA323AE23A03070308070307040008040139E63939E43931 + B42F5E1347000000000000000000000000000000000000000000000000000000 + 0000000000000000000061B10000000079DD008CFF008CFF008CFF008CFF008C + FF008CFF008CFF008CFF008CFF0E91FF1E98FF2E9FFF3FA6FF040408382BAF4D + 5AEF555AF70F12250501050F04160804074250F3121A123AE93A39E239080803 + 0D2F08010401268C2539E7393DE63D3FE23E0804100000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 79DD008CFF008CFF008CFF008CFF008CFF008CFF008CFF008CFF028CFF1293FF + 239AFF33A1FF43A8FF0802083A2AA3565BF7555AF71714330501050104000801 + 07424FF12828203AEA3A39E639030703182F1008340801040139E7393DE83D39 + E939080400000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000070CD0088F9008CFF008CFF008CFF008C + FF008CFF008CFF008CFF078EFF1795FF279CFF38A3FF48AAFF0808005151F155 + 5AF30804030804000504050800082E358E0E0C1F1D192439E53940E640080400 + 2AA12739E63908020708010539E8393BE93B0804080000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000007CE3008CFF008CFF008CFF058EFD1D96F92398F8269AFA31A0FC42A8FF + 4FAEFF5CB3FF65B7FF0C08084F5AF14E57F50B04080804043639A54647E81C13 + 49363AA70804080F120835953439E7393EE63E39DF3939EA39081105308A2B3F + E73F080601000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000047BDB1D96F92398F82498F83BA0 + F399C1E1B1C9DDBCD4E7CBE0F3D9EDFFDCEEFFDEEFFFCDE8FF080808575BF750 + 58F624125A5057F34845DF4A41E0150E30C55734E3723EC56E33A23D27050105 + 39E43939E63939E6393CE63C14420C3BE03B192A090000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000004 + 04042D88D399C1E1B1C9DDB1C9DCB7CBDBCFD3D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFF9FCFF0C08085D61F15B61EF555AF64A4FE13937BB0E0A12DE74 + 39E1733CDE713CDF753AE67541C36B342C231F17141B3AE63A39E7393DE83D39 + E93939DE39000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000001818186893B8C3CCD2D5D5D6D5D5D6D5D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFFFFFFFFFFFF140C145C5EF668 + 63F75555EA10061CC3673FDF713A0C1104080403080105080007070407D56F36 + DE743EDE72401C200C29452939E63939E73939EA390000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000343434A2B4C2D5D5D6D6D6D6D6D6D6D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFFEFEFF20161C5C5EF6373EAE0E0413E2713DE1763CCD6A3C2A0D + 08A44B2CDE743EBD612F080401030403E1713CDE7239DE713AE1723C22201139 + C13341E641000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001B1B1B99AEBED5D5D6D5D5D6D5D5 + D6CFD3D7B8CBDBBFD5E7CEE2F3DCEFFFDFF0FFE2F1FFE9F4FF10100C3639A46E + 4540DE7239DE713DE1713C07000784261CDE7639E3743E0812001F0407D86E36 + E3753EE57540E57541DE763CDE733DD26637493C387E2F7B0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00001B1B1B99AEBFCED3D7B7CBDBB1C9DD99C1E140A2F339A2FA49AAFC59B2FF + 66B8FF74BEFF92CBFFD9ECFF0F0402C66531DE7139E2733D854B1E0A01084D11 + 0DE3733EE1723CDF713ADF753AE1763C1D0A08290708E57140E1763CDE733DC7 + 6B34080408000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000001818187FA5C399C1E13BA0F32498 + F81D96F91091FD1C97FF2C9EFF3CA5FF4DACFF5DB3FF71BBFF8DC8FF9FD0FF08 + 0400080406B95C2EDE7239070B070803014D1615DE723CDE7540E5714030090D + 0504003A120FE67541DE75390808044A0C290000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000707071778C81C92F3058EFD008CFF008CFF1092FF2099FF31A0FF41A7FF + 51AEFF62B5FF72BCFF7BBFFF7BBBF96E9FCD0808080806041D0508E571403E22 + 0C200708080405070407070007080303B05F31DE723967301908010500000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000007CE3008CFF008C + FF048DFF1594FF259BFF35A2FF46A9FF56B0FF66B7FF77BEFF7BBFFF6DAAE300 + 0000000000000000000000080401200C088D4024E17141E57140DF713ADE713E + DE76390801070000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000079DD008CFF008CFF098FFF1996FF2A9DFF3AA4FF4AABFF + 5BB2FF6BB9FF7BBFFF7BBFFF6AA5DD0000000000000000000000000000001D1A + 0C1A0F08110903441912E57140623B1E08020300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000079DD008CFF008C + FF0E91FF1E98FF2E9FFF3FA6FF4FADFF5FB4FF70BBFF7BBFFF78BAF96299CD00 + 00000000000000000000000000000000000000003914100000005A2411000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000070CD0088F9078EFD2C9CF940A3F850ACFA60B4FC70BCFF + 7DC2FF87C6FF7EC0FF6DAAE30000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000707071A85DD40A2 + F3A0C3E1B7CBDDC6D8E7D4E5F3E2F1FFE5F2FFD9ECFF9FD0FF7AACDD05050500 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001818187FA5C3B8CBDBD0D4D7D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFAFCFFE2EDF99FB7CD1C1C1C0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000001B1B1B99AEBFD4D5 + D6D6D6D6D6D6D6E3E3E3F1F1F1FFFFFFFFFFFFFEFEFFD1DAE33E3E3E00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000001D1D1D7B9BB4CACED1D6D6D6D5D5D6E2E2E3F0F0F1FEFEFF + FEFEFFFEFEFFC9D2DD2121210000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000343434A5B5 + C2CFD3D7BFCEDBC9D9E7D7E6F3E6F3FFECF5FFF0F4F9AEBDCD23232300000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000018181887A8C3A6C6E169B3F367B6FA77BEFC88C6FF + 9FD0FFB4CBE33939390000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000040404338C + D749A8F947A9FD54AFFF64B6FF74BDFF7EC0FF76ABDD05050500000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000001F7DCD369FF948AAFF58B1FF69B8FF79BFFF + 78BAF96299CD0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003592E34DACFF5DB3FF6DBAFF7BBFFF6DAAE300000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003890DD51AEFF62B5FF72BCFF7BBFFF + 6AA5DD0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 003B8FD84C9CE3589FDE69A9E375B6F46299CD00000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000003376B00000000000000000005788B6 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000006CC61A83DD247FCC00000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000006DC71A83DD2686D71F6EB1 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFE1FDFFF0000FFFFE0078FFF0000FFFE + 000007FF0000FFF0000001FF0000FF80000000FF0000FF000000003F0000FF00 + 0000000F0000FE00000000070000F800000000070000F8000000000F0000FC00 + 000000070000FE00000000070000FF80000000070000FFC0000000070000FFE0 + 000000070000FFE0000000070000FFE0000000070000FFE0000000070000FFF0 + 000000070000FFF0000000030000FFF0000000070000FFF00000000F0000FFF0 + 0000003F0000FFF8000E00FF0000FFF8000F01FF0000FFF8000FD7FF0000FFF8 + 001FFFFF0000FFFC001FFFFF0000FFFC001FFFFF0000FFFC003FFFFF0000FFFC + 003FFFFF0000FFFE003FFFFF0000FFFE007FFFFF0000FFFE007FFFFF0000FFFE + 007FFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF00FFFFFF0000FFFF + 01FFFFFF0000FFFF01FFFFFF0000FFFF81FFFFFF0000FFFFC3FFFFFF0000FFFF + FFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000FFFFFFFFFFFF0000} + OldCreateOrder = False + Position = poDefaultPosOnly + OnClose = FormClose + OnHide = FormHide + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object PageControlPref: TPageControl + Left = 8 + Top = 8 + Width = 497 + Height = 497 + TabOrder = 1 + end + object ButtonApply: TButton + Left = 146 + Top = 520 + Width = 105 + Height = 25 + Caption = 'Apply' + TabOrder = 0 + OnClick = ButtonApplyClick + end + object ButtonSave: TButton + Left = 265 + Top = 520 + Width = 105 + Height = 25 + Caption = 'Save' + TabOrder = 2 + OnClick = ButtonSaveClick + end + object ButtonOK: TButton + Left = 26 + Top = 520 + Width = 105 + Height = 25 + Caption = 'OK' + TabOrder = 3 + OnClick = ButtonOkClick + end + object ButtonCancel: TButton + Left = 386 + Top = 520 + Width = 105 + Height = 25 + Caption = 'Cancel' + TabOrder = 4 + OnClick = ButtonCancelClick + end +end diff --git a/modules/gui/win32/preferences.h b/modules/gui/win32/preferences.h new file mode 100644 index 0000000000..9dbb92db17 --- /dev/null +++ b/modules/gui/win32/preferences.h @@ -0,0 +1,125 @@ +/***************************************************************************** + * preferences.h: the "Preferences" dialog box + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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. + *****************************************************************************/ + +#ifndef preferencesH +#define preferencesH +//--------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include +#include +#include "CSPIN.h" +//--------------------------------------------------------------------------- +class TGroupBoxPref : public TGroupBox +{ +public: + __fastcall TGroupBoxPref( TComponent* Owner, module_config_t *p_config_arg ); + module_config_t *p_config; + virtual void __fastcall UpdateChanges(); + TListView * __fastcall CreateListView( TWinControl *Parent, + int Left, int Width, int Top, int Height, TViewStyle ViewStyle ); + TButton * __fastcall CreateButton( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption ); + TCheckBox * __fastcall CreateCheckBox( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption ); + TLabel * __fastcall CreateLabel( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Caption, + bool WordWrap ); + TEdit * __fastcall CreateEdit( TWinControl *Parent, + int Left, int Width, int Top, int Height, AnsiString Text ); + TCSpinEdit * __fastcall CreateSpinEdit( TWinControl *Parent, + int Left, int Width, int Top, int Height, + long Min, long Max, long Value ); +}; +//--------------------------------------------------------------------------- +class TGroupBoxPlugin : public TGroupBoxPref +{ +public: + __fastcall TGroupBoxPlugin( TComponent* Owner, module_config_t *p_config ); + TListView *ListView; + TButton *ButtonConfig; + TButton *ButtonSelect; + TLabel *LabelDesc; + TLabel *LabelHint; + TLabel *LabelSelected; + TEdit *Edit; + module_t *ModuleSelected; + void __fastcall UpdateChanges(); + void __fastcall ListViewSelectItem( TObject *Sender, TListItem *Item, + bool Selected ); + void __fastcall ButtonSelectClick( TObject *Sender ); + void __fastcall ButtonConfigClick( TObject *Sender ); +}; +//--------------------------------------------------------------------------- +class TGroupBoxString : public TGroupBoxPref +{ +public: + __fastcall TGroupBoxString( TComponent* Owner, module_config_t *p_config ); + TLabel *LabelDesc; + TEdit *Edit; + void __fastcall UpdateChanges(); +}; +//--------------------------------------------------------------------------- +class TGroupBoxInteger : public TGroupBoxPref +{ +public: + __fastcall TGroupBoxInteger( TComponent* Owner, module_config_t *p_config ); + TLabel *LabelDesc; + TCSpinEdit *SpinEdit; + void __fastcall UpdateChanges(); +}; +//--------------------------------------------------------------------------- +class TGroupBoxBool : public TGroupBoxPref +{ +public: + __fastcall TGroupBoxBool( TComponent* Owner, module_config_t *p_config ); + TLabel *LabelDesc; + TCheckBox *CheckBox; + void __fastcall UpdateChanges(); +}; +//--------------------------------------------------------------------------- +class TPreferencesDlg : public TForm +{ +__published: // IDE-managed Components + TPageControl *PageControlPref; + TButton *ButtonApply; + TButton *ButtonSave; + TButton *ButtonOK; + TButton *ButtonCancel; + void __fastcall FormShow( TObject *Sender ); + void __fastcall FormHide( TObject *Sender ); + void __fastcall ButtonOkClick( TObject *Sender ); + void __fastcall ButtonApplyClick( TObject *Sender ); + void __fastcall ButtonSaveClick( TObject *Sender ); + void __fastcall ButtonCancelClick( TObject *Sender ); + void __fastcall FormClose( TObject *Sender, TCloseAction &Action ); +private: // User declarations +public: // User declarations + __fastcall TPreferencesDlg( TComponent* Owner ); + void __fastcall CreateConfigDialog( char *psz_module_name ); + void __fastcall SaveValue( module_config_t *p_config ); +}; +//--------------------------------------------------------------------------- +#endif diff --git a/modules/gui/win32/win32.bpr b/modules/gui/win32/win32.bpr new file mode 100644 index 0000000000..bcfb1014ef --- /dev/null +++ b/modules/gui/win32/win32.bpr @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=0 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1036 +CodePage=1252 + +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.0 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= + +[HistoryLists\hlIncludePath] +Count1= +Item0=..\win32;..\..\win32;$(BCB)\include;$(BCB)\include\vcl;..\..\include;..\..\src\misc + +[HistoryLists\hlLibraryPath] +Count=1 +Item0=..\win32;..\..\win32;$(BCB)\lib\obj;$(BCB)\lib + +[HistoryLists\hlDebugSourcePath] +Count=1 +Item0=$(BCB)\source\vcl + +[HistoryLists\hlConditionals] +Count=1 +Item0=_DEBUG + +[Debugging] +DebugSourceDirs=$(BCB)\source\vcl + +[Parameters] +RunParams= +HostApplication= +RemoteHost= +RemotePath= +RemoteDebug=0 + +[Compiler] +ShowInfoMsgs=0 +LinkDebugVcl=0 +LinkCGLIB=0 + +[Language] +ActiveLang= +ProjectLang= +RootDir= + + diff --git a/modules/gui/win32/win32.cpp b/modules/gui/win32/win32.cpp new file mode 100644 index 0000000000..e3480b3c84 --- /dev/null +++ b/modules/gui/win32/win32.cpp @@ -0,0 +1,57 @@ +/***************************************************************************** + * win32.cpp : Win32 interface plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teulière + * + * 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 /* malloc(), free() */ +#include + +#include + +#include "win32.h" /* Borland specific */ + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(Open) ( vlc_object_t * ); +void E_(Close) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +#define MAX_LINES_TEXT N_("maximum number of lines in the log window") +#define MAX_LINES_LONGTEXT N_( \ + "You can set the maximum number of lines that the log window will display."\ + " Enter -1 if you want to keep all messages." ) + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_integer( "intfwin-max-lines", 500, NULL, MAX_LINES_TEXT, MAX_LINES_LONGTEXT ); + set_description( _("Win32 interface module") ); + set_capability( "interface", 100 ); + set_callbacks( E_(Open), E_(Close) ); + add_shortcut( "win" ); + add_shortcut( "win32" ); +vlc_module_end(); + diff --git a/modules/gui/win32/win32.h b/modules/gui/win32/win32.h new file mode 100644 index 0000000000..3724dbd7bd --- /dev/null +++ b/modules/gui/win32/win32.h @@ -0,0 +1,27 @@ +/***************************************************************************** + * win32.h : Win32 interface plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teulière + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * Exported interface functions. + *****************************************************************************/ +extern "C" __declspec(dllexport) + int __VLC_SYMBOL( vlc_entry ) ( module_t *p_module ); diff --git a/modules/gui/win32/win32_common.h b/modules/gui/win32/win32_common.h new file mode 100644 index 0000000000..63f956c1d3 --- /dev/null +++ b/modules/gui/win32/win32_common.h @@ -0,0 +1,91 @@ +/***************************************************************************** + * win32_common.h: private win32 interface description + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * + * Authors: Olivier Teuliere + * + * 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 "about.h" +#include "disc.h" +#include "mainframe.h" +#include "menu.h" +#include "messages.h" +#include "network.h" +#include "playlist.h" +#include "preferences.h" + +VLC_DECLARE_STRUCT(es_descriptor_t) + +/***************************************************************************** + * The TrackBar is graduated from 0 to SLIDER_MAX_VALUE. + * SLIDER_MAX_VALUE is set to the higher acceptable value (2^31 - 1), in order + * to obtain the best precision in date calculation + *****************************************************************************/ +#define SLIDER_MAX_VALUE 2147483647 + +/***************************************************************************** + * intf_sys_t: description and status of Win32 interface + *****************************************************************************/ +struct intf_sys_t +{ + /* special actions */ + vlc_bool_t b_playing; + vlc_bool_t b_popup_changed; /* display popup menu ? */ + vlc_bool_t b_slider_free; /* slider status */ + + /* menus handlers */ + vlc_bool_t b_program_update; /* do we need to update programs + menu */ + vlc_bool_t b_title_update; /* do we need to update title menus */ + vlc_bool_t b_chapter_update; /* do we need to update chapter + menus */ + vlc_bool_t b_audio_update; /* do we need to update audio menus */ + vlc_bool_t b_spu_update; /* do we need to update spu menus */ + + /* windows and widgets */ + TMainFrameDlg * p_window; /* main window */ + TPlaylistDlg * p_playwin; /* playlist */ + TPopupMenu * p_popup; /* popup menu */ + TAboutDlg * p_about; /* about window */ + TDiscDlg * p_disc; /* disc selection window */ + TNetworkDlg * p_network; /* network stream window */ + TPreferencesDlg * p_preferences; /* preferences window */ + + /* The slider */ + off_t OldValue; /* previous value */ + + /* The messages window */ + TMessagesDlg * p_messages; /* messages window */ + msg_subscription_t* p_sub; /* message bank subscription */ + + /* Playlist management */ + int i_playing; /* playlist selected item */ + + /* The window labels for DVD mode */ + TLabel * p_label_title; + TLabel * p_label_chapter; + int i_part; /* current chapter */ + + /* Language information */ + es_descriptor_t * p_audio_es_old; + es_descriptor_t * p_spu_es_old; + + /* The input thread */ + input_thread_t * p_input; +}; + diff --git a/modules/misc/dummy/.cvsignore b/modules/misc/dummy/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/misc/dummy/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/misc/dummy/Makefile b/modules/misc/dummy/Makefile new file mode 100644 index 0000000000..307e1c7569 --- /dev/null +++ b/modules/misc/dummy/Makefile @@ -0,0 +1 @@ +dummy_SOURCES = dummy.c aout.c vout.c interface.c input.c decoder.c diff --git a/modules/misc/dummy/aout.c b/modules/misc/dummy/aout.c new file mode 100644 index 0000000000..20c45aa9d4 --- /dev/null +++ b/modules/misc/dummy/aout.c @@ -0,0 +1,76 @@ +/***************************************************************************** + * aout_dummy.c : dummy audio output plugin + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: aout.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 + +#include +#include + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int SetFormat ( aout_thread_t * ); +static int GetBufInfo ( aout_thread_t *, int ); +static void Play ( aout_thread_t *, byte_t *, int ); + +/***************************************************************************** + * OpenAudio: opens a dummy audio device + *****************************************************************************/ +int E_(OpenAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = Play; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * SetFormat: pretends to set the dsp output format + *****************************************************************************/ +static int SetFormat( aout_thread_t *p_aout ) +{ + return( 0 ); +} + +/***************************************************************************** + * GetBufInfo: returns available bytes in buffer + *****************************************************************************/ +static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +{ + return( sizeof(s16) * i_buffer_limit + 1 ); /* value big enough to sleep */ +} + +/***************************************************************************** + * Play: pretends to play a sound + *****************************************************************************/ +static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) +{ + ; +} + diff --git a/modules/misc/dummy/decoder.c b/modules/misc/dummy/decoder.c new file mode 100644 index 0000000000..444469f5d8 --- /dev/null +++ b/modules/misc/dummy/decoder.c @@ -0,0 +1,119 @@ +/***************************************************************************** + * dec_dummy.c: dummy decoder plugin for vlc. + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: decoder.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include + +#ifdef HAVE_UNISTD_H +# include /* write(), close() */ +#endif + +#include /* open() */ +#include +#include + +#include /* sprintf() */ + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Run ( decoder_fifo_t * ); + +/***************************************************************************** + * OpenDecoder: probe the decoder and return score + ***************************************************************************** + * Always returns 0 because we are the dummy decoder! + *****************************************************************************/ +int E_(OpenDecoder) ( vlc_object_t *p_this ) +{ + ((decoder_fifo_t*)p_this)->pf_run = Run; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Run: this function is called just after the thread is created + *****************************************************************************/ +static int Run ( decoder_fifo_t *p_fifo ) +{ + bit_stream_t bit_stream; + mtime_t last_date = mdate(); + size_t i_bytes = 0; + + char psz_file[100]; + int i_fd; + + sprintf( psz_file, "stream.%i", p_fifo->i_object_id ); + i_fd = open( psz_file, O_WRONLY | O_CREAT | O_TRUNC, 00644 ); + + if( i_fd == -1 ) + { + msg_Err( p_fifo, "cannot create `%s'", psz_file ); + p_fifo->b_error = 1; + DecoderError( p_fifo ); + return -1; + } + + msg_Dbg( p_fifo, "dumping stream to file `%s'", psz_file ); + + InitBitstream( &bit_stream, p_fifo, NULL, NULL ); + + while( !p_fifo->b_die && !p_fifo->b_error ) + { + byte_t byte; + + byte = GetBits( &bit_stream, 8 ); + i_bytes++; + + write( i_fd, &byte, 1 ); + + if( mdate() < last_date + 2000000 ) + { + continue; + } + + msg_Dbg( p_fifo, "dumped %i bytes", i_bytes ); + + i_bytes = 0; + last_date = mdate(); + } + + if( i_bytes ) + { + msg_Dbg( p_fifo, "dumped %i bytes", i_bytes ); + } + + close( i_fd ); + + if( p_fifo->b_error ) + { + DecoderError( p_fifo ); + return -1; + } + + return 0; +} + diff --git a/modules/misc/dummy/dummy.c b/modules/misc/dummy/dummy.c new file mode 100644 index 0000000000..8ccd5d470f --- /dev/null +++ b/modules/misc/dummy/dummy.c @@ -0,0 +1,67 @@ +/***************************************************************************** + * dummy.c : dummy plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: dummy.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include + +#include + +#include "dummy.h" + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define CHROMA_TEXT N_("dummy image chroma format") +#define CHROMA_LONGTEXT N_( \ + "Force the dummy video output to create images using a specific chroma " \ + "format instead of trying to improve performances by using the most " \ + "efficient one.") + +vlc_module_begin(); + set_description( _("dummy functions module") ); + add_shortcut( "vlc" ); + add_submodule(); + set_capability( "interface", 0 ); + set_callbacks( E_(OpenIntf), NULL ); + add_submodule(); + set_capability( "access", 0 ); + set_callbacks( E_(OpenAccess), NULL ); + add_submodule(); + set_capability( "demux", 0 ); + set_callbacks( E_(OpenDemux), E_(CloseDemux) ); + add_submodule(); + set_capability( "decoder", 0 ); + set_callbacks( E_(OpenDecoder), NULL ); + add_submodule(); + set_capability( "audio output", 0 ); + set_callbacks( E_(OpenAudio), NULL ); + add_submodule(); + set_capability( "video output", 0 ); + set_callbacks( E_(OpenVideo), NULL ); + add_category_hint( N_("Video"), NULL ); + add_string( "dummy-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT ); +vlc_module_end(); + diff --git a/modules/misc/dummy/dummy.h b/modules/misc/dummy/dummy.h new file mode 100644 index 0000000000..0cbd902aa5 --- /dev/null +++ b/modules/misc/dummy/dummy.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * dummy.h : dummy plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001, 2002 VideoLAN + * $Id: dummy.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t * ); + +int E_(OpenAccess) ( vlc_object_t * ); + +int E_(OpenDemux) ( vlc_object_t * ); +void E_(CloseDemux) ( vlc_object_t * ); + +int E_(OpenDecoder) ( vlc_object_t * ); + +int E_(OpenAudio) ( vlc_object_t * ); + +int E_(OpenVideo) ( vlc_object_t * ); + diff --git a/modules/misc/dummy/input.c b/modules/misc/dummy/input.c new file mode 100644 index 0000000000..7d6cfa8235 --- /dev/null +++ b/modules/misc/dummy/input.c @@ -0,0 +1,197 @@ +/***************************************************************************** + * input_dummy.c: dummy input plugin, to manage "vlc:***" special options + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: input.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include +#include +#include + +#include +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Demux ( input_thread_t * ); + +/***************************************************************************** + * access_sys_t: private input data + *****************************************************************************/ +struct demux_sys_t +{ + /* The real command */ + int i_command; + + /* Used for the pause command */ + mtime_t expiration; +}; + +#define COMMAND_NOP 0 +#define COMMAND_QUIT 1 +#define COMMAND_LOOP 2 +#define COMMAND_PAUSE 3 + +/***************************************************************************** + * OpenAccess: open the target, ie. do nothing + *****************************************************************************/ +int E_(OpenAccess) ( vlc_object_t *p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + + p_input->stream.i_method = INPUT_METHOD_NONE; + + /* Force dummy demux plug-in */ + p_input->psz_demux = "vlc"; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * OpenDemux: initialize the target, ie. parse the command + *****************************************************************************/ +int E_(OpenDemux) ( vlc_object_t *p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + char * psz_name = p_input->psz_name; + int i_len = strlen( psz_name ); + struct demux_sys_t * p_method; + int i_arg; + + p_input->stream.b_seekable = 0; + p_input->pf_demux = Demux; + p_input->pf_rewind = NULL; + + p_method = malloc( sizeof( struct demux_sys_t ) ); + if( p_method == NULL ) + { + msg_Err( p_input, "out of memory" ); + return -1; + } + + p_input->p_demux_data = p_method; + p_input->stream.p_demux_data = NULL; + + /* Check for a "vlc:nop" command */ + if( i_len == 3 && !strncasecmp( psz_name, "nop", 3 ) ) + { + msg_Info( p_input, "command `nop'" ); + p_method->i_command = COMMAND_NOP; + return 0; + } + + /* Check for a "vlc:quit" command */ + if( i_len == 4 && !strncasecmp( psz_name, "quit", 4 ) ) + { + msg_Info( p_input, "command `quit'" ); + p_method->i_command = COMMAND_QUIT; + return 0; + } + + /* Check for a "vlc:loop" command */ + if( i_len == 4 && !strncasecmp( psz_name, "loop", 4 ) ) + { + msg_Info( p_input, "command `loop'" ); + p_method->i_command = COMMAND_LOOP; + return 0; + } + + /* Check for a "vlc:pause:***" command */ + if( i_len > 6 && !strncasecmp( psz_name, "pause:", 6 ) ) + { + i_arg = atoi( psz_name + 6 ); + msg_Info( p_input, "command `pause %i'", i_arg ); + p_method->i_command = COMMAND_PAUSE; + p_method->expiration = mdate() + (mtime_t)i_arg * (mtime_t)1000000; + return 0; + } + + msg_Err( p_input, "unknown command `%s'", psz_name ); + free( p_input->p_demux_data ); + p_input->b_error = 1; + + return -1; +} + +/***************************************************************************** + * CloseDemux: initialize the target, ie. parse the command + *****************************************************************************/ +void E_(CloseDemux) ( vlc_object_t *p_this ) +{ + input_thread_t *p_input = (input_thread_t *)p_this; + + free( p_input->p_demux_data ); +} + +/***************************************************************************** + * Demux: do what the command says + *****************************************************************************/ +static int Demux( input_thread_t *p_input ) +{ + struct demux_sys_t * p_method = p_input->p_demux_data; + playlist_t *p_playlist; + + p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT ); + + if( p_playlist == NULL ) + { + msg_Err( p_input, "we are not attached to a playlist" ); + p_input->b_error = 1; + return 1; + } + + switch( p_method->i_command ) + { + case COMMAND_QUIT: + p_input->p_vlc->b_die = 1; + break; + + case COMMAND_LOOP: + playlist_Goto( p_playlist, 0 ); + break; + + case COMMAND_PAUSE: + if( mdate() < p_method->expiration ) + { + msleep( 10000 ); + } + else + { + p_input->b_eof = 1; + } + break; + + case COMMAND_NOP: + default: + p_input->b_eof = 1; + break; + } + + vlc_object_release( p_playlist ); + + return 1; +} + diff --git a/modules/misc/dummy/interface.c b/modules/misc/dummy/interface.c new file mode 100644 index 0000000000..d6c8848c73 --- /dev/null +++ b/modules/misc/dummy/interface.c @@ -0,0 +1,69 @@ +/***************************************************************************** + * intf_dummy.c: dummy interface plugin + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: interface.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include + +#include +#include + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static void Run ( intf_thread_t * ); + +/***************************************************************************** + * Open: initialize dummy interface + *****************************************************************************/ +int E_(OpenIntf) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*) p_this; +#ifdef WIN32 + AllocConsole(); + freopen( "CONOUT$", "w", stdout ); + freopen( "CONOUT$", "w", stderr ); + freopen( "CONIN$", "r", stdin ); + msg_Info( p_intf, VERSION_MESSAGE ); + msg_Info( p_intf, _("\nUsing the dummy interface plugin...") ); +#endif + + p_intf->pf_run = Run; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Run: main loop + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + while( !p_intf->b_die ) + { + /* Wait a bit */ + msleep( INTF_IDLE_SLEEP ); + } +} + diff --git a/modules/misc/dummy/vout.c b/modules/misc/dummy/vout.c new file mode 100644 index 0000000000..000ebe55c9 --- /dev/null +++ b/modules/misc/dummy/vout.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * vout_dummy.c: Dummy video output display method for testing purposes + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: vout.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include + +#define DUMMY_WIDTH 16 +#define DUMMY_HEIGHT 16 +#define DUMMY_MAX_DIRECTBUFFERS 10 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * OpenVideo: activates dummy video thread output method + ***************************************************************************** + * This function initializes a dummy vout method. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = Render; + p_vout->pf_display = Display; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Init: initialize dummy video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index, i_chroma; + char *psz_chroma; + picture_t *p_pic; + vlc_bool_t b_chroma = 0; + + psz_chroma = config_GetPsz( p_vout, "dummy-chroma" ); + if( psz_chroma ) + { + if( strlen( psz_chroma ) >= 4 ) + { + i_chroma = (unsigned char)psz_chroma[0] << 0; + i_chroma |= (unsigned char)psz_chroma[1] << 8; + i_chroma |= (unsigned char)psz_chroma[2] << 16; + i_chroma |= (unsigned char)psz_chroma[3] << 24; + + b_chroma = 1; + } + + free( psz_chroma ); + } + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + if( b_chroma ) + { + msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)", + i_chroma, (char*)&i_chroma ); + p_vout->output.i_chroma = i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + } + else + { + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); + p_vout->output.i_rmask = 0xf800; + p_vout->output.i_gmask = 0x07e0; + p_vout->output.i_bmask = 0x001f; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + } + + /* Try to initialize DUMMY_MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < DUMMY_MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL ) + { + break; + } + + vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_width, + p_vout->output.i_height, + p_vout->output.i_chroma ); + + if( p_pic->i_planes == 0 ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * End: terminate dummy video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Manage: handle dummy events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + return( 0 ); +} + +/***************************************************************************** + * Render: render previously calculated output + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* No need to do anything, the fake direct buffers stay as they are */ +} + +/***************************************************************************** + * Display: displays previously rendered output + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* No need to do anything, the fake direct buffers stay as they are */ +} + diff --git a/modules/misc/logger/.cvsignore b/modules/misc/logger/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/misc/logger/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/misc/logger/Makefile b/modules/misc/logger/Makefile new file mode 100644 index 0000000000..35ed9d76c3 --- /dev/null +++ b/modules/misc/logger/Makefile @@ -0,0 +1 @@ +logger_SOURCES = logger.c diff --git a/modules/misc/logger/logger.c b/modules/misc/logger/logger.c new file mode 100644 index 0000000000..c17d6ac9ee --- /dev/null +++ b/modules/misc/logger/logger.c @@ -0,0 +1,299 @@ +/***************************************************************************** + * logger.c : file logging plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: logger.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include + +#include +#include + +#define MODE_TEXT 0 +#define MODE_HTML 1 + +#define LOG_FILE "vlc-log.txt" +#define LOG_STRING( msg, file ) fwrite( msg, strlen( msg ), 1, file ); + +#define TEXT_HEADER "-- logger module started --\n" +#define TEXT_FOOTER "-- logger module stopped --\n" + +#define HTML_HEADER \ + "\n" \ + " \n" \ + " vlc log\n" \ + " \n" \ + " \n" \ + "
\n" \
+    "      -- logger module started --\n"
+#define HTML_FOOTER \
+    "      -- logger module stopped --\n" \
+    "    
\n" \ + " \n" \ + "\n" + +/***************************************************************************** + * intf_sys_t: description and status of log interface + *****************************************************************************/ +struct intf_sys_t +{ + int i_mode; + + FILE * p_file; /* The log file */ + msg_subscription_t *p_sub; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); +static void Run ( intf_thread_t * ); + +static void FlushQueue ( msg_subscription_t *, FILE *, int ); +static void TextPrint ( const msg_item_t *, FILE * ); +static void HtmlPrint ( const msg_item_t *, FILE * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "logfile", NULL, NULL, N_("log filename"), N_("Specify the log filename.") ); + add_string( "logmode", NULL, NULL, N_("log format"), N_("Specify the log format. Available choices are \"text\" (default) and \"html\"") ); + set_description( _("file logging interface module") ); + set_capability( "interface", 0 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Open: initialize and create stuff + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + char *psz_mode, *psz_file; + +#ifdef WIN32 + AllocConsole(); + freopen( "CONOUT$", "w", stdout ); + freopen( "CONOUT$", "w", stderr ); + freopen( "CONIN$", "r", stdin ); + msg_Info( p_intf, VERSION_MESSAGE ); + msg_Info( p_intf, _("\nUsing the logger interface plugin...") ); +#endif + + /* Allocate instance and initialize some members */ + p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return -1; + } + + psz_mode = config_GetPsz( p_intf, "logmode" ); + if( psz_mode ) + { + if( !strcmp( psz_mode, "text" ) ) + { + p_intf->p_sys->i_mode = MODE_TEXT; + } + else if( !strcmp( psz_mode, "html" ) ) + { + p_intf->p_sys->i_mode = MODE_HTML; + } + else + { + msg_Err( p_intf, "invalid log mode `%s', using `text'", psz_mode ); + p_intf->p_sys->i_mode = MODE_TEXT; + } + + free( psz_mode ); + } + else + { + msg_Warn( p_intf, "no log mode specified, using `text'" ); + p_intf->p_sys->i_mode = MODE_TEXT; + } + + psz_file = config_GetPsz( p_intf, "logfile" ); + if( !psz_file ) + { + switch( p_intf->p_sys->i_mode ) + { + case MODE_HTML: + psz_file = strdup( "vlc-log.html" ); + break; + case MODE_TEXT: + default: + psz_file = strdup( "vlc-log.txt" ); + break; + } + + msg_Warn( p_intf, "no log filename provided, using `%s'", psz_file ); + } + + /* Open the log file and remove any buffering for the stream */ + msg_Dbg( p_intf, "opening logfile `%s'", psz_file ); + p_intf->p_sys->p_file = fopen( psz_file, "wt" ); + setvbuf( p_intf->p_sys->p_file, NULL, _IONBF, 0 ); + + p_intf->p_sys->p_sub = msg_Subscribe( p_intf ); + + if( p_intf->p_sys->p_file == NULL ) + { + msg_Err( p_intf, "error opening logfile `%s'", psz_file ); + free( p_intf->p_sys ); + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + free( psz_file ); + return -1; + } + + free( psz_file ); + + switch( p_intf->p_sys->i_mode ) + { + case MODE_HTML: + LOG_STRING( HTML_HEADER, p_intf->p_sys->p_file ); + break; + case MODE_TEXT: + default: + LOG_STRING( TEXT_HEADER, p_intf->p_sys->p_file ); + break; + } + + return 0; +} + +/***************************************************************************** + * Close: destroy interface stuff + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + /* Flush the queue and unsubscribe from the message queue */ + FlushQueue( p_intf->p_sys->p_sub, p_intf->p_sys->p_file, + p_intf->p_sys->i_mode ); + msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub ); + + switch( p_intf->p_sys->i_mode ) + { + case MODE_HTML: + LOG_STRING( HTML_FOOTER, p_intf->p_sys->p_file ); + break; + case MODE_TEXT: + default: + LOG_STRING( TEXT_FOOTER, p_intf->p_sys->p_file ); + break; + } + + /* Close the log file */ + fclose( p_intf->p_sys->p_file ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: rc thread + ***************************************************************************** + * This part of the interface is in a separate thread so that we can call + * exec() from within it without annoying the rest of the program. + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + while( !p_intf->b_die ) + { + FlushQueue( p_intf->p_sys->p_sub, p_intf->p_sys->p_file, + p_intf->p_sys->i_mode ); + + msleep( INTF_IDLE_SLEEP ); + } +} + +/***************************************************************************** + * FlushQueue: flush the message queue into the log file + *****************************************************************************/ +static void FlushQueue( msg_subscription_t *p_sub, FILE *p_file, int i_mode ) +{ + int i_start, i_stop; + + vlc_mutex_lock( p_sub->p_lock ); + i_stop = *p_sub->pi_stop; + vlc_mutex_unlock( p_sub->p_lock ); + + if( p_sub->i_start != i_stop ) + { + /* Append all messages to log file */ + for( i_start = p_sub->i_start; + i_start != i_stop; + i_start = (i_start+1) % VLC_MSG_QSIZE ) + { + switch( i_mode ) + { + case MODE_HTML: + HtmlPrint( &p_sub->p_msg[i_start], p_file ); + break; + case MODE_TEXT: + default: + TextPrint( &p_sub->p_msg[i_start], p_file ); + break; + } + } + + vlc_mutex_lock( p_sub->p_lock ); + p_sub->i_start = i_start; + vlc_mutex_unlock( p_sub->p_lock ); + } +} + +static const char *ppsz_type[4] = { ": ", " error: ", + " warning: ", " debug: " }; + +static void TextPrint( const msg_item_t *p_msg, FILE *p_file ) +{ + LOG_STRING( p_msg->psz_module, p_file ); + LOG_STRING( ppsz_type[p_msg->i_type], p_file ); + LOG_STRING( p_msg->psz_msg, p_file ); + LOG_STRING( "\n", p_file ); +} + +static void HtmlPrint( const msg_item_t *p_msg, FILE *p_file ) +{ + static const char *ppsz_color[4] = { "", + "", + "", + "" }; + + LOG_STRING( p_msg->psz_module, p_file ); + LOG_STRING( ppsz_type[p_msg->i_type], p_file ); + LOG_STRING( ppsz_color[p_msg->i_type], p_file ); + LOG_STRING( p_msg->psz_msg, p_file ); + LOG_STRING( "\n", p_file ); +} + diff --git a/modules/misc/memcpy/.cvsignore b/modules/misc/memcpy/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/misc/memcpy/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/misc/memcpy/Makefile b/modules/misc/memcpy/Makefile new file mode 100644 index 0000000000..ed9ee32d80 --- /dev/null +++ b/modules/misc/memcpy/Makefile @@ -0,0 +1,5 @@ +memcpy_SOURCES = memcpy.c +memcpymmx_SOURCES = memcpy.c +memcpymmxext_SOURCES = memcpy.c +memcpy3dn_SOURCES = memcpy.c +memcpyaltivec_SOURCES = memcpyaltivec.c diff --git a/modules/misc/memcpy/fastmemcpy.h b/modules/misc/memcpy/fastmemcpy.h new file mode 100644 index 0000000000..07068e98d7 --- /dev/null +++ b/modules/misc/memcpy/fastmemcpy.h @@ -0,0 +1,386 @@ +/***************************************************************************** + * fastmemcpy.h : fast memcpy routines + ***************************************************************************** + * $Id: fastmemcpy.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: various Linux kernel hackers + * various MPlayer hackers + * Nick Kurshev + * + * 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. + *****************************************************************************/ + +/* + aclib - advanced C library ;) + This file contains functions which improve and expand standard C-library +*/ + +#define BLOCK_SIZE 4096 +#define CONFUSION_FACTOR 0 +//Feel free to fine-tune the above 2, it might be possible to get some speedup with them :) + +//#define STATISTICS + +#ifndef HAVE_SSE2 +/* + P3 processor has only one SSE decoder so can execute only 1 sse insn per + cpu clock, but it has 3 mmx decoders (include load/store unit) + and executes 3 mmx insns per cpu clock. + P4 processor has some chances, but after reading: + http://www.emulators.com/pentium4.htm + I have doubts. Anyway SSE2 version of this code can be written better. +*/ +#undef HAVE_SSE +#endif + + +/* + This part of code was taken by me from Linux-2.4.3 and slightly modified +for MMX, MMX2, SSE instruction set. I have done it since linux uses page aligned +blocks but mplayer uses weakly ordered data and original sources can not +speedup them. Only using PREFETCHNTA and MOVNTQ together have effect! + +>From IA-32 Intel Architecture Software Developer's Manual Volume 1, + +Order Number 245470: +"10.4.6. Cacheability Control, Prefetch, and Memory Ordering Instructions" + +Data referenced by a program can be temporal (data will be used again) or +non-temporal (data will be referenced once and not reused in the immediate +future). To make efficient use of the processor's caches, it is generally +desirable to cache temporal data and not cache non-temporal data. Overloading +the processor's caches with non-temporal data is sometimes referred to as +"polluting the caches". +The non-temporal data is written to memory with Write-Combining semantics. + +The PREFETCHh instructions permits a program to load data into the processor +at a suggested cache level, so that it is closer to the processors load and +store unit when it is needed. If the data is already present in a level of +the cache hierarchy that is closer to the processor, the PREFETCHh instruction +will not result in any data movement. +But we should you PREFETCHNTA: Non-temporal data fetch data into location +close to the processor, minimizing cache pollution. + +The MOVNTQ (store quadword using non-temporal hint) instruction stores +packed integer data from an MMX register to memory, using a non-temporal hint. +The MOVNTPS (store packed single-precision floating-point values using +non-temporal hint) instruction stores packed floating-point data from an +XMM register to memory, using a non-temporal hint. + +The SFENCE (Store Fence) instruction controls write ordering by creating a +fence for memory store operations. This instruction guarantees that the results +of every store instruction that precedes the store fence in program order is +globally visible before any store instruction that follows the fence. The +SFENCE instruction provides an efficient way of ensuring ordering between +procedures that produce weakly-ordered data and procedures that consume that +data. + +If you have questions please contact with me: Nick Kurshev: nickols_k@mail.ru. +*/ + +// 3dnow memcpy support from kernel 2.4.2 +// by Pontscho/fresh!mindworkz + +#if defined( HAVE_MMX2 ) || defined( HAVE_3DNOW ) || defined( HAVE_MMX ) + +#undef HAVE_MMX1 +#if defined(HAVE_MMX) && !defined(HAVE_MMX2) && !defined(HAVE_3DNOW) && !defined(HAVE_SSE) +/* means: mmx v.1. Note: Since we added alignment of destinition it speedups + of memory copying on PentMMX, Celeron-1 and P2 upto 12% versus + standard (non MMX-optimized) version. + Note: on K6-2+ it speedups memory copying upto 25% and + on K7 and P3 about 500% (5 times). */ +#define HAVE_MMX1 +#endif + + +#undef HAVE_K6_2PLUS +#if !defined( HAVE_MMX2) && defined( HAVE_3DNOW) +#define HAVE_K6_2PLUS +#endif + +/* for small memory blocks (<256 bytes) this version is faster */ +#define small_memcpy(to,from,n)\ +{\ +register unsigned long int dummy;\ +__asm__ __volatile__(\ + "rep; movsb"\ + :"=&D"(to), "=&S"(from), "=&c"(dummy)\ +/* It's most portable way to notify compiler */\ +/* that edi, esi and ecx are clobbered in asm block. */\ +/* Thanks to A'rpi for hint!!! */\ + :"0" (to), "1" (from),"2" (n)\ + : "memory");\ +} + +#ifdef HAVE_SSE +#define MMREG_SIZE 16 +#else +#define MMREG_SIZE 64 //8 +#endif + +/* Small defines (for readability only) ;) */ +#ifdef HAVE_K6_2PLUS +#define PREFETCH "prefetch" +/* On K6 femms is faster of emms. On K7 femms is directly mapped on emms. */ +#define EMMS "femms" +#else +#define PREFETCH "prefetchnta" +#define EMMS "emms" +#endif + +#ifdef HAVE_MMX2 +#define MOVNTQ "movntq" +#else +#define MOVNTQ "movq" +#endif + +#ifdef HAVE_MMX1 +#define MIN_LEN 0x800 /* 2K blocks */ +#else +#define MIN_LEN 0x40 /* 64-byte blocks */ +#endif + +void * fast_memcpy(void * to, const void * from, size_t len) +{ + void *retval; + size_t i; + retval = to; +#ifdef STATISTICS + { + static int freq[33]; + static int t=0; + int i; + for(i=0; len>(1<= MIN_LEN) + { + register unsigned long int delta; + /* Align destinition to MMREG_SIZE -boundary */ + delta = ((unsigned long int)to)&(MMREG_SIZE-1); + if(delta) + { + delta=MMREG_SIZE-delta; + len -= delta; + small_memcpy(to, from, delta); + } + i = len >> 6; /* len/64 */ + len&=63; + /* + This algorithm is top effective when the code consequently + reads and writes blocks which have size of cache line. + Size of cache line is processor-dependent. + It will, however, be a minimum of 32 bytes on any processors. + It would be better to have a number of instructions which + perform reading and writing to be multiple to a number of + processor's decoders, but it's not always possible. + */ +#ifdef HAVE_SSE /* Only P3 (may be Cyrix3) */ + if(((unsigned long)from) & 15) + /* if SRC is misaligned */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + PREFETCH" 320(%0)\n" + "movups (%0), %%xmm0\n" + "movups 16(%0), %%xmm1\n" + "movups 32(%0), %%xmm2\n" + "movups 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + else + /* + Only if SRC is aligned on 16-byte boundary. + It allows to use movaps instead of movups, which required data + to be aligned or a general-protection exception (#GP) is generated. + */ + for(; i>0; i--) + { + __asm__ __volatile__ ( + PREFETCH" 320(%0)\n" + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } +#else + // Align destination at BLOCK_SIZE boundary + for(; ((int)to & (BLOCK_SIZE-1)) && i>0; i--) + { + __asm__ __volatile__ ( +#ifndef HAVE_MMX1 + PREFETCH" 320(%0)\n" +#endif + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + MOVNTQ" %%mm0, (%1)\n" + MOVNTQ" %%mm1, 8(%1)\n" + MOVNTQ" %%mm2, 16(%1)\n" + MOVNTQ" %%mm3, 24(%1)\n" + MOVNTQ" %%mm4, 32(%1)\n" + MOVNTQ" %%mm5, 40(%1)\n" + MOVNTQ" %%mm6, 48(%1)\n" + MOVNTQ" %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + +// printf(" %d %d\n", (int)from&1023, (int)to&1023); + // Pure Assembly cuz gcc is a bit unpredictable ;) +# if 0 + if(i>=BLOCK_SIZE/64) + asm volatile( + "xorl %%eax, %%eax \n\t" + ".balign 16 \n\t" + "1: \n\t" + "movl (%0, %%eax), %%ebx \n\t" + "movl 32(%0, %%eax), %%ebx \n\t" + "movl 64(%0, %%eax), %%ebx \n\t" + "movl 96(%0, %%eax), %%ebx \n\t" + "addl $128, %%eax \n\t" + "cmpl %3, %%eax \n\t" + " jb 1b \n\t" + + "xorl %%eax, %%eax \n\t" + + ".balign 16 \n\t" + "2: \n\t" + "movq (%0, %%eax), %%mm0\n" + "movq 8(%0, %%eax), %%mm1\n" + "movq 16(%0, %%eax), %%mm2\n" + "movq 24(%0, %%eax), %%mm3\n" + "movq 32(%0, %%eax), %%mm4\n" + "movq 40(%0, %%eax), %%mm5\n" + "movq 48(%0, %%eax), %%mm6\n" + "movq 56(%0, %%eax), %%mm7\n" + MOVNTQ" %%mm0, (%1, %%eax)\n" + MOVNTQ" %%mm1, 8(%1, %%eax)\n" + MOVNTQ" %%mm2, 16(%1, %%eax)\n" + MOVNTQ" %%mm3, 24(%1, %%eax)\n" + MOVNTQ" %%mm4, 32(%1, %%eax)\n" + MOVNTQ" %%mm5, 40(%1, %%eax)\n" + MOVNTQ" %%mm6, 48(%1, %%eax)\n" + MOVNTQ" %%mm7, 56(%1, %%eax)\n" + "addl $64, %%eax \n\t" + "cmpl %3, %%eax \n\t" + "jb 2b \n\t" + +#if CONFUSION_FACTOR > 0 + // a few percent speedup on out of order executing CPUs + "movl %5, %%eax \n\t" + "2: \n\t" + "movl (%0), %%ebx \n\t" + "movl (%0), %%ebx \n\t" + "movl (%0), %%ebx \n\t" + "movl (%0), %%ebx \n\t" + "decl %%eax \n\t" + " jnz 2b \n\t" +#endif + + "xorl %%eax, %%eax \n\t" + "addl %3, %0 \n\t" + "addl %3, %1 \n\t" + "subl %4, %2 \n\t" + "cmpl %4, %2 \n\t" + " jae 1b \n\t" + : "+r" (from), "+r" (to), "+r" (i) + : "r" (BLOCK_SIZE), "i" (BLOCK_SIZE/64), "i" (CONFUSION_FACTOR) + : "%eax", "%ebx" + ); +#endif + + for(; i>0; i--) + { + __asm__ __volatile__ ( +#ifndef HAVE_MMX1 + PREFETCH" 320(%0)\n" +#endif + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + MOVNTQ" %%mm0, (%1)\n" + MOVNTQ" %%mm1, 8(%1)\n" + MOVNTQ" %%mm2, 16(%1)\n" + MOVNTQ" %%mm3, 24(%1)\n" + MOVNTQ" %%mm4, 32(%1)\n" + MOVNTQ" %%mm5, 40(%1)\n" + MOVNTQ" %%mm6, 48(%1)\n" + MOVNTQ" %%mm7, 56(%1)\n" + :: "r" (from), "r" (to) : "memory"); + ((const unsigned char *)from)+=64; + ((unsigned char *)to)+=64; + } + +#endif /* Have SSE */ +#ifdef HAVE_MMX2 + /* since movntq is weakly-ordered, a "sfence" + * is needed to become ordered again. */ + __asm__ __volatile__ ("sfence":::"memory"); +#endif +#ifndef HAVE_SSE + /* enables to use FPU */ + __asm__ __volatile__ (EMMS:::"memory"); +#endif + } + /* + * Now do the tail of the block + */ + if(len) small_memcpy(to, from, len); + return retval; +} + + +#endif /* #if defined( HAVE_MMX2 ) || defined( HAVE_3DNOW ) || defined( HAVE_MMX ) */ diff --git a/modules/misc/memcpy/memcpy.c b/modules/misc/memcpy/memcpy.c new file mode 100644 index 0000000000..b70b8c746d --- /dev/null +++ b/modules/misc/memcpy/memcpy.c @@ -0,0 +1,103 @@ +/***************************************************************************** + * memcpy.c : classic memcpy module + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: memcpy.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include + +#include + +#undef HAVE_MMX +#undef HAVE_MMX2 +#undef HAVE_SSE +#undef HAVE_SSE2 +#undef HAVE_3DNOW +#undef HAVE_ALTIVEC + +#if defined( MODULE_NAME_IS_memcpy3dn ) +# define PRIORITY 100 +# define HAVE_3DNOW +#elif defined( MODULE_NAME_IS_memcpymmx ) +# define PRIORITY 100 +# define HAVE_MMX +#elif defined( MODULE_NAME_IS_memcpymmxext ) +# define PRIORITY 200 +# define HAVE_MMX2 +#else +# define PRIORITY 50 +#endif + +/***************************************************************************** + * Extern prototype + *****************************************************************************/ +#ifndef MODULE_NAME_IS_memcpy +# define fast_memcpy E_(fast_memcpy) +# include "fastmemcpy.h" +#endif + +/***************************************************************************** + * Module initializer + *****************************************************************************/ +static int Activate ( vlc_object_t *p_this ) +{ +#ifdef MODULE_NAME_IS_memcpy + p_this->p_vlc->pf_memcpy = memcpy; +#else + p_this->p_vlc->pf_memcpy = fast_memcpy; +#endif + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#ifdef MODULE_NAME_IS_memcpy + set_description( _("libc memcpy module") ); + add_shortcut( "c" ); + add_shortcut( "libc" ); +#elif defined( MODULE_NAME_IS_memcpy3dn ) + set_description( _("3D Now! memcpy module") ); + add_requirement( 3DNOW ); + add_shortcut( "3dn" ); + add_shortcut( "3dnow" ); + add_shortcut( "memcpy3dn" ); + add_shortcut( "memcpy3dnow" ); +#elif defined( MODULE_NAME_IS_memcpymmx ) + set_description( _("MMX memcpy module") ); + add_requirement( MMX ); + add_shortcut( "mmx" ); + add_shortcut( "memcpymmx" ); +#elif defined( MODULE_NAME_IS_memcpymmxext ) + set_description( _("MMX EXT memcpy module") ); + add_requirement( MMXEXT ); + add_shortcut( "mmxext" ); + add_shortcut( "memcpymmxext" ); +#endif + set_capability( "memcpy", PRIORITY ); + set_callbacks( Activate, NULL ); +vlc_module_end(); + diff --git a/modules/misc/memcpy/memcpyaltivec.c b/modules/misc/memcpy/memcpyaltivec.c new file mode 100644 index 0000000000..25d4ff28a1 --- /dev/null +++ b/modules/misc/memcpy/memcpyaltivec.c @@ -0,0 +1,212 @@ +/***************************************************************************** + * memcpyaltivec.c : AltiVec memcpy module + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: memcpyaltivec.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Christophe Massiot + * + * 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. + *****************************************************************************/ + +#ifndef __BUILD_ALTIVEC_ASM__ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static void * fast_memcpy ( void * to, const void * from, size_t len ); + +/***************************************************************************** + * Module initializer. + *****************************************************************************/ +static int Activate ( vlc_object_t *p_this ) +{ + p_this->p_vlc->pf_memcpy = fast_memcpy; + return VLC_SUCCESS; +} + +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin(); + set_description( _("AltiVec memcpy module") ); + set_capability( "memcpy", 100 ); + set_callbacks( Activate, NULL ); + add_shortcut( "altivec" ); +vlc_module_end(); + +#else +typedef unsigned long size_t; +#endif /* __BUILD_ALTIVEC_ASM__ */ + +#if defined(CAN_COMPILE_C_ALTIVEC) || defined( __BUILD_ALTIVEC_ASM__ ) + +#define vector_s16_t vector signed short +#define vector_u16_t vector unsigned short +#define vector_s8_t vector signed char +#define vector_u8_t vector unsigned char +#define vector_s32_t vector signed int +#define vector_u32_t vector unsigned int +#define MMREG_SIZE 16 + +#define SMALL_MEMCPY(to, from, len) \ +{ \ + unsigned char * end = to + len; \ + while( to < end ) \ + { \ + *to++ = *from++; \ + } \ +} + +static void * fast_memcpy( void * _to, const void * _from, size_t len ) +{ + void * retval = _to; + unsigned char * to = (unsigned char *)_to; + unsigned char * from = (unsigned char *)_from; + + if( len > 16 ) + { + /* Align destination to MMREG_SIZE -boundary */ + register unsigned long int delta; + + delta = ((unsigned long)to)&(MMREG_SIZE-1); + if( delta ) + { + delta = MMREG_SIZE - delta; + len -= delta; + SMALL_MEMCPY(to, from, delta); + } + + if( len & ~(MMREG_SIZE-1) ) + { + vector_u8_t perm, ref0, ref1, tmp; + + perm = vec_lvsl( 0, from ); + ref0 = vec_ld( 0, from ); + ref1 = vec_ld( 15, from ); + from += 16; + len -= 16; + tmp = vec_perm( ref0, ref1, perm ); + while( len & ~(MMREG_SIZE-1) ) + { + ref0 = vec_ld( 0, from ); + ref1 = vec_ld( 15, from ); + from += 16; + len -= 16; + vec_st( tmp, 0, to ); + tmp = vec_perm( ref0, ref1, perm ); + to += 16; + } + vec_st( tmp, 0, to ); + to += 16; + } + } + + if( len ) + { + SMALL_MEMCPY( to, from, len ); + } + + return retval; +} + +#endif + +#if !defined(CAN_COMPILE_C_ALTIVEC) && !defined(__BUILD_ALTIVEC_ASM__) + +/* + * The asm code is generated with: + * + * gcc-2.95 -fvec -D__BUILD_ALTIVEC_ASM__ -O9 -fomit-frame-pointer -mregnames -S * memcpyaltivec.c + * + * sed 's/.L/._L/g' memcpyaltivec.s | + * awk '{args=""; len=split ($2, arg, ","); + * for (i=1; i<=len; i++) { a=arg[i]; if (i + * Mathias Kretschmer + * + * 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 +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#ifdef WIN32 +# include +# include +# ifndef IN_MULTICAST +# define IN_MULTICAST(a) IN_CLASSD(a) +# endif +#else +# include /* hostent ... */ +# include +# include +# ifdef HAVE_ARPA_INET_H +# include /* inet_ntoa(), inet_aton() */ +# endif +#endif + +#include "network.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int NetOpen( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("IPv4 network abstraction layer") ); + set_capability( "network", 50 ); + set_callbacks( NetOpen, NULL ); +vlc_module_end(); + +/***************************************************************************** + * BuildAddr: utility function to build a struct sockaddr_in + *****************************************************************************/ +static int BuildAddr( struct sockaddr_in * p_socket, + const char * psz_address, int i_port ) +{ + /* Reset struct */ + memset( p_socket, 0, sizeof( struct sockaddr_in ) ); + p_socket->sin_family = AF_INET; /* family */ + p_socket->sin_port = htons( i_port ); + if( !*psz_address ) + { + p_socket->sin_addr.s_addr = INADDR_ANY; + } + else + { + struct hostent * p_hostent; + + /* Try to convert address directly from in_addr - this will work if + * psz_address is dotted decimal. */ +#ifdef HAVE_ARPA_INET_H + if( !inet_aton( psz_address, &p_socket->sin_addr ) ) +#else + if( (p_socket->sin_addr.s_addr = inet_addr( psz_address )) == -1 ) +#endif + { + /* We have a fqdn, try to find its address */ + if ( (p_hostent = gethostbyname( psz_address )) == NULL ) + { +//X intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_address ); + return( -1 ); + } + + /* Copy the first address of the host in the socket address */ + memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0], + p_hostent->h_length ); + } + } + return( 0 ); +} + +/***************************************************************************** + * OpenUDP: open a UDP socket + ***************************************************************************** + * psz_bind_addr, i_bind_port : address and port used for the bind() + * system call. If psz_bind_addr == "", the socket is bound to + * INADDR_ANY and broadcast reception is enabled. If i_bind_port == 0, + * 1234 is used. If psz_bind_addr is a multicast (class D) address, + * join the multicast group. + * psz_server_addr, i_server_port : address and port used for the connect() + * system call. It can avoid receiving packets from unauthorized IPs. + * Its use leads to great confusion and is currently discouraged. + * This function returns -1 in case of error. + *****************************************************************************/ +static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket ) +{ + char * psz_bind_addr = p_socket->psz_bind_addr; + int i_bind_port = p_socket->i_bind_port; + char * psz_server_addr = p_socket->psz_server_addr; + int i_server_port = p_socket->i_server_port; +#ifdef WIN32 + char * psz_bind_win32; /* WIN32 multicast kludge */ +#endif + + int i_handle, i_opt, i_opt_size; + struct sockaddr_in sock; + + if( i_bind_port == 0 ) + { + i_bind_port = config_GetInt( p_this, "server-port" ); + } + + /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0) + * protocol */ + if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ) + { + msg_Err( p_this, "cannot create socket (%s)", strerror(errno) ); + return( -1 ); + } + + /* We may want to reuse an already used socket */ + i_opt = 1; + if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR, + (void *) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Err( p_this, "cannot configure socket (SO_REUSEADDR: %s)", + strerror(errno)); + close( i_handle ); + return( -1 ); + } + + /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid + * packet loss caused by scheduling problems */ + i_opt = 0x80000; + if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, + (void *) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Warn( p_this, "cannot configure socket (SO_RCVBUF: %s)", + strerror(errno)); + } + + /* Check if we really got what we have asked for, because Linux, etc. + * will silently limit the max buffer size to net.core.rmem_max which + * is typically only 65535 bytes */ + i_opt = 0; + i_opt_size = sizeof( i_opt ); + if( getsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, + (void*) &i_opt, &i_opt_size ) == -1 ) + { + msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %s)", + strerror(errno) ); + } + else if( i_opt < 0x80000 ) + { + msg_Warn( p_this, "socket buffer size is 0x%x instead of 0x%x", + i_opt, 0x80000 ); + } + + + /* Build the local socket */ + +#ifdef WIN32 + /* Under Win32 and for the multicast, we bind on INADDR_ANY, + * so let's call BuildAddr with "" instead of psz_bind_addr */ + psz_bind_win32 = psz_bind_addr ; + + /* Check if this is a multicast socket */ + if (IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) ) + { + psz_bind_win32 = ""; + } + if ( BuildAddr( &sock, psz_bind_win32, i_bind_port ) == -1 ) +#else + if ( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 ) +#endif + { + close( i_handle ); + return( -1 ); + } + + /* Bind it */ + if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 ) + { + msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + + /* Allow broadcast reception if we bound on INADDR_ANY */ + if( !*psz_bind_addr ) + { + i_opt = 1; + if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, + (void*) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %s)", + strerror(errno) ); + } + } + + /* Join the multicast group if the socket is a multicast address */ +#ifndef IN_MULTICAST +# define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#ifndef WIN32 + if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) ) + { + struct ip_mreq imr; + imr.imr_interface.s_addr = INADDR_ANY; + imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr; +#else + if( IN_MULTICAST( ntohl(inet_addr(psz_bind_addr) ) ) ) + { + struct ip_mreq imr; + imr.imr_interface.s_addr = INADDR_ANY; + imr.imr_multiaddr.s_addr = inet_addr(psz_bind_addr); +#endif + if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char*)&imr, sizeof(struct ip_mreq) ) == -1 ) + { + msg_Err( p_this, "failed to join IP multicast group (%s)", + strerror(errno) ); + close( i_handle ); + return( -1 ); + } + } + + if( *psz_server_addr ) + { + /* Build socket for remote connection */ + if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 ) + { + msg_Err( p_this, "cannot build remote address" ); + close( i_handle ); + return( -1 ); + } + + /* Connect the socket */ + if( connect( i_handle, (struct sockaddr *) &sock, + sizeof( sock ) ) == (-1) ) + { + msg_Err( p_this, "cannot connect socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + } + + p_socket->i_handle = i_handle; + p_socket->i_mtu = config_GetInt( p_this, "mtu" ); + return( 0 ); +} + +/***************************************************************************** + * OpenTCP: open a TCP socket + ***************************************************************************** + * psz_server_addr, i_server_port : address and port used for the connect() + * system call. If i_server_port == 0, 80 is used. + * Other parameters are ignored. + * This function returns -1 in case of error. + *****************************************************************************/ +static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket ) +{ + char * psz_server_addr = p_socket->psz_server_addr; + int i_server_port = p_socket->i_server_port; + + int i_handle; + struct sockaddr_in sock; + + if( i_server_port == 0 ) + { + i_server_port = 80; + } + + /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0) + * protocol */ + if( (i_handle = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) + { + msg_Err( p_this, "cannot create socket (%s)", strerror(errno) ); + return( -1 ); + } + + /* Build remote address */ + if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 ) + { + close( i_handle ); + return( -1 ); + } + + /* Connect the socket */ + if( connect( i_handle, (struct sockaddr *) &sock, + sizeof( sock ) ) == (-1) ) + { + msg_Err( p_this, "cannot connect socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + + p_socket->i_handle = i_handle; + p_socket->i_mtu = 0; /* There is no MTU notion in TCP */ + + return( 0 ); +} + +/***************************************************************************** + * NetOpen: wrapper around OpenUDP and OpenTCP + *****************************************************************************/ +static int NetOpen( vlc_object_t * p_this ) +{ + network_socket_t * p_socket = p_this->p_private; + + if( p_socket->i_type == NETWORK_UDP ) + { + return OpenUDP( p_this, p_socket ); + } + else + { + return OpenTCP( p_this, p_socket ); + } +} diff --git a/modules/misc/network/ipv6.c b/modules/misc/network/ipv6.c new file mode 100644 index 0000000000..e2323bde6e --- /dev/null +++ b/modules/misc/network/ipv6.c @@ -0,0 +1,422 @@ +/***************************************************************************** + * ipv6.c: IPv6 network abstraction layer + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: ipv6.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Alexis Guillard + * Christophe Massiot + * Remco Poortinga + * + * 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 +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#ifdef WIN32 +# include +# include +#elif !defined( SYS_BEOS ) && !defined( SYS_NTO ) +# include /* hostent ... */ +# include +# include +# include +# ifdef HAVE_ARPA_INET_H +# include /* inet_ntoa(), inet_aton() */ +# endif +#endif + +#include "network.h" + +#if defined(WIN32) +static const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}}; +/* the following will have to be removed when w32api defines them */ +#ifndef IPPROTO_IPV6 +# define IPPROTO_IPV6 41 +#endif +#ifndef IPV6_JOIN_GROUP +# define IPV6_JOIN_GROUP 20 +#endif +#endif + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("IPv6 network abstraction layer") ); + set_capability( "network", 40 ); + set_callbacks( Open, NULL ); +vlc_module_end(); + +/***************************************************************************** + * BuildAddr: utility function to build a struct sockaddr_in6 + *****************************************************************************/ +static int BuildAddr( struct sockaddr_in6 * p_socket, + char * psz_address, int i_port ) +{ + char * psz_multicast_interface = ""; + +#if defined(WIN32) + /* Try to get getaddrinfo() and freeaddrinfo() from wship6.dll */ + typedef int (CALLBACK * GETADDRINFO) ( const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res ); + typedef void (CALLBACK * FREEADDRINFO) ( struct addrinfo FAR *ai ); + + struct addrinfo hints, *res; + GETADDRINFO _getaddrinfo = NULL; + FREEADDRINFO _freeaddrinfo = NULL; + + HINSTANCE wship6_dll = LoadLibrary("wship6.dll"); + if( wship6_dll ) + { + _getaddrinfo = (GETADDRINFO) GetProcAddress( wship6_dll, + "getaddrinfo" ); + _freeaddrinfo = (FREEADDRINFO) GetProcAddress( wship6_dll, + "freeaddrinfo" ); + } + if( !_getaddrinfo || !_freeaddrinfo ) + { +//X msg_Err( p_this, "no IPv6 stack installed" ); + if( wship6_dll ) FreeLibrary( wship6_dll ); + return( -1 ); + } +#endif + + /* Reset struct */ + memset( p_socket, 0, sizeof( struct sockaddr_in6 ) ); + p_socket->sin6_family = AF_INET6; /* family */ + p_socket->sin6_port = htons( i_port ); + if( !*psz_address ) + { + p_socket->sin6_addr = in6addr_any; + } + else if( psz_address[0] == '[' + && psz_address[strlen(psz_address) - 1] == ']' ) + { + psz_address++; + /* see if there is an interface name in there... */ + if( (psz_multicast_interface = strchr(psz_address, '%')) != NULL ) + { + *psz_multicast_interface = '\0'; + psz_multicast_interface++; +//X msg_Dbg( p_this, "Interface name specified: \"%s\"", +// psz_multicast_interface ); + /* now convert that interface name to an index */ +#if !defined( WIN32 ) + p_socket->sin6_scope_id = if_nametoindex(psz_multicast_interface); +#else + /* FIXME: for now we always use the default interface */ + p_socket->sin6_scope_id = 0; +//X msg_Warn( 3, "Using default interface. This has to be FIXED!"); +#endif +//X msg_Warn( p_this, " = #%i\n", p_socket->sin6_scope_id ); + } + psz_address[strlen(psz_address) - 1] = '\0' ; + +#if !defined( WIN32 ) + inet_pton(AF_INET6, psz_address, &p_socket->sin6_addr.s6_addr); + +#else + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + + if( _getaddrinfo( psz_address, NULL, &hints, &res ) ) + { + FreeLibrary( wship6_dll ); + return( -1 ); + } + memcpy( &p_socket->sin6_addr, + &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, + sizeof(struct in6_addr) ); + _freeaddrinfo( res ); + +#endif + } + else + { +#ifdef HAVE_GETHOSTBYNAME2 + struct hostent * p_hostent; + + /* We have a fqdn, try to find its address */ + if ( (p_hostent = gethostbyname2( psz_address, AF_INET6 )) == NULL ) + { +//X intf_ErrMsg( "ipv6 error: unknown host %s", psz_address ); + return( -1 ); + } + + /* Copy the first address of the host in the socket address */ + memcpy( &p_socket->sin6_addr, p_hostent->h_addr_list[0], + p_hostent->h_length ); + +#elif defined(WIN32) + if( _getaddrinfo( psz_address, NULL, &hints, &res ) ) + { + FreeLibrary( wship6_dll ); + return( -1 ); + } + memcpy( &p_socket->sin6_addr, + &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, + sizeof(struct in6_addr) ); + _freeaddrinfo( res ); + +#else +//X intf_ErrMsg( "ipv6 error: IPv6 address %s is invalid", psz_address ); + return( -1 ); +#endif + } + +#if defined(WIN32) + FreeLibrary( wship6_dll ); +#endif + + return( 0 ); +} + +/***************************************************************************** + * OpenUDP: open a UDP socket + ***************************************************************************** + * psz_bind_addr, i_bind_port : address and port used for the bind() + * system call. If psz_bind_addr == NULL, the socket is bound to + * in6addr_any and broadcast reception is enabled. If i_bind_port == 0, + * 1234 is used. If psz_bind_addr is a multicast (class D) address, + * join the multicast group. + * psz_server_addr, i_server_port : address and port used for the connect() + * system call. It can avoid receiving packets from unauthorized IPs. + * Its use leads to great confusion and is currently discouraged. + * This function returns -1 in case of error. + *****************************************************************************/ +static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket ) +{ + char * psz_bind_addr = p_socket->psz_bind_addr; + int i_bind_port = p_socket->i_bind_port; + char * psz_server_addr = p_socket->psz_server_addr; + int i_server_port = p_socket->i_server_port; + + int i_handle, i_opt, i_opt_size; + struct sockaddr_in6 sock; + + if( i_bind_port == 0 ) + { +//X i_bind_port = config_GetInt( "server-port" ); + } + + /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET6 domain, automatic (0) + * protocol */ + if( (i_handle = socket( AF_INET6, SOCK_DGRAM, 0 )) == -1 ) + { + msg_Err( p_this, "cannot create socket (%s)", strerror(errno) ); + return( -1 ); + } + + /* We may want to reuse an already used socket */ + i_opt = 1; + if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR, + (void *) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Err( p_this, "cannot configure socket (SO_REUSEADDR: %s)", + strerror(errno) ); + close( i_handle ); + return( -1 ); + } + + /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid + * packet loss caused by scheduling problems */ + i_opt = 0x80000; + if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, + (void *) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Warn( p_this, "cannot configure socket (SO_RCVBUF: %s)", + strerror(errno) ); + } + + /* Check if we really got what we have asked for, because Linux, etc. + * will silently limit the max buffer size to net.core.rmem_max which + * is typically only 65535 bytes */ + i_opt = 0; + i_opt_size = sizeof( i_opt ); + if( getsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, + (void*) &i_opt, &i_opt_size ) == -1 ) + { + msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %s)", + strerror(errno) ); + } + else if( i_opt < 0x80000 ) + { + msg_Warn( p_this, "socket buffer size is 0x%x instead of 0x%x", + i_opt, 0x80000 ); + } + + /* Build the local socket */ + if ( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 ) + { + close( i_handle ); + return( -1 ); + } + + /* Bind it */ + if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 ) + { + msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + + /* Allow broadcast reception if we bound on in6addr_any */ + if( !*psz_bind_addr ) + { + i_opt = 1; + if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, + (void*) &i_opt, sizeof( i_opt ) ) == -1 ) + { + msg_Warn( p_this, "ipv6 warning: cannot configure socket " + "(SO_BROADCAST: %s)", strerror(errno) ); + } + } + + /* Join the multicast group if the socket is a multicast address */ + if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) ) + { + struct ipv6_mreq imr; + int res; + + imr.ipv6mr_interface = sock.sin6_scope_id; + imr.ipv6mr_multiaddr = sock.sin6_addr; + res = setsockopt(i_handle, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void*) &imr, + sizeof(imr)); + + if( res == -1 ) + { +//X intf_ErrMsg( "ipv6 error: setsockopt JOIN_GROUP failed" ); + } + } + + + if( *psz_server_addr ) + { + /* Build socket for remote connection */ + if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 ) + { + msg_Err( p_this, "cannot build remote address" ); + close( i_handle ); + return( -1 ); + } + + /* Connect the socket */ + if( connect( i_handle, (struct sockaddr *) &sock, + sizeof( sock ) ) == (-1) ) + { + msg_Err( p_this, "cannot connect socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + } + + p_socket->i_handle = i_handle; + p_socket->i_mtu = config_GetInt( p_this, "mtu" ); + + return( 0 ); +} + +/***************************************************************************** + * OpenTCP: open a TCP socket + ***************************************************************************** + * psz_server_addr, i_server_port : address and port used for the connect() + * system call. If i_server_port == 0, 80 is used. + * Other parameters are ignored. + * This function returns -1 in case of error. + *****************************************************************************/ +static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket ) +{ + char * psz_server_addr = p_socket->psz_server_addr; + int i_server_port = p_socket->i_server_port; + + int i_handle; + struct sockaddr_in6 sock; + + if( i_server_port == 0 ) + { + i_server_port = 80; + } + + /* Open a SOCK_STREAM (TCP) socket, in the AF_INET6 domain, automatic (0) + * protocol */ + if( (i_handle = socket( AF_INET6, SOCK_STREAM, 0 )) == -1 ) + { + msg_Err( p_this, "cannot create socket (%s)", strerror(errno) ); + return( -1 ); + } + + /* Build remote address */ + if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 ) + { + close( i_handle ); + return( -1 ); + } + + /* Connect the socket */ + if( connect( i_handle, (struct sockaddr *) &sock, + sizeof( sock ) ) == (-1) ) + { + msg_Err( p_this, "cannot connect socket (%s)", strerror(errno) ); + close( i_handle ); + return( -1 ); + } + + p_socket->i_handle = i_handle; + p_socket->i_mtu = 0; /* There is no MTU notion in TCP */ + + return( 0 ); +} + +/***************************************************************************** + * Open: wrapper around OpenUDP and OpenTCP + *****************************************************************************/ +static int Open( vlc_object_t * p_this ) +{ + network_socket_t * p_socket = p_this->p_private; + + if( p_socket->i_type == NETWORK_UDP ) + { + return OpenUDP( p_this, p_socket ); + } + else + { + return OpenTCP( p_this, p_socket ); + } +} diff --git a/modules/misc/null/.cvsignore b/modules/misc/null/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/misc/null/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/misc/null/Makefile b/modules/misc/null/Makefile new file mode 100644 index 0000000000..fbea82909a --- /dev/null +++ b/modules/misc/null/Makefile @@ -0,0 +1 @@ +null_SOURCES = null.c diff --git a/modules/misc/null/null.c b/modules/misc/null/null.c new file mode 100644 index 0000000000..434d999d0c --- /dev/null +++ b/modules/misc/null/null.c @@ -0,0 +1,35 @@ +/***************************************************************************** + * null.c : NULL module for vlc + ***************************************************************************** + * Copyright (C) 2000-2001 VideoLAN + * $Id: null.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 + +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin(); + set_description( _("the module that does nothing") ); +vlc_module_end(); + diff --git a/modules/video_chroma/.cvsignore b/modules/video_chroma/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_chroma/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_chroma/Makefile b/modules/video_chroma/Makefile new file mode 100644 index 0000000000..8a6a9845af --- /dev/null +++ b/modules/video_chroma/Makefile @@ -0,0 +1,8 @@ +i420_rgb_SOURCES = i420_rgb.c i420_rgb8.c i420_rgb16.c +i420_rgb_mmx_SOURCES = i420_rgb.c i420_rgb16.c +i420_yuy2_SOURCES = i420_yuy2.c +i420_yuy2_mmx_SOURCES = i420_yuy2.c +i422_yuy2_SOURCES = i422_yuy2.c +i422_yuy2_mmx_SOURCES = i422_yuy2.c +i420_ymga_SOURCES = i420_ymga.c +i420_ymga_mmx_SOURCES = i420_ymga.c diff --git a/modules/video_chroma/i420_rgb.c b/modules/video_chroma/i420_rgb.c new file mode 100644 index 0000000000..e2475e9d6b --- /dev/null +++ b/modules/video_chroma/i420_rgb.c @@ -0,0 +1,419 @@ +/***************************************************************************** + * i420_rgb.c : YUV to bitmap RGB conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: i420_rgb.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* exp(), pow() */ +#include /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#include "i420_rgb.h" +#if defined (MODULE_NAME_IS_i420_rgb) +# include "i420_rgb_c.h" +#endif + +/***************************************************************************** + * Local and extern prototypes. + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static void Deactivate ( vlc_object_t * ); + +#if defined (MODULE_NAME_IS_i420_rgb) +static void SetGammaTable ( int *pi_table, double f_gamma ); +static void SetYUV ( vout_thread_t * ); +static void Set8bppPalette ( vout_thread_t *, u8 * ); +#endif + +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin(); +#if defined (MODULE_NAME_IS_i420_rgb) + set_description( _("I420,IYUV,YV12 to " + "RGB,RV15,RV16,RV24,RV32 conversions") ); + set_capability( "chroma", 80 ); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + set_description( _( "MMX I420,IYUV,YV12 to " + "RV15,RV16,RV24,RV32 conversions") ); + set_capability( "chroma", 100 ); + add_requirement( MMX ); +#endif + set_callbacks( Activate, Deactivate ); +vlc_module_end(); + +/***************************************************************************** + * Activate: allocate a chroma function + ***************************************************************************** + * This function allocates and initializes a chroma function + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; +#if defined (MODULE_NAME_IS_i420_rgb) + size_t i_tables_size; +#endif + + if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 ) + { + return -1; + } + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('Y','V','1','2'): + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + switch( p_vout->output.i_chroma ) + { +#if defined (MODULE_NAME_IS_i420_rgb) + case VLC_FOURCC('R','G','B','2'): + p_vout->chroma.pf_convert = E_(I420_RGB8); + break; +#endif + case VLC_FOURCC('R','V','1','5'): + p_vout->chroma.pf_convert = E_(I420_RGB15); + break; + + case VLC_FOURCC('R','V','1','6'): + p_vout->chroma.pf_convert = E_(I420_RGB16); + break; + + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + p_vout->chroma.pf_convert = E_(I420_RGB32); + break; + + default: + return -1; + } + break; + + default: + return -1; + } + + p_vout->chroma.p_sys = malloc( sizeof( chroma_sys_t ) ); + if( p_vout->chroma.p_sys == NULL ) + { + return -1; + } + + switch( p_vout->output.i_chroma ) + { +#if defined (MODULE_NAME_IS_i420_rgb) + case VLC_FOURCC('R','G','B','2'): + p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH ); + break; +#endif + + case VLC_FOURCC('R','V','1','5'): + case VLC_FOURCC('R','V','1','6'): + p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 2 ); + break; + + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + p_vout->chroma.p_sys->p_buffer = malloc( VOUT_MAX_WIDTH * 4 ); + break; + + default: + p_vout->chroma.p_sys->p_buffer = NULL; + break; + } + + if( p_vout->chroma.p_sys->p_buffer == NULL ) + { + free( p_vout->chroma.p_sys ); + return -1; + } + + p_vout->chroma.p_sys->p_offset = malloc( p_vout->output.i_width + * ( ( p_vout->output.i_chroma + == VLC_FOURCC('R','G','B','2') ) ? 2 : 1 ) + * sizeof( int ) ); + if( p_vout->chroma.p_sys->p_offset == NULL ) + { + free( p_vout->chroma.p_sys->p_buffer ); + free( p_vout->chroma.p_sys ); + return -1; + } + +#if defined (MODULE_NAME_IS_i420_rgb) + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('R','G','B','2'): + i_tables_size = sizeof( u8 ) * PALETTE_TABLE_SIZE; + break; + case VLC_FOURCC('R','V','1','5'): + case VLC_FOURCC('R','V','1','6'): + i_tables_size = sizeof( u16 ) * RGB_TABLE_SIZE; + break; + default: /* RV24, RV32 */ + i_tables_size = sizeof( u32 ) * RGB_TABLE_SIZE; + break; + } + + p_vout->chroma.p_sys->p_base = malloc( i_tables_size ); + if( p_vout->chroma.p_sys->p_base == NULL ) + { + free( p_vout->chroma.p_sys->p_offset ); + free( p_vout->chroma.p_sys->p_buffer ); + free( p_vout->chroma.p_sys ); + return -1; + } + + SetYUV( p_vout ); +#endif + + return 0; +} + +/***************************************************************************** + * Deactivate: free the chroma function + ***************************************************************************** + * This function frees the previously allocated chroma function + *****************************************************************************/ +static void Deactivate( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + +#if defined (MODULE_NAME_IS_i420_rgb) + free( p_vout->chroma.p_sys->p_base ); +#endif + free( p_vout->chroma.p_sys->p_offset ); + free( p_vout->chroma.p_sys->p_buffer ); + free( p_vout->chroma.p_sys ); +} + +#if defined (MODULE_NAME_IS_i420_rgb) +/***************************************************************************** + * SetGammaTable: return intensity table transformed by gamma curve. + ***************************************************************************** + * pi_table is a table of 256 entries from 0 to 255. + *****************************************************************************/ +static void SetGammaTable( int *pi_table, double f_gamma ) +{ + int i_y; /* base intensity */ + + /* Use exp(gamma) instead of gamma */ + f_gamma = exp( f_gamma ); + + /* Build gamma table */ + for( i_y = 0; i_y < 256; i_y++ ) + { + pi_table[ i_y ] = pow( (double)i_y / 256, f_gamma ) * 256; + } +} + +/***************************************************************************** + * SetYUV: compute tables and set function pointers + *****************************************************************************/ +static void SetYUV( vout_thread_t *p_vout ) +{ + int pi_gamma[256]; /* gamma table */ + int i_index; /* index in tables */ + + /* Build gamma table */ + SetGammaTable( pi_gamma, p_vout->f_gamma ); + + /* + * Set pointers and build YUV tables + */ + + /* Color: build red, green and blue tables */ + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('R','G','B','2'): + p_vout->chroma.p_sys->p_rgb8 = (u8 *)p_vout->chroma.p_sys->p_base; + Set8bppPalette( p_vout, p_vout->chroma.p_sys->p_rgb8 ); + break; + + case VLC_FOURCC('R','V','1','5'): + case VLC_FOURCC('R','V','1','6'): + p_vout->chroma.p_sys->p_rgb16 = (u16 *)p_vout->chroma.p_sys->p_base; + for( i_index = 0; i_index < RED_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb16[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 ); + p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 ); + } + for( i_index = 0; i_index < GREEN_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 ); + p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 ); + } + for( i_index = 0; i_index < BLUE_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] ); + p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] ); + } + for( i_index = 0; i_index < 256; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb16[RED_OFFSET + i_index] = RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 ); + p_vout->chroma.p_sys->p_rgb16[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 ); + p_vout->chroma.p_sys->p_rgb16[BLUE_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] ); + } + break; + + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + p_vout->chroma.p_sys->p_rgb32 = (u32 *)p_vout->chroma.p_sys->p_base; + for( i_index = 0; i_index < RED_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb32[RED_OFFSET - RED_MARGIN + i_index] = RGB2PIXEL( p_vout, pi_gamma[0], 0, 0 ); + p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, pi_gamma[255], 0, 0 ); + } + for( i_index = 0; i_index < GREEN_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET - GREEN_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[0], 0 ); + p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + 256 + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[255], 0 ); + } + for( i_index = 0; i_index < BLUE_MARGIN; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET - BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[0] ); + p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + BLUE_MARGIN + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[255] ); + } + for( i_index = 0; i_index < 256; i_index++ ) + { + p_vout->chroma.p_sys->p_rgb32[RED_OFFSET + i_index] = RGB2PIXEL( p_vout, pi_gamma[ i_index ], 0, 0 ); + p_vout->chroma.p_sys->p_rgb32[GREEN_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, pi_gamma[ i_index ], 0 ); + p_vout->chroma.p_sys->p_rgb32[BLUE_OFFSET + i_index] = RGB2PIXEL( p_vout, 0, 0, pi_gamma[ i_index ] ); + } + break; + } +} + +static void Set8bppPalette( vout_thread_t *p_vout, u8 *p_rgb8 ) +{ + #define CLIP( x ) ( ((x < 0) ? 0 : (x > 255) ? 255 : x) << 8 ) + + int y,u,v; + int r,g,b; + int i = 0, j = 0; + u16 red[ 256 ], green[ 256 ], blue[ 256 ]; + unsigned char p_lookup[PALETTE_TABLE_SIZE]; + + /* This loop calculates the intersection of an YUV box and the RGB cube. */ + for ( y = 0; y <= 256; y += 16, i += 128 - 81 ) + { + for ( u = 0; u <= 256; u += 32 ) + { + for ( v = 0; v <= 256; v += 32 ) + { + r = y + ( (V_RED_COEF*(v-128)) >> SHIFT ); + g = y + ( (U_GREEN_COEF*(u-128) + + V_GREEN_COEF*(v-128)) >> SHIFT ); + b = y + ( (U_BLUE_COEF*(u-128)) >> SHIFT ); + + if( r >= 0x00 && g >= 0x00 && b >= 0x00 + && r <= 0xff && g <= 0xff && b <= 0xff ) + { + /* This one should never happen unless someone + * fscked up my code */ + if( j == 256 ) + { + msg_Err( p_vout, "no colors left in palette" ); + break; + } + + /* Clip the colors */ + red[ j ] = CLIP( r ); + green[ j ] = CLIP( g ); + blue[ j ] = CLIP( b ); + + /* Allocate color */ + p_lookup[ i ] = 1; + p_rgb8[ i++ ] = j; + j++; + } + else + { + p_lookup[ i ] = 0; + p_rgb8[ i++ ] = 0; + } + } + } + } + + /* The colors have been allocated, we can set the palette */ + p_vout->output.pf_setpalette( p_vout, red, green, blue ); + +#if 0 + /* There will eventually be a way to know which colors + * couldn't be allocated and try to find a replacement */ + p_vout->i_white_pixel = 0xff; + p_vout->i_black_pixel = 0x00; + p_vout->i_gray_pixel = 0x44; + p_vout->i_blue_pixel = 0x3b; +#endif + + /* This loop allocates colors that got outside the RGB cube */ + for ( i = 0, y = 0; y <= 256; y += 16, i += 128 - 81 ) + { + for ( u = 0; u <= 256; u += 32 ) + { + for ( v = 0; v <= 256; v += 32, i++ ) + { + int u2, v2, dist, mindist = 100000000; + + if( p_lookup[ i ] || y == 0 ) + { + continue; + } + + /* Heavy. yeah. */ + for( u2 = 0; u2 <= 256; u2 += 32 ) + { + for( v2 = 0; v2 <= 256; v2 += 32 ) + { + j = ((y>>4)<<7) + (u2>>5)*9 + (v2>>5); + dist = (u-u2)*(u-u2) + (v-v2)*(v-v2); + + /* Find the nearest color */ + if( p_lookup[ j ] && dist < mindist ) + { + p_rgb8[ i ] = p_rgb8[ j ]; + mindist = dist; + } + + j -= 128; + + /* Find the nearest color */ + if( p_lookup[ j ] && dist + 128 < mindist ) + { + p_rgb8[ i ] = p_rgb8[ j ]; + mindist = dist + 128; + } + } + } + } + } + } +} + +#endif + diff --git a/modules/video_chroma/i420_rgb.h b/modules/video_chroma/i420_rgb.h new file mode 100644 index 0000000000..dcd929de79 --- /dev/null +++ b/modules/video_chroma/i420_rgb.h @@ -0,0 +1,315 @@ +/***************************************************************************** + * i420_rgb.h : YUV to bitmap RGB conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * $Id: i420_rgb.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * chroma_sys_t: chroma method descriptor + ***************************************************************************** + * This structure is part of the chroma transformation descriptor, it + * describes the yuv2rgb specific properties. + *****************************************************************************/ +struct chroma_sys_t +{ + u8 *p_buffer; + int *p_offset; + +#ifdef MODULE_NAME_IS_i420_rgb + /* Pre-calculated conversion tables */ + void *p_base; /* base for all conversion tables */ + u8 *p_rgb8; /* RGB 8 bits table */ + u16 *p_rgb16; /* RGB 16 bits table */ + u32 *p_rgb32; /* RGB 32 bits table */ +#endif +}; + +/***************************************************************************** + * Prototypes + *****************************************************************************/ +#ifdef MODULE_NAME_IS_i420_rgb +void E_(I420_RGB8) ( vout_thread_t *, picture_t *, picture_t * ); +#endif +void E_(I420_RGB15)( vout_thread_t *, picture_t *, picture_t * ); +void E_(I420_RGB16)( vout_thread_t *, picture_t *, picture_t * ); +void E_(I420_RGB32)( vout_thread_t *, picture_t *, picture_t * ); + +/***************************************************************************** + * CONVERT_*_PIXEL: pixel conversion macros + ***************************************************************************** + * These conversion routines are used by YUV conversion functions. + * conversion are made from p_y, p_u, p_v, which are modified, to p_buffer, + * which is also modified. CONVERT_4YUV_PIXEL is used for 8bpp dithering, + * CONVERT_4YUV_PIXEL_SCALE does the same but also scales the output. + *****************************************************************************/ +#define CONVERT_Y_PIXEL( BPP ) \ + /* Only Y sample is present */ \ + p_ybase = p_yuv + *p_y++; \ + *p_buffer++ = p_ybase[RED_OFFSET-((V_RED_COEF*128)>>SHIFT) + i_red] | \ + p_ybase[GREEN_OFFSET-(((U_GREEN_COEF+V_GREEN_COEF)*128)>>SHIFT) \ + + i_green ] | p_ybase[BLUE_OFFSET-((U_BLUE_COEF*128)>>SHIFT) + i_blue]; + +#define CONVERT_YUV_PIXEL( BPP ) \ + /* Y, U and V samples are present */ \ + i_uval = *p_u++; \ + i_vval = *p_v++; \ + i_red = (V_RED_COEF * i_vval) >> SHIFT; \ + i_green = (U_GREEN_COEF * i_uval + V_GREEN_COEF * i_vval) >> SHIFT; \ + i_blue = (U_BLUE_COEF * i_uval) >> SHIFT; \ + CONVERT_Y_PIXEL( BPP ) \ + +#define CONVERT_4YUV_PIXEL( CHROMA ) \ + *p_pic++ = p_lookup[ \ + (((*p_y++ + dither10[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither20[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither20[i_real_y]) >> 5) ]; \ + *p_pic++ = p_lookup[ \ + (((*p_y++ + dither11[i_real_y]) >> 4) << 7) \ + + ((*p_u++ + dither21[i_real_y]) >> 5) * 9 \ + + ((*p_v++ + dither21[i_real_y]) >> 5) ]; \ + *p_pic++ = p_lookup[ \ + (((*p_y++ + dither12[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither22[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither22[i_real_y]) >> 5) ]; \ + *p_pic++ = p_lookup[ \ + (((*p_y++ + dither13[i_real_y]) >> 4) << 7) \ + + ((*p_u++ + dither23[i_real_y]) >> 5) * 9 \ + + ((*p_v++ + dither23[i_real_y]) >> 5) ]; \ + +#define CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \ + *p_pic++ = p_lookup[ \ + ( ((*p_y + dither10[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither20[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither20[i_real_y]) >> 5) ]; \ + p_y += *p_offset++; \ + p_u += *p_offset; \ + p_v += *p_offset++; \ + *p_pic++ = p_lookup[ \ + ( ((*p_y + dither11[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither21[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither21[i_real_y]) >> 5) ]; \ + p_y += *p_offset++; \ + p_u += *p_offset; \ + p_v += *p_offset++; \ + *p_pic++ = p_lookup[ \ + ( ((*p_y + dither12[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither22[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither22[i_real_y]) >> 5) ]; \ + p_y += *p_offset++; \ + p_u += *p_offset; \ + p_v += *p_offset++; \ + *p_pic++ = p_lookup[ \ + ( ((*p_y + dither13[i_real_y]) >> 4) << 7) \ + + ((*p_u + dither23[i_real_y]) >> 5) * 9 \ + + ((*p_v + dither23[i_real_y]) >> 5) ]; \ + p_y += *p_offset++; \ + p_u += *p_offset; \ + p_v += *p_offset++; \ + +/***************************************************************************** + * SCALE_WIDTH: scale a line horizontally + ***************************************************************************** + * This macro scales a line using rendering buffer and offset array. It works + * for 1, 2 and 4 Bpp. + *****************************************************************************/ +#define SCALE_WIDTH \ + if( b_hscale ) \ + { \ + /* Horizontal scaling, conversion has been done to buffer. \ + * Rewind buffer and offset, then copy and scale line */ \ + p_buffer = p_buffer_start; \ + p_offset = p_offset_start; \ + for( i_x = p_vout->output.i_width / 16; i_x--; ) \ + { \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + } \ + for( i_x = p_vout->output.i_width & 15; i_x--; ) \ + { \ + *p_pic++ = *p_buffer; p_buffer += *p_offset++; \ + } \ + p_pic += i_right_margin; \ + } \ + else \ + { \ + /* No scaling, conversion has been done directly in picture memory. \ + * Increment of picture pointer to end of line is still needed */ \ + (u8*)p_pic += p_dest->p->i_pitch; \ + } \ + +/***************************************************************************** + * SCALE_WIDTH_DITHER: scale a line horizontally for dithered 8 bpp + ***************************************************************************** + * This macro scales a line using an offset array. + *****************************************************************************/ +#define SCALE_WIDTH_DITHER( CHROMA ) \ + if( b_hscale ) \ + { \ + /* Horizontal scaling - we can't use a buffer due to dithering */ \ + p_offset = p_offset_start; \ + for( i_x = p_vout->output.i_width / 16; i_x--; ) \ + { \ + CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \ + CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \ + CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \ + CONVERT_4YUV_PIXEL_SCALE( CHROMA ) \ + } \ + } \ + else \ + { \ + for( i_x = p_vout->render.i_width / 16; i_x--; ) \ + { \ + CONVERT_4YUV_PIXEL( CHROMA ) \ + CONVERT_4YUV_PIXEL( CHROMA ) \ + CONVERT_4YUV_PIXEL( CHROMA ) \ + CONVERT_4YUV_PIXEL( CHROMA ) \ + } \ + } \ + /* Increment of picture pointer to end of line is still needed */ \ + p_pic += i_right_margin; \ + \ + /* Increment the Y coordinate in the matrix, modulo 4 */ \ + i_real_y = (i_real_y + 1) & 0x3; \ + +/***************************************************************************** + * SCALE_HEIGHT: handle vertical scaling + ***************************************************************************** + * This macro handle vertical scaling for a picture. CHROMA may be 420, 422 or + * 444 for RGB conversion, or 400 for gray conversion. It works for 1, 2, 3 + * and 4 Bpp. + *****************************************************************************/ +#define SCALE_HEIGHT( CHROMA, BPP ) \ + /* If line is odd, rewind 4:2:0 U and V samples */ \ + if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \ + { \ + p_u -= i_chroma_width; \ + p_v -= i_chroma_width; \ + } \ + \ + /* \ + * Handle vertical scaling. The current line can be copied or next one \ + * can be ignored. \ + */ \ + switch( i_vscale ) \ + { \ + case -1: /* vertical scaling factor is < 1 */ \ + while( (i_scale_count -= p_vout->output.i_height) > 0 ) \ + { \ + /* Height reduction: skip next source line */ \ + p_y += p_vout->render.i_width; \ + i_y++; \ + if( (CHROMA == 420) || (CHROMA == 422) ) \ + { \ + if( i_y & 0x1 ) \ + { \ + p_u += i_chroma_width; \ + p_v += i_chroma_width; \ + } \ + } \ + else if( CHROMA == 444 ) \ + { \ + p_u += p_vout->render.i_width; \ + p_v += p_vout->render.i_width; \ + } \ + } \ + i_scale_count += p_vout->render.i_height; \ + break; \ + case 1: /* vertical scaling factor is > 1 */ \ + while( (i_scale_count -= p_vout->render.i_height) > 0 ) \ + { \ + /* Height increment: copy previous picture line */ \ + p_vout->p_vlc->pf_memcpy( p_pic, p_pic_start, \ + p_vout->output.i_width * BPP ); \ + (u8*)p_pic += p_dest->p->i_pitch; \ + } \ + i_scale_count += p_vout->output.i_height; \ + break; \ + } \ + +/***************************************************************************** + * SCALE_HEIGHT_DITHER: handle vertical scaling for dithered 8 bpp + ***************************************************************************** + * This macro handles vertical scaling for a picture. CHROMA may be 420, + * 422 or 444 for RGB conversion, or 400 for gray conversion. + *****************************************************************************/ +#define SCALE_HEIGHT_DITHER( CHROMA ) \ + \ + /* If line is odd, rewind 4:2:0 U and V samples */ \ + if( ((CHROMA == 420) || (CHROMA == 422)) && !(i_y & 0x1) ) \ + { \ + p_u -= i_chroma_width; \ + p_v -= i_chroma_width; \ + } \ + \ + /* \ + * Handle vertical scaling. The current line can be copied or next one \ + * can be ignored. \ + */ \ + \ + switch( i_vscale ) \ + { \ + case -1: /* vertical scaling factor is < 1 */ \ + while( (i_scale_count -= p_vout->output.i_height) > 0 ) \ + { \ + /* Height reduction: skip next source line */ \ + p_y += p_vout->render.i_width; \ + i_y++; \ + if( (CHROMA == 420) || (CHROMA == 422) ) \ + { \ + if( i_y & 0x1 ) \ + { \ + p_u += i_chroma_width; \ + p_v += i_chroma_width; \ + } \ + } \ + else if( CHROMA == 444 ) \ + { \ + p_u += p_vout->render.i_width; \ + p_v += p_vout->render.i_width; \ + } \ + } \ + i_scale_count += p_vout->render.i_height; \ + break; \ + case 1: /* vertical scaling factor is > 1 */ \ + while( (i_scale_count -= p_vout->render.i_height) > 0 ) \ + { \ + p_y -= p_vout->render.i_width; \ + p_u -= i_chroma_width; \ + p_v -= i_chroma_width; \ + SCALE_WIDTH_DITHER( CHROMA ); \ + } \ + i_scale_count += p_vout->output.i_height; \ + break; \ + } \ + diff --git a/modules/video_chroma/i420_rgb16.c b/modules/video_chroma/i420_rgb16.c new file mode 100644 index 0000000000..070324d4f6 --- /dev/null +++ b/modules/video_chroma/i420_rgb16.c @@ -0,0 +1,498 @@ +/***************************************************************************** + * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * $Id: i420_rgb16.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#include "i420_rgb.h" +#if defined (MODULE_NAME_IS_i420_rgb) +# include "i420_rgb_c.h" +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) +# include "i420_rgb_mmx.h" +#endif + +static void SetOffset( int, int, int, int, vlc_bool_t *, int *, int * ); + +/***************************************************************************** + * I420_RGB15: color YUV 4:2:0 to RGB 15 bpp + ***************************************************************************** + * Horizontal alignment needed: + * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed + * - output: 1 pixel (2 bytes), margins allowed + * Vertical alignment needed: + * - input: 2 lines (2 Y lines, 1 U/V line) + * - output: 1 line + *****************************************************************************/ +void E_(I420_RGB15)( vout_thread_t *p_vout, picture_t *p_src, + picture_t *p_dest ) +{ + /* We got this one from the old arguments */ + u16 *p_pic = (u16*)p_dest->p->p_pixels; + u8 *p_y = p_src->Y_PIXELS; + u8 *p_u = p_src->U_PIXELS; + u8 *p_v = p_src->V_PIXELS; + + vlc_bool_t b_hscale; /* horizontal scaling type */ + int i_vscale; /* vertical scaling type */ + int i_x, i_y; /* horizontal and vertical indexes */ + int i_right_margin; + int i_rewind; + int i_scale_count; /* scale modulo counter */ + int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */ + u16 * p_pic_start; /* beginning of the current line for copy */ +#if defined (MODULE_NAME_IS_i420_rgb) + int i_uval, i_vval; /* U and V samples */ + int i_red, i_green, i_blue; /* U and V modified samples */ + u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16; + u16 * p_ybase; /* Y dependant conversion table */ +#endif + + /* Conversion buffer pointer */ + u16 * p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer; + u16 * p_buffer; + + /* Offset array pointer */ + int * p_offset_start = p_vout->chroma.p_sys->p_offset; + int * p_offset; + + i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch; + + if( p_vout->render.i_width & 7 ) + { + i_rewind = 8 - ( p_vout->render.i_width & 7 ); + } + else + { + i_rewind = 0; + } + + /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered + * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1' + * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */ + SetOffset( p_vout->render.i_width, p_vout->render.i_height, + p_vout->output.i_width, p_vout->output.i_height, + &b_hscale, &i_vscale, p_offset_start ); + + /* + * Perform conversion + */ + i_scale_count = ( i_vscale == 1 ) ? + p_vout->output.i_height : p_vout->render.i_height; + for( i_y = 0; i_y < p_vout->render.i_height; i_y++ ) + { + p_pic_start = p_pic; + p_buffer = b_hscale ? p_buffer_start : p_pic; + + for ( i_x = p_vout->render.i_width / 8; i_x--; ) + { +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_15 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + + /* Here we do some unaligned reads and duplicate conversions, but + * at least we have all the pixels */ + if( i_rewind ) + { + p_y -= i_rewind; + p_u -= i_rewind >> 1; + p_v -= i_rewind >> 1; + p_buffer -= i_rewind; +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_15 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + SCALE_WIDTH; + SCALE_HEIGHT( 420, 2 ); + } +} + +/***************************************************************************** + * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp + ***************************************************************************** + * Horizontal alignment needed: + * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed + * - output: 1 pixel (2 bytes), margins allowed + * Vertical alignment needed: + * - input: 2 lines (2 Y lines, 1 U/V line) + * - output: 1 line + *****************************************************************************/ +void E_(I420_RGB16)( vout_thread_t *p_vout, picture_t *p_src, + picture_t *p_dest ) +{ + /* We got this one from the old arguments */ + u16 *p_pic = (u16*)p_dest->p->p_pixels; + u8 *p_y = p_src->Y_PIXELS; + u8 *p_u = p_src->U_PIXELS; + u8 *p_v = p_src->V_PIXELS; + + vlc_bool_t b_hscale; /* horizontal scaling type */ + int i_vscale; /* vertical scaling type */ + int i_x, i_y; /* horizontal and vertical indexes */ + int i_right_margin; + int i_rewind; + int i_scale_count; /* scale modulo counter */ + int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */ + u16 * p_pic_start; /* beginning of the current line for copy */ +#if defined (MODULE_NAME_IS_i420_rgb) + int i_uval, i_vval; /* U and V samples */ + int i_red, i_green, i_blue; /* U and V modified samples */ + u16 * p_yuv = p_vout->chroma.p_sys->p_rgb16; + u16 * p_ybase; /* Y dependant conversion table */ +#endif + + /* Conversion buffer pointer */ + u16 * p_buffer_start = (u16*)p_vout->chroma.p_sys->p_buffer; + u16 * p_buffer; + + /* Offset array pointer */ + int * p_offset_start = p_vout->chroma.p_sys->p_offset; + int * p_offset; + + i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch; + + if( p_vout->render.i_width & 7 ) + { + i_rewind = 8 - ( p_vout->render.i_width & 7 ); + } + else + { + i_rewind = 0; + } + + /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered + * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1' + * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */ + SetOffset( p_vout->render.i_width, p_vout->render.i_height, + p_vout->output.i_width, p_vout->output.i_height, + &b_hscale, &i_vscale, p_offset_start ); + + /* + * Perform conversion + */ + i_scale_count = ( i_vscale == 1 ) ? + p_vout->output.i_height : p_vout->render.i_height; + for( i_y = 0; i_y < p_vout->render.i_height; i_y++ ) + { + p_pic_start = p_pic; + p_buffer = b_hscale ? p_buffer_start : p_pic; + + for ( i_x = p_vout->render.i_width / 8; i_x--; ) + { +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + + /* Here we do some unaligned reads and duplicate conversions, but + * at least we have all the pixels */ + if( i_rewind ) + { + p_y -= i_rewind; + p_u -= i_rewind >> 1; + p_v -= i_rewind >> 1; + p_buffer -= i_rewind; +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); + CONVERT_YUV_PIXEL(2); CONVERT_Y_PIXEL(2); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_16 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + SCALE_WIDTH; + SCALE_HEIGHT( 420, 2 ); + } +} + +/***************************************************************************** + * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp + ***************************************************************************** + * Horizontal alignment needed: + * - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed + * - output: 1 pixel (2 bytes), margins allowed + * Vertical alignment needed: + * - input: 2 lines (2 Y lines, 1 U/V line) + * - output: 1 line + *****************************************************************************/ +void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src, + picture_t *p_dest ) +{ + /* We got this one from the old arguments */ + u32 *p_pic = (u32*)p_dest->p->p_pixels; + u8 *p_y = p_src->Y_PIXELS; + u8 *p_u = p_src->U_PIXELS; + u8 *p_v = p_src->V_PIXELS; + + vlc_bool_t b_hscale; /* horizontal scaling type */ + int i_vscale; /* vertical scaling type */ + int i_x, i_y; /* horizontal and vertical indexes */ + int i_right_margin; + int i_rewind; + int i_scale_count; /* scale modulo counter */ + int i_chroma_width = p_vout->render.i_width / 4; /* chroma width */ + u32 * p_pic_start; /* beginning of the current line for copy */ +#if defined (MODULE_NAME_IS_i420_rgb) + int i_uval, i_vval; /* U and V samples */ + int i_red, i_green, i_blue; /* U and V modified samples */ + u32 * p_yuv = p_vout->chroma.p_sys->p_rgb32; + u32 * p_ybase; /* Y dependant conversion table */ +#endif + + /* Conversion buffer pointer */ + u32 * p_buffer_start = (u32*)p_vout->chroma.p_sys->p_buffer; + u32 * p_buffer; + + /* Offset array pointer */ + int * p_offset_start = p_vout->chroma.p_sys->p_offset; + int * p_offset; + + i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch; + + if( p_vout->render.i_width & 7 ) + { + i_rewind = 8 - ( p_vout->render.i_width & 7 ); + } + else + { + i_rewind = 0; + } + + /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered + * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1' + * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */ + SetOffset( p_vout->render.i_width, p_vout->render.i_height, + p_vout->output.i_width, p_vout->output.i_height, + &b_hscale, &i_vscale, p_offset_start ); + + /* + * Perform conversion + */ + i_scale_count = ( i_vscale == 1 ) ? + p_vout->output.i_height : p_vout->render.i_height; + for( i_y = 0; i_y < p_vout->render.i_height; i_y++ ) + { + p_pic_start = p_pic; + p_buffer = b_hscale ? p_buffer_start : p_pic; + + for ( i_x = p_vout->render.i_width / 8; i_x--; ) + { +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_32 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_32 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + + /* Here we do some unaligned reads and duplicate conversions, but + * at least we have all the pixels */ + if( i_rewind ) + { + p_y -= i_rewind; + p_u -= i_rewind >> 1; + p_v -= i_rewind >> 1; + p_buffer -= i_rewind; +#if defined (MODULE_NAME_IS_i420_rgb) + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); + CONVERT_YUV_PIXEL(4); CONVERT_Y_PIXEL(4); +#elif defined (MODULE_NAME_IS_i420_rgb_mmx) + __asm__( MMX_INIT_32 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + __asm__( ".align 8" + MMX_YUV_MUL + MMX_YUV_ADD + MMX_UNPACK_32 + : : "r" (p_y), "r" (p_u), "r" (p_v), "r" (p_buffer) ); + + p_y += 8; + p_u += 4; + p_v += 4; + p_buffer += 8; +#endif + } + SCALE_WIDTH; + SCALE_HEIGHT( 420, 4 ); + } +} + +/* Following functions are local */ + +/***************************************************************************** + * SetOffset: build offset array for conversion functions + ***************************************************************************** + * This function will build an offset array used in later conversion functions. + * It will also set horizontal and vertical scaling indicators. + *****************************************************************************/ +static void SetOffset( int i_width, int i_height, int i_pic_width, + int i_pic_height, vlc_bool_t *pb_hscale, + int *pi_vscale, int *p_offset ) +{ + int i_x; /* x position in destination */ + int i_scale_count; /* modulo counter */ + + /* + * Prepare horizontal offset array + */ + if( i_pic_width - i_width == 0 ) + { + /* No horizontal scaling: YUV conversion is done directly to picture */ + *pb_hscale = 0; + } + else if( i_pic_width - i_width > 0 ) + { + /* Prepare scaling array for horizontal extension */ + *pb_hscale = 1; + i_scale_count = i_pic_width; + for( i_x = i_width; i_x--; ) + { + while( (i_scale_count -= i_width) > 0 ) + { + *p_offset++ = 0; + } + *p_offset++ = 1; + i_scale_count += i_pic_width; + } + } + else /* if( i_pic_width - i_width < 0 ) */ + { + /* Prepare scaling array for horizontal reduction */ + *pb_hscale = 1; + i_scale_count = i_width; + for( i_x = i_pic_width; i_x--; ) + { + *p_offset = 1; + while( (i_scale_count -= i_pic_width) > 0 ) + { + *p_offset += 1; + } + p_offset++; + i_scale_count += i_width; + } + } + + /* + * Set vertical scaling indicator + */ + if( i_pic_height - i_height == 0 ) + { + *pi_vscale = 0; + } + else if( i_pic_height - i_height > 0 ) + { + *pi_vscale = 1; + } + else /* if( i_pic_height - i_height < 0 ) */ + { + *pi_vscale = -1; + } +} + diff --git a/modules/video_chroma/i420_rgb8.c b/modules/video_chroma/i420_rgb8.c new file mode 100644 index 0000000000..6b643b489e --- /dev/null +++ b/modules/video_chroma/i420_rgb8.c @@ -0,0 +1,177 @@ +/***************************************************************************** + * i420_rgb8.c : YUV to bitmap RGB conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000 VideoLAN + * $Id: i420_rgb8.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#include "i420_rgb.h" +#include "i420_rgb_c.h" + +static void SetOffset( int, int, int, int, vlc_bool_t *, int *, int * ); + +/***************************************************************************** + * I420_RGB8: color YUV 4:2:0 to RGB 8 bpp + *****************************************************************************/ +void E_(I420_RGB8)( vout_thread_t *p_vout, picture_t *p_src, picture_t *p_dest ) +{ + /* We got this one from the old arguments */ + u8 *p_pic = (u8*)p_dest->p->p_pixels; + u8 *p_y = p_src->Y_PIXELS; + u8 *p_u = p_src->U_PIXELS; + u8 *p_v = p_src->V_PIXELS; + + vlc_bool_t b_hscale; /* horizontal scaling type */ + int i_vscale; /* vertical scaling type */ + int i_x, i_y; /* horizontal and vertical indexes */ + int i_real_y; /* y % 4 */ + int i_right_margin; + int i_scale_count; /* scale modulo counter */ + int i_chroma_width = p_vout->render.i_width / 2; /* chroma width */ + + /* Lookup table */ + u8 * p_lookup = p_vout->chroma.p_sys->p_base; + + /* Offset array pointer */ + int * p_offset_start = p_vout->chroma.p_sys->p_offset; + int * p_offset; + + /* The dithering matrices */ + static int dither10[4] = { 0x0, 0x8, 0x2, 0xa }; + static int dither11[4] = { 0xc, 0x4, 0xe, 0x6 }; + static int dither12[4] = { 0x3, 0xb, 0x1, 0x9 }; + static int dither13[4] = { 0xf, 0x7, 0xd, 0x5 }; + + static int dither20[4] = { 0x0, 0x10, 0x4, 0x14 }; + static int dither21[4] = { 0x18, 0x8, 0x1c, 0xc }; + static int dither22[4] = { 0x6, 0x16, 0x2, 0x12 }; + static int dither23[4] = { 0x1e, 0xe, 0x1a, 0xa }; + + SetOffset( p_vout->render.i_width, p_vout->render.i_height, + p_vout->output.i_width, p_vout->output.i_height, + &b_hscale, &i_vscale, p_offset_start ); + + i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch; + + /* + * Perform conversion + */ + i_scale_count = ( i_vscale == 1 ) ? + p_vout->output.i_height : p_vout->render.i_height; + for( i_y = 0, i_real_y = 0; i_y < p_vout->render.i_height; i_y++ ) + { + /* Do horizontal and vertical scaling */ + SCALE_WIDTH_DITHER( 420 ); + SCALE_HEIGHT_DITHER( 420 ); + } +} + +/* Following functions are local */ + +/***************************************************************************** + * SetOffset: build offset array for conversion functions + ***************************************************************************** + * This function will build an offset array used in later conversion functions. + * It will also set horizontal and vertical scaling indicators. The p_offset + * structure has interleaved Y and U/V offsets. + *****************************************************************************/ +static void SetOffset( int i_width, int i_height, int i_pic_width, + int i_pic_height, vlc_bool_t *pb_hscale, + int *pi_vscale, int *p_offset ) +{ + int i_x; /* x position in destination */ + int i_scale_count; /* modulo counter */ + + /* + * Prepare horizontal offset array + */ + if( i_pic_width - i_width == 0 ) + { + /* No horizontal scaling: YUV conversion is done directly to picture */ + *pb_hscale = 0; + } + else if( i_pic_width - i_width > 0 ) + { + int i_dummy = 0; + + /* Prepare scaling array for horizontal extension */ + *pb_hscale = 1; + i_scale_count = i_pic_width; + for( i_x = i_width; i_x--; ) + { + while( (i_scale_count -= i_width) > 0 ) + { + *p_offset++ = 0; + *p_offset++ = 0; + } + *p_offset++ = 1; + *p_offset++ = i_dummy; + i_dummy = 1 - i_dummy; + i_scale_count += i_pic_width; + } + } + else /* if( i_pic_width - i_width < 0 ) */ + { + int i_remainder = 0; + int i_jump; + + /* Prepare scaling array for horizontal reduction */ + *pb_hscale = 1; + i_scale_count = i_width; + for( i_x = i_pic_width; i_x--; ) + { + i_jump = 1; + while( (i_scale_count -= i_pic_width) > 0 ) + { + i_jump += 1; + } + *p_offset++ = i_jump; + *p_offset++ = ( i_jump += i_remainder ) >> 1; + i_remainder = i_jump & 1; + i_scale_count += i_width; + } + } + + /* + * Set vertical scaling indicator + */ + if( i_pic_height - i_height == 0 ) + { + *pi_vscale = 0; + } + else if( i_pic_height - i_height > 0 ) + { + *pi_vscale = 1; + } + else /* if( i_pic_height - i_height < 0 ) */ + { + *pi_vscale = -1; + } +} + diff --git a/modules/video_chroma/i420_rgb_c.h b/modules/video_chroma/i420_rgb_c.h new file mode 100644 index 0000000000..1387fcef34 --- /dev/null +++ b/modules/video_chroma/i420_rgb_c.h @@ -0,0 +1,55 @@ +/***************************************************************************** + * chroma_common.h: YUV transformation functions + * Provides functions to perform the YUV conversion. The functions provided here + * are a complete and portable C implementation, and may be replaced in certain + * case by optimized functions. + ***************************************************************************** + * Copyright (C) 1999, 2000 VideoLAN + * $Id: i420_rgb_c.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Vincent Seguin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + *****************************************************************************/ + +/***************************************************************************** + * Constants + *****************************************************************************/ + +/* Margins and offsets in conversion tables - Margins are used in case a RGB + * RGB conversion would give a value outside the 0-255 range. Offsets have been + * calculated to avoid using the same cache line for 2 tables. conversion tables + * are 2*MARGIN + 256 long and stores pixels.*/ +#define RED_MARGIN 178 +#define GREEN_MARGIN 135 +#define BLUE_MARGIN 224 +#define RED_OFFSET 1501 /* 1323 to 1935 */ +#define GREEN_OFFSET 135 /* 0 to 526 */ +#define BLUE_OFFSET 818 /* 594 to 1298 */ +#define RGB_TABLE_SIZE 1935 /* total table size */ + +#define GRAY_MARGIN 384 +#define GRAY_TABLE_SIZE 1024 /* total table size */ + +#define PALETTE_TABLE_SIZE 2176 /* YUV -> 8bpp palette lookup table */ + +/* macros used for YUV pixel conversions */ +#define SHIFT 20 +#define U_GREEN_COEF ((int)(-0.391 * (1< + * Gaël Hendryckx + * Samuel Hocevar + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + *****************************************************************************/ + +/* hope these constant values are cache line aligned */ +#define UNUSED_LONGLONG(foo) \ + static const unsigned long long foo __asm__ (#foo) __attribute__((unused)) +UNUSED_LONGLONG(mmx_80w) = 0x0080008000800080; +UNUSED_LONGLONG(mmx_10w) = 0x1010101010101010; +UNUSED_LONGLONG(mmx_00ffw) = 0x00ff00ff00ff00ff; +UNUSED_LONGLONG(mmx_Y_coeff) = 0x253f253f253f253f; + +UNUSED_LONGLONG(mmx_U_green) = 0xf37df37df37df37d; +UNUSED_LONGLONG(mmx_U_blue) = 0x4093409340934093; +UNUSED_LONGLONG(mmx_V_red) = 0x3312331233123312; +UNUSED_LONGLONG(mmx_V_green) = 0xe5fce5fce5fce5fc; + +UNUSED_LONGLONG(mmx_mask_f8) = 0xf8f8f8f8f8f8f8f8; +UNUSED_LONGLONG(mmx_mask_fc) = 0xfcfcfcfcfcfcfcfc; +#undef UNUSED_LONGLONG + +#define MMX_INIT_16 " \n\ +movd (%1), %%mm0 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%2), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +pxor %%mm4, %%mm4 # zero mm4 \n\ +movq (%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +#movl $0, (%3) # cache preload for image \n\ +" + +#define MMX_INIT_16_GRAY " \n\ +movq (%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +#movl $0, (%3) # cache preload for image \n\ +" + +#define MMX_INIT_32 " \n\ +movd (%1), %%mm0 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movl $0, (%3) # cache preload for image \n\ +movd (%2), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +pxor %%mm4, %%mm4 # zero mm4 \n\ +movq (%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +" + +/* + * Do the multiply part of the conversion for even and odd pixels, + * register usage: + * mm0 -> Cblue, mm1 -> Cred, mm2 -> Cgreen even pixels, + * mm3 -> Cblue, mm4 -> Cred, mm5 -> Cgreen odd pixels, + * mm6 -> Y even, mm7 -> Y odd + */ + +#define MMX_YUV_MUL " \n\ +# convert the chroma part \n\ +punpcklbw %%mm4, %%mm0 # scatter 4 Cb 00 u3 00 u2 00 u1 00 u0 \n\ +punpcklbw %%mm4, %%mm1 # scatter 4 Cr 00 v3 00 v2 00 v1 00 v0 \n\ +psubsw mmx_80w, %%mm0 # Cb -= 128 \n\ +psubsw mmx_80w, %%mm1 # Cr -= 128 \n\ +psllw $3, %%mm0 # Promote precision \n\ +psllw $3, %%mm1 # Promote precision \n\ +movq %%mm0, %%mm2 # Copy 4 Cb 00 u3 00 u2 00 u1 00 u0 \n\ +movq %%mm1, %%mm3 # Copy 4 Cr 00 v3 00 v2 00 v1 00 v0 \n\ +pmulhw mmx_U_green, %%mm2 # Mul Cb with green coeff -> Cb green \n\ +pmulhw mmx_V_green, %%mm3 # Mul Cr with green coeff -> Cr green \n\ +pmulhw mmx_U_blue, %%mm0 # Mul Cb -> Cblue 00 b3 00 b2 00 b1 00 b0 \n\ +pmulhw mmx_V_red, %%mm1 # Mul Cr -> Cred 00 r3 00 r2 00 r1 00 r0 \n\ +paddsw %%mm3, %%mm2 # Cb green + Cr green -> Cgreen \n\ + \n\ +# convert the luma part \n\ +psubusb mmx_10w, %%mm6 # Y -= 16 \n\ +movq %%mm6, %%mm7 # Copy 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +pand mmx_00ffw, %%mm6 # get Y even 00 Y6 00 Y4 00 Y2 00 Y0 \n\ +psrlw $8, %%mm7 # get Y odd 00 Y7 00 Y5 00 Y3 00 Y1 \n\ +psllw $3, %%mm6 # Promote precision \n\ +psllw $3, %%mm7 # Promote precision \n\ +pmulhw mmx_Y_coeff, %%mm6 # Mul 4 Y even 00 y6 00 y4 00 y2 00 y0 \n\ +pmulhw mmx_Y_coeff, %%mm7 # Mul 4 Y odd 00 y7 00 y5 00 y3 00 y1 \n\ +" + +/* + * Do the addition part of the conversion for even and odd pixels, + * register usage: + * mm0 -> Cblue, mm1 -> Cred, mm2 -> Cgreen even pixels, + * mm3 -> Cblue, mm4 -> Cred, mm5 -> Cgreen odd pixels, + * mm6 -> Y even, mm7 -> Y odd + */ + +#define MMX_YUV_ADD " \n\ +# Do horizontal and vertical scaling \n\ +movq %%mm0, %%mm3 # Copy Cblue \n\ +movq %%mm1, %%mm4 # Copy Cred \n\ +movq %%mm2, %%mm5 # Copy Cgreen \n\ +paddsw %%mm6, %%mm0 # Y even + Cblue 00 B6 00 B4 00 B2 00 B0 \n\ +paddsw %%mm7, %%mm3 # Y odd + Cblue 00 B7 00 B5 00 B3 00 B1 \n\ +paddsw %%mm6, %%mm1 # Y even + Cred 00 R6 00 R4 00 R2 00 R0 \n\ +paddsw %%mm7, %%mm4 # Y odd + Cred 00 R7 00 R5 00 R3 00 R1 \n\ +paddsw %%mm6, %%mm2 # Y even + Cgreen 00 G6 00 G4 00 G2 00 G0 \n\ +paddsw %%mm7, %%mm5 # Y odd + Cgreen 00 G7 00 G5 00 G3 00 G1 \n\ + \n\ +# Limit RGB even to 0..255 \n\ +packuswb %%mm0, %%mm0 # B6 B4 B2 B0 / B6 B4 B2 B0 \n\ +packuswb %%mm1, %%mm1 # R6 R4 R2 R0 / R6 R4 R2 R0 \n\ +packuswb %%mm2, %%mm2 # G6 G4 G2 G0 / G6 G4 G2 G0 \n\ + \n\ +# Limit RGB odd to 0..255 \n\ +packuswb %%mm3, %%mm3 # B7 B5 B3 B1 / B7 B5 B3 B1 \n\ +packuswb %%mm4, %%mm4 # R7 R5 R3 R1 / R7 R5 R3 R1 \n\ +packuswb %%mm5, %%mm5 # G7 G5 G3 G1 / G7 G5 G3 G1 \n\ + \n\ +# Interleave RGB even and odd \n\ +punpcklbw %%mm3, %%mm0 # B7 B6 B5 B4 B3 B2 B1 B0 \n\ +punpcklbw %%mm4, %%mm1 # R7 R6 R5 R4 R3 R2 R1 R0 \n\ +punpcklbw %%mm5, %%mm2 # G7 G6 G5 G4 G3 G2 G1 G0 \n\ +" + +/* + * Grayscale case, only use Y + */ + +#define MMX_YUV_GRAY " \n\ +# convert the luma part \n\ +psubusb mmx_10w, %%mm6 \n\ +movq %%mm6, %%mm7 \n\ +pand mmx_00ffw, %%mm6 \n\ +psrlw $8, %%mm7 \n\ +psllw $3, %%mm6 \n\ +psllw $3, %%mm7 \n\ +pmulhw mmx_Y_coeff, %%mm6 \n\ +pmulhw mmx_Y_coeff, %%mm7 \n\ +packuswb %%mm6, %%mm6 \n\ +packuswb %%mm7, %%mm7 \n\ +punpcklbw %%mm7, %%mm6 \n\ +" + +#define MMX_UNPACK_16_GRAY " \n\ +movq %%mm6, %%mm5 \n\ +pand mmx_mask_f8, %%mm6 \n\ +pand mmx_mask_fc, %%mm5 \n\ +movq %%mm6, %%mm7 \n\ +psrlw $3, %%mm7 \n\ +pxor %%mm3, %%mm3 \n\ +movq %%mm7, %%mm2 \n\ +movq %%mm5, %%mm0 \n\ +punpcklbw %%mm3, %%mm5 \n\ +punpcklbw %%mm6, %%mm7 \n\ +psllw $3, %%mm5 \n\ +por %%mm5, %%mm7 \n\ +movq %%mm7, (%3) \n\ +punpckhbw %%mm3, %%mm0 \n\ +punpckhbw %%mm6, %%mm2 \n\ +psllw $3, %%mm0 \n\ +movq 8(%0), %%mm6 \n\ +por %%mm0, %%mm2 \n\ +movq %%mm2, 8(%3) \n\ +" + + +/* + * convert RGB plane to RGB 15 bits, + * mm0 -> B, mm1 -> R, mm2 -> G, + * mm4 -> GB, mm5 -> AR pixel 4-7, + * mm6 -> GB, mm7 -> AR pixel 0-3 + */ + +#define MMX_UNPACK_15 " \n\ +# mask unneeded bits off \n\ +pand mmx_mask_f8, %%mm0 # b7b6b5b4 b3______ b7b6b5b4 b3______ \n\ +psrlw $3,%%mm0 # ______b7 b6b5b4b3 ______b7 b6b5b4b3 \n\ +pand mmx_mask_f8, %%mm2 # g7g6g5g4 g3______ g7g6g5g4 g3______ \n\ +pand mmx_mask_f8, %%mm1 # r7r6r5r4 r3______ r7r6r5r4 r3______ \n\ +psrlw $1,%%mm1 # __r7r6r5 r4r3____ __r7r6r5 r4r3____ \n\ +pxor %%mm4, %%mm4 # zero mm4 \n\ +movq %%mm0, %%mm5 # Copy B7-B0 \n\ +movq %%mm2, %%mm7 # Copy G7-G0 \n\ + \n\ +# convert rgb24 plane to rgb15 pack for pixel 0-3 \n\ +punpcklbw %%mm4, %%mm2 # ________ ________ g7g6g5g4 g3______ \n\ +punpcklbw %%mm1, %%mm0 # r7r6r5r4 r3______ ______b7 b6b5b4b3 \n\ +psllw $2,%%mm2 # ________ ____g7g6 g5g4g3__ ________ \n\ +por %%mm2, %%mm0 # r7r6r5r4 r3__g7g6 g5g4g3b7 b6b5b4b3 \n\ +movq 8(%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movq %%mm0, (%3) # store pixel 0-3 \n\ + \n\ +# convert rgb24 plane to rgb16 pack for pixel 0-3 \n\ +punpckhbw %%mm4, %%mm7 # ________ ________ g7g6g5g4 g3______ \n\ +punpckhbw %%mm1, %%mm5 # r7r6r5r4 r3______ ______b7 b6b5b4b3 \n\ +psllw $2,%%mm7 # ________ ____g7g6 g5g4g3__ ________ \n\ +movd 4(%1), %%mm0 # Load 4 Cb __ __ __ __ u3 u2 u1 u0 \n\ +por %%mm7, %%mm5 # r7r6r5r4 r3__g7g6 g5g4g3b7 b6b5b4b3 \n\ +movd 4(%2), %%mm1 # Load 4 Cr __ __ __ __ v3 v2 v1 v0 \n\ +movq %%mm5, 8(%3) # store pixel 4-7 \n\ +" + +/* + * convert RGB plane to RGB 16 bits, + * mm0 -> B, mm1 -> R, mm2 -> G, + * mm4 -> GB, mm5 -> AR pixel 4-7, + * mm6 -> GB, mm7 -> AR pixel 0-3 + */ + +#define MMX_UNPACK_16 " \n\ +# mask unneeded bits off \n\ +pand mmx_mask_f8, %%mm0 # b7b6b5b4 b3______ b7b6b5b4 b3______ \n\ +pand mmx_mask_fc, %%mm2 # g7g6g5g4 g3g2____ g7g6g5g4 g3g2____ \n\ +pand mmx_mask_f8, %%mm1 # r7r6r5r4 r3______ r7r6r5r4 r3______ \n\ +psrlw $3,%%mm0 # ______b7 b6b5b4b3 ______b7 b6b5b4b3 \n\ +pxor %%mm4, %%mm4 # zero mm4 \n\ +movq %%mm0, %%mm5 # Copy B7-B0 \n\ +movq %%mm2, %%mm7 # Copy G7-G0 \n\ + \n\ +# convert rgb24 plane to rgb16 pack for pixel 0-3 \n\ +punpcklbw %%mm4, %%mm2 # ________ ________ g7g6g5g4 g3g2____ \n\ +punpcklbw %%mm1, %%mm0 # r7r6r5r4 r3______ ______b7 b6b5b4b3 \n\ +psllw $3,%%mm2 # ________ __g7g6g5 g4g3g2__ ________ \n\ +por %%mm2, %%mm0 # r7r6r5r4 r3g7g6g5 g4g3g2b7 b6b5b4b3 \n\ +movq 8(%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movq %%mm0, (%3) # store pixel 0-3 \n\ + \n\ +# convert rgb24 plane to rgb16 pack for pixel 0-3 \n\ +punpckhbw %%mm4, %%mm7 # ________ ________ g7g6g5g4 g3g2____ \n\ +punpckhbw %%mm1, %%mm5 # r7r6r5r4 r3______ ______b7 b6b5b4b3 \n\ +psllw $3,%%mm7 # ________ __g7g6g5 g4g3g2__ ________ \n\ +movd 4(%1), %%mm0 # Load 4 Cb __ __ __ __ u3 u2 u1 u0 \n\ +por %%mm7, %%mm5 # r7r6r5r4 r3g7g6g5 g4g3g2b7 b6b5b4b3 \n\ +movd 4(%2), %%mm1 # Load 4 Cr __ __ __ __ v3 v2 v1 v0 \n\ +movq %%mm5, 8(%3) # store pixel 4-7 \n\ +" + +/* + * convert RGB plane to RGB packed format, + * mm0 -> B, mm1 -> R, mm2 -> G, mm3 -> 0, + * mm4 -> GB, mm5 -> AR pixel 4-7, + * mm6 -> GB, mm7 -> AR pixel 0-3 + */ + +#define MMX_UNPACK_32 " \n\ +pxor %%mm3, %%mm3 # zero mm3 \n\ +movq %%mm0, %%mm6 # B7 B6 B5 B4 B3 B2 B1 B0 \n\ +movq %%mm1, %%mm7 # R7 R6 R5 R4 R3 R2 R1 R0 \n\ +movq %%mm0, %%mm4 # B7 B6 B5 B4 B3 B2 B1 B0 \n\ +movq %%mm1, %%mm5 # R7 R6 R5 R4 R3 R2 R1 R0 \n\ +punpcklbw %%mm2, %%mm6 # G3 B3 G2 B2 G1 B1 G0 B0 \n\ +punpcklbw %%mm3, %%mm7 # 00 R3 00 R2 00 R1 00 R0 \n\ +punpcklwd %%mm7, %%mm6 # 00 R1 B1 G1 00 R0 B0 G0 \n\ +movq %%mm6, (%3) # Store ARGB1 ARGB0 \n\ +movq %%mm0, %%mm6 # B7 B6 B5 B4 B3 B2 B1 B0 \n\ +punpcklbw %%mm2, %%mm6 # G3 B3 G2 B2 G1 B1 G0 B0 \n\ +punpckhwd %%mm7, %%mm6 # 00 R3 G3 B3 00 R2 B3 G2 \n\ +movq %%mm6, 8(%3) # Store ARGB3 ARGB2 \n\ +punpckhbw %%mm2, %%mm4 # G7 B7 G6 B6 G5 B5 G4 B4 \n\ +punpckhbw %%mm3, %%mm5 # 00 R7 00 R6 00 R5 00 R4 \n\ +punpcklwd %%mm5, %%mm4 # 00 R5 B5 G5 00 R4 B4 G4 \n\ +movq %%mm4, 16(%3) # Store ARGB5 ARGB4 \n\ +movq %%mm0, %%mm4 # B7 B6 B5 B4 B3 B2 B1 B0 \n\ +punpckhbw %%mm2, %%mm4 # G7 B7 G6 B6 G5 B5 G4 B4 \n\ +punpckhwd %%mm5, %%mm4 # 00 R7 G7 B7 00 R6 B6 G6 \n\ +movq %%mm4, 24(%3) # Store ARGB7 ARGB6 \n\ + \n\ +#movd 4(%1), %%mm0 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +#movd 4(%2), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +#pxor %%mm4, %%mm4 # zero mm4 \n\ +#movq 8(%0), %%mm6 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +" + diff --git a/modules/video_chroma/i420_ymga.c b/modules/video_chroma/i420_ymga.c new file mode 100644 index 0000000000..14341bfd47 --- /dev/null +++ b/modules/video_chroma/i420_ymga.c @@ -0,0 +1,150 @@ +/***************************************************************************** + * i420_ymga.c : YUV to YUV conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: i420_ymga.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#define SRC_FOURCC "I420,IYUV,YV12" +#define DEST_FOURCC "YMGA" + +/***************************************************************************** + * Local and extern prototypes. + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static void I420_YMGA ( vout_thread_t *, picture_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#if defined (MODULE_NAME_IS_i420_ymga) + set_description( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 80 ); +#elif defined (MODULE_NAME_IS_i420_ymga_mmx) + set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 100 ); + add_requirement( MMX ); +#endif + set_callbacks( Activate, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Activate: allocate a chroma function + ***************************************************************************** + * This function allocates and initializes a chroma function + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 ) + { + return -1; + } + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('Y','V','1','2'): + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('Y','M','G','A'): + p_vout->chroma.pf_convert = I420_YMGA; + break; + + default: + return -1; + } + break; + + default: + return -1; + } + + return 0; +} + +/* Following functions are local */ + +/***************************************************************************** + * I420_YMGA: planar YUV 4:2:0 to Matrox's planar/packed YUV 4:2:0 + *****************************************************************************/ +static void I420_YMGA( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_uv = p_dest->U_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x; + + /* Copy the Y part */ + p_vout->p_vlc->pf_memcpy( p_dest->Y_PIXELS, p_source->Y_PIXELS, + p_dest->p[Y_PLANE].i_pitch * p_dest->p[Y_PLANE].i_lines ); + + /* Copy the U:V part */ + for( i_x = p_dest->p[U_PLANE].i_pitch * p_dest->p[U_PLANE].i_lines / 64; + i_x--; ) + { +#if defined (MODULE_NAME_IS_i420_ymga) + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; + *p_uv++ = *p_u++; *p_uv++ = *p_v++; *p_uv++ = *p_u++; *p_uv++ = *p_v++; +#else + __asm__( ".align 32 \n\ + movd (%0), %%mm0 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ + movd 4(%0), %%mm2 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ + movd 8(%0), %%mm4 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ + movd 12(%0), %%mm6 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ + movd (%1), %%mm1 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ + movd 4(%1), %%mm3 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ + movd 8(%1), %%mm5 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ + movd 12(%1), %%mm7 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ + punpcklbw %%mm1, %%mm0 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ + punpcklbw %%mm3, %%mm2 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ + punpcklbw %%mm5, %%mm4 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ + punpcklbw %%mm7, %%mm6 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ + movq %%mm0, (%2) # Store CrCb \n\ + movq %%mm2, 8(%2) # Store CrCb \n\ + movq %%mm4, 16(%2) # Store CrCb \n\ + movq %%mm6, 24(%2) # Store CrCb" + : : "r" (p_v), "r" (p_u), "r" (p_uv) ); + + p_v += 16; p_u += 16; p_uv += 32; +#endif + } +} + diff --git a/modules/video_chroma/i420_yuy2.c b/modules/video_chroma/i420_yuy2.c new file mode 100644 index 0000000000..9aa3acb5cd --- /dev/null +++ b/modules/video_chroma/i420_yuy2.c @@ -0,0 +1,377 @@ +/***************************************************************************** + * i420_yuy2.c : YUV to YUV conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: i420_yuy2.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#include "i420_yuy2.h" + +#define SRC_FOURCC "I420,IYUV,YV12" + +#if defined (MODULE_NAME_IS_i420_yuy2) +# define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211" +#else +# define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv" +#endif + +/***************************************************************************** + * Local and extern prototypes. + *****************************************************************************/ +static int Activate ( vlc_object_t * ); + +static void I420_YUY2 ( vout_thread_t *, picture_t *, picture_t * ); +static void I420_YVYU ( vout_thread_t *, picture_t *, picture_t * ); +static void I420_UYVY ( vout_thread_t *, picture_t *, picture_t * ); +static void I420_IUYV ( vout_thread_t *, picture_t *, picture_t * ); +static void I420_cyuv ( vout_thread_t *, picture_t *, picture_t * ); +#if defined (MODULE_NAME_IS_i420_yuy2) +static void I420_Y211 ( vout_thread_t *, picture_t *, picture_t * ); +#endif + +#ifdef MODULE_NAME_IS_i420_yuy2_mmx +static unsigned long long i_00ffw; +static unsigned long long i_80w; +#endif + +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin(); +#if defined (MODULE_NAME_IS_i420_yuy2) + set_description( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 80 ); +#elif defined (MODULE_NAME_IS_i420_yuy2_mmx) + set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 100 ); + add_requirement( MMX ); + /* Initialize MMX-specific constants */ + i_00ffw = 0x00ff00ff00ff00ff; + i_80w = 0x0000000080808080; +#endif + set_callbacks( Activate, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Activate: allocate a chroma function + ***************************************************************************** + * This function allocates and initializes a chroma function + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 ) + { + return -1; + } + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('Y','V','1','2'): + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('Y','U','Y','2'): + case VLC_FOURCC('Y','U','N','V'): + p_vout->chroma.pf_convert = I420_YUY2; + break; + + case VLC_FOURCC('Y','V','Y','U'): + p_vout->chroma.pf_convert = I420_YVYU; + break; + + case VLC_FOURCC('U','Y','V','Y'): + case VLC_FOURCC('U','Y','N','V'): + case VLC_FOURCC('Y','4','2','2'): + p_vout->chroma.pf_convert = I420_UYVY; + break; + + case VLC_FOURCC('I','U','Y','V'): + p_vout->chroma.pf_convert = I420_IUYV; + break; + + case VLC_FOURCC('c','y','u','v'): + p_vout->chroma.pf_convert = I420_cyuv; + break; + +#if defined (MODULE_NAME_IS_i420_yuy2) + case VLC_FOURCC('Y','2','1','1'): + p_vout->chroma.pf_convert = I420_Y211; + break; +#endif + + default: + return -1; + } + break; + + default: + return -1; + } + + return 0; +} + +/* Following functions are local */ + +/***************************************************************************** + * I420_YUY2: planar YUV 4:2:0 to packed YUYV 4:2:2 + *****************************************************************************/ +static void I420_YUY2( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line1, *p_line2 = p_dest->p->p_pixels; + u8 *p_y1, *p_y2 = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + const int i_source_margin = p_source->p->i_pitch + - p_source->p->i_visible_pitch; + const int i_dest_margin = p_dest->p->i_pitch + - p_dest->p->i_visible_pitch; + + for( i_y = p_vout->render.i_height / 2 ; i_y-- ; ) + { + p_line1 = p_line2; + p_line2 += p_dest->p->i_pitch; + + p_y1 = p_y2; + p_y2 += p_source->p[Y_PLANE].i_pitch; + + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i420_yuy2) + C_YUV420_YUYV( ); + C_YUV420_YUYV( ); + C_YUV420_YUYV( ); + C_YUV420_YUYV( ); +#else + MMX_CALL( MMX_YUV420_YUYV ); +#endif + } + + p_y1 += i_source_margin; + p_y2 += i_source_margin; + p_line1 += i_dest_margin; + p_line2 += i_dest_margin; + } +} + +/***************************************************************************** + * I420_YVYU: planar YUV 4:2:0 to packed YVYU 4:2:2 + *****************************************************************************/ +static void I420_YVYU( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line1, *p_line2 = p_dest->p->p_pixels; + u8 *p_y1, *p_y2 = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + const int i_source_margin = p_source->p->i_pitch + - p_source->p->i_visible_pitch; + const int i_dest_margin = p_dest->p->i_pitch + - p_dest->p->i_visible_pitch; + + for( i_y = p_vout->render.i_height / 2 ; i_y-- ; ) + { + p_line1 = p_line2; + p_line2 += p_dest->p->i_pitch; + + p_y1 = p_y2; + p_y2 += p_source->p[Y_PLANE].i_pitch; + + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i420_yuy2) + C_YUV420_YVYU( ); + C_YUV420_YVYU( ); + C_YUV420_YVYU( ); + C_YUV420_YVYU( ); +#else + MMX_CALL( MMX_YUV420_YVYU ); +#endif + } + + p_y1 += i_source_margin; + p_y2 += i_source_margin; + p_line1 += i_dest_margin; + p_line2 += i_dest_margin; + } +} + +/***************************************************************************** + * I420_UYVY: planar YUV 4:2:0 to packed UYVY 4:2:2 + *****************************************************************************/ +static void I420_UYVY( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line1, *p_line2 = p_dest->p->p_pixels; + u8 *p_y1, *p_y2 = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + const int i_source_margin = p_source->p->i_pitch + - p_source->p->i_visible_pitch; + const int i_dest_margin = p_dest->p->i_pitch + - p_dest->p->i_visible_pitch; + + for( i_y = p_vout->render.i_height / 2 ; i_y-- ; ) + { + p_line1 = p_line2; + p_line2 += p_dest->p->i_pitch; + + p_y1 = p_y2; + p_y2 += p_source->p[Y_PLANE].i_pitch; + + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i420_yuy2) + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); +#else + MMX_CALL( MMX_YUV420_UYVY ); +#endif + } + + p_y1 += i_source_margin; + p_y2 += i_source_margin; + p_line1 += i_dest_margin; + p_line2 += i_dest_margin; + } +} + +/***************************************************************************** + * I420_IUYV: planar YUV 4:2:0 to interleaved packed UYVY 4:2:2 + *****************************************************************************/ +static void I420_IUYV( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + /* FIXME: TODO ! */ + msg_Err( p_vout, "I420_IUYV unimplemented, please harass " ); +} + +/***************************************************************************** + * I420_cyuv: planar YUV 4:2:0 to upside-down packed UYVY 4:2:2 + *****************************************************************************/ +static void I420_cyuv( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line1 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch + + p_dest->p->i_pitch; + u8 *p_line2 = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch; + u8 *p_y1, *p_y2 = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + const int i_source_margin = p_source->p->i_pitch + - p_source->p->i_visible_pitch; + const int i_dest_margin = p_dest->p->i_pitch + - p_dest->p->i_visible_pitch; + + for( i_y = p_vout->render.i_height / 2 ; i_y-- ; ) + { + p_line1 -= 3 * p_dest->p->i_pitch; + p_line2 -= 3 * p_dest->p->i_pitch; + + p_y1 = p_y2; + p_y2 += p_source->p[Y_PLANE].i_pitch; + + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i420_yuy2) + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); + C_YUV420_UYVY( ); +#else + MMX_CALL( MMX_YUV420_UYVY ); +#endif + } + + p_y1 += i_source_margin; + p_y2 += i_source_margin; + p_line1 += i_dest_margin; + p_line2 += i_dest_margin; + } +} + +/***************************************************************************** + * I420_Y211: planar YUV 4:2:0 to packed YUYV 2:1:1 + *****************************************************************************/ +#if defined (MODULE_NAME_IS_i420_yuy2) +static void I420_Y211( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line1, *p_line2 = p_dest->p->p_pixels; + u8 *p_y1, *p_y2 = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + const int i_source_margin = p_source->p->i_pitch + - p_source->p->i_visible_pitch; + const int i_dest_margin = p_dest->p->i_pitch + - p_dest->p->i_visible_pitch; + + for( i_y = p_vout->render.i_height / 2 ; i_y-- ; ) + { + p_line1 = p_line2; + p_line2 += p_dest->p->i_pitch; + + p_y1 = p_y2; + p_y2 += p_source->p[Y_PLANE].i_pitch; + + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { + C_YUV420_Y211( ); + C_YUV420_Y211( ); + } + + p_y1 += i_source_margin; + p_y2 += i_source_margin; + p_line1 += i_dest_margin; + p_line2 += i_dest_margin; + } +} +#endif + diff --git a/modules/video_chroma/i420_yuy2.h b/modules/video_chroma/i420_yuy2.h new file mode 100644 index 0000000000..f56f6c5e64 --- /dev/null +++ b/modules/video_chroma/i420_yuy2.h @@ -0,0 +1,143 @@ +/***************************************************************************** + * i420_yuy2.h : YUV to YUV conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: i420_yuy2.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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. + *****************************************************************************/ + +#ifdef MODULE_NAME_IS_i420_yuy2_mmx + +#define MMX_CALL(MMX_INSTRUCTIONS) \ + do { \ + __asm__ __volatile__( \ + ".align 8 \n\t" \ + MMX_INSTRUCTIONS \ + : \ + : "r" (p_line1), "r" (p_line2), "r" (p_y1), "r" (p_y2), \ + "r" (p_u), "r" (p_v) ); \ + p_line1 += 16; p_line2 += 16; p_y1 += 8; p_y2 += 8; p_u += 4; p_v += 4; \ + } while(0); \ + +#define MMX_YUV420_YUYV " \n\ +movq (%2), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movd (%4), %%mm1 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%5), %%mm2 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # v3 u3 v2 u2 v1 u1 v0 u0 \n\ +movq %%mm0, %%mm2 # y7 y6 y5 y4 y3 y2 y1 y0 \n\ +punpcklbw %%mm1, %%mm2 # v1 y3 u1 y2 v0 y1 u0 y0 \n\ +movq %%mm2, (%0) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # v3 y7 u3 y6 v2 y5 u2 y4 \n\ +movq %%mm0, 8(%0) # Store high YUYV \n\ +movq (%3), %%mm0 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movq %%mm0, %%mm2 # Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +punpcklbw %%mm1, %%mm2 # v1 Y3 u1 Y2 v0 Y1 u0 Y0 \n\ +movq %%mm2, (%1) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # v3 Y7 u3 Y6 v2 Y5 u2 Y4 \n\ +movq %%mm0, 8(%1) # Store high YUYV \n\ +" + +#define MMX_YUV420_YVYU " \n\ +movq (%2), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movd (%4), %%mm2 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%5), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +movq %%mm0, %%mm2 # y7 y6 y5 y4 y3 y2 y1 y0 \n\ +punpcklbw %%mm1, %%mm2 # u1 y3 v1 y2 u0 y1 v0 y0 \n\ +movq %%mm2, (%0) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # u3 y7 v3 y6 u2 y5 v2 y4 \n\ +movq %%mm0, 8(%0) # Store high YUYV \n\ +movq (%3), %%mm0 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movq %%mm0, %%mm2 # Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +punpcklbw %%mm1, %%mm2 # u1 Y3 v1 Y2 u0 Y1 v0 Y0 \n\ +movq %%mm2, (%1) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # u3 Y7 v3 Y6 u2 Y5 v2 Y4 \n\ +movq %%mm0, 8(%1) # Store high YUYV \n\ +" + +#define MMX_YUV420_UYVY " \n\ +movq (%2), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movq (%3), %%mm3 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movd (%4), %%mm2 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%5), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +movq %%mm1, %%mm2 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +punpcklbw %%mm0, %%mm2 # y3 v1 y2 u1 y1 v0 y0 u0 \n\ +movq %%mm2, (%0) # Store low UYVY \n\ +movq %%mm1, %%mm2 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +punpckhbw %%mm0, %%mm2 # y3 v1 y2 u1 y1 v0 y0 u0 \n\ +movq %%mm2, 8(%0) # Store high UYVY \n\ +movq %%mm1, %%mm2 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +punpcklbw %%mm3, %%mm2 # Y3 v1 Y2 u1 Y1 v0 Y0 u0 \n\ +movq %%mm2, (%1) # Store low UYVY \n\ +punpckhbw %%mm3, %%mm1 # Y7 v3 Y6 u3 Y5 v2 Y4 u2 \n\ +movq %%mm1, 8(%1) # Store high UYVY \n\ +" + +/* FIXME: this code does not work ! Chroma seems to be wrong. */ +#define MMX_YUV420_Y211 " \n\ +movq (%2), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movq (%3), %%mm1 # Load 8 Y Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 \n\ +movd (%4), %%mm2 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%5), %%mm3 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +pand i_00ffw, %%mm0 # get Y even 00 Y6 00 Y4 00 Y2 00 Y0 \n\ +packuswb %%mm0, %%mm0 # pack Y y6 y4 y2 y0 y6 y4 y2 y0 \n\ +pand i_00ffw, %%mm2 # get U even 00 u6 00 u4 00 u2 00 u0 \n\ +packuswb %%mm2, %%mm2 # pack U 00 00 u2 u0 00 00 u2 u0 \n\ +pand i_00ffw, %%mm3 # get V even 00 v6 00 v4 00 v2 00 v0 \n\ +packuswb %%mm3, %%mm3 # pack V 00 00 v2 v0 00 00 v2 v0 \n\ +punpcklbw %%mm3, %%mm2 # 00 00 00 00 v2 u2 v0 u0 \n\ +psubsw i_80w, %%mm2 # U,V -= 128 \n\ +punpcklbw %%mm2, %%mm0 # v2 y6 u2 y4 v0 y2 u0 y0 \n\ +movq %%mm0, (%0) # Store YUYV \n\ +pand i_00ffw, %%mm1 # get Y even 00 Y6 00 Y4 00 Y2 00 Y0 \n\ +packuswb %%mm1, %%mm1 # pack Y Y6 Y4 Y2 Y0 Y6 Y4 Y2 Y0 \n\ +punpcklbw %%mm2, %%mm1 # v2 Y6 u2 Y4 v0 Y2 u0 Y0 \n\ +movq %%mm1, (%1) # Store YUYV \n\ +" + +#else + +#define C_YUV420_YUYV( ) \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_u)++; \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_v)++; \ + +#define C_YUV420_YVYU( ) \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_v)++; \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_u)++; \ + +#define C_YUV420_UYVY( ) \ + *(p_line1)++ = *(p_line2)++ = *(p_u)++; \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_v)++; \ + *(p_line1)++ = *(p_y1)++; *(p_line2)++ = *(p_y2)++; \ + +#define C_YUV420_Y211( ) \ + *(p_line1)++ = *(p_y1); ((u16*)p_y1)++; \ + *(p_line2)++ = *(p_y2); ((u16*)p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_u) - 0x80; ((u16*)p_u)++; \ + *(p_line1)++ = *(p_y1); ((u16*)p_y1)++; \ + *(p_line2)++ = *(p_y2); ((u16*)p_y2)++; \ + *(p_line1)++ = *(p_line2)++ = *(p_v) - 0x80; ((u16*)p_v)++; \ + +#endif + diff --git a/modules/video_chroma/i422_yuy2.c b/modules/video_chroma/i422_yuy2.c new file mode 100644 index 0000000000..2b50b840a3 --- /dev/null +++ b/modules/video_chroma/i422_yuy2.c @@ -0,0 +1,318 @@ +/***************************************************************************** + * i422_yuy2.c : YUV to YUV conversion module for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: i422_yuy2.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* strerror() */ +#include /* malloc(), free() */ + +#include +#include + +#include "i422_yuy2.h" + +#define SRC_FOURCC "I422" +#if defined (MODULE_NAME_IS_i422_yuy2) +# define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv,Y211" +#else +# define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,IUYV,cyuv" +#endif + +/***************************************************************************** + * Local and extern prototypes. + *****************************************************************************/ +static int Activate ( vlc_object_t * ); + +static void I422_YUY2 ( vout_thread_t *, picture_t *, picture_t * ); +static void I422_YVYU ( vout_thread_t *, picture_t *, picture_t * ); +static void I422_UYVY ( vout_thread_t *, picture_t *, picture_t * ); +static void I422_IUYV ( vout_thread_t *, picture_t *, picture_t * ); +static void I422_cyuv ( vout_thread_t *, picture_t *, picture_t * ); +#if defined (MODULE_NAME_IS_i422_yuy2) +static void I422_Y211 ( vout_thread_t *, picture_t *, picture_t * ); +#endif + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); +#if defined (MODULE_NAME_IS_i422_yuy2) + set_description( _("conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 80 ); +#elif defined (MODULE_NAME_IS_i422_yuy2_mmx) + set_description( _("MMX conversions from " SRC_FOURCC " to " DEST_FOURCC) ); + set_capability( "chroma", 100 ); + add_requirement( MMX ); +#endif + set_callbacks( Activate, NULL ); +vlc_module_end(); + +/***************************************************************************** + * Activate: allocate a chroma function + ***************************************************************************** + * This function allocates and initializes a chroma function + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + if( p_vout->render.i_width & 1 || p_vout->render.i_height & 1 ) + { + return -1; + } + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('I','4','2','2'): + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('Y','U','Y','2'): + case VLC_FOURCC('Y','U','N','V'): + p_vout->chroma.pf_convert = I422_YUY2; + break; + + case VLC_FOURCC('Y','V','Y','U'): + p_vout->chroma.pf_convert = I422_YVYU; + break; + + case VLC_FOURCC('U','Y','V','Y'): + case VLC_FOURCC('U','Y','N','V'): + case VLC_FOURCC('Y','4','2','2'): + p_vout->chroma.pf_convert = I422_UYVY; + break; + + case VLC_FOURCC('I','U','Y','V'): + p_vout->chroma.pf_convert = I422_IUYV; + break; + + case VLC_FOURCC('c','y','u','v'): + p_vout->chroma.pf_convert = I422_cyuv; + break; + +#if defined (MODULE_NAME_IS_i422_yuy2) + case VLC_FOURCC('Y','2','1','1'): + p_vout->chroma.pf_convert = I422_Y211; + break; +#endif + + default: + return -1; + } + break; + + default: + return -1; + } + + return 0; +} + +/* Following functions are local */ + +/***************************************************************************** + * I422_YUY2: planar YUV 4:2:2 to packed YUY2 4:2:2 + *****************************************************************************/ +static void I422_YUY2( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line = p_dest->p->p_pixels; + u8 *p_y = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + for( i_y = p_vout->render.i_height ; i_y-- ; ) + { + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i422_yuy2) + C_YUV422_YUYV( p_line, p_y, p_u, p_v ); + C_YUV422_YUYV( p_line, p_y, p_u, p_v ); + C_YUV422_YUYV( p_line, p_y, p_u, p_v ); + C_YUV422_YUYV( p_line, p_y, p_u, p_v ); +#else + __asm__( ".align 8" MMX_YUV422_YUYV + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; + + __asm__( ".align 8" MMX_YUV422_YUYV + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; +#endif + } + } +} + +/***************************************************************************** + * I422_YVYU: planar YUV 4:2:2 to packed YVYU 4:2:2 + *****************************************************************************/ +static void I422_YVYU( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line = p_dest->p->p_pixels; + u8 *p_y = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + for( i_y = p_vout->render.i_height ; i_y-- ; ) + { + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i422_yuy2) + C_YUV422_YVYU( p_line, p_y, p_u, p_v ); + C_YUV422_YVYU( p_line, p_y, p_u, p_v ); + C_YUV422_YVYU( p_line, p_y, p_u, p_v ); + C_YUV422_YVYU( p_line, p_y, p_u, p_v ); +#else + __asm__( ".align 8" MMX_YUV422_YVYU + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; + + __asm__( ".align 8" MMX_YUV422_YVYU + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; +#endif + } + } +} + +/***************************************************************************** + * I422_UYVY: planar YUV 4:2:2 to packed UYVY 4:2:2 + *****************************************************************************/ +static void I422_UYVY( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line = p_dest->p->p_pixels; + u8 *p_y = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + for( i_y = p_vout->render.i_height ; i_y-- ; ) + { + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { +#if defined (MODULE_NAME_IS_i422_yuy2) + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); +#else + __asm__( ".align 8" MMX_YUV422_UYVY + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; + + __asm__( ".align 8" MMX_YUV422_UYVY + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; +#endif + } + } +} + +/***************************************************************************** + * I422_IUYV: planar YUV 4:2:2 to interleaved packed IUYV 4:2:2 + *****************************************************************************/ +static void I422_IUYV( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + /* FIXME: TODO ! */ + msg_Err( p_vout, "I422_IUYV unimplemented, please harass " ); +} + +/***************************************************************************** + * I422_cyuv: planar YUV 4:2:2 to upside-down packed UYVY 4:2:2 + *****************************************************************************/ +static void I422_cyuv( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch; + u8 *p_y = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + for( i_y = p_vout->render.i_height ; i_y-- ; ) + { + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { + p_line -= 2 * p_dest->p->i_pitch; + +#if defined (MODULE_NAME_IS_i422_yuy2) + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); + C_YUV422_UYVY( p_line, p_y, p_u, p_v ); +#else + __asm__( ".align 8" MMX_YUV422_UYVY + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; + + __asm__( ".align 8" MMX_YUV422_UYVY + : : "r" (p_line), "r" (p_y), "r" (p_u), "r" (p_v) ); + + p_line += 8; p_y += 4; p_u += 2; p_v += 2; +#endif + } + } +} + +/***************************************************************************** + * I422_Y211: planar YUV 4:2:2 to packed YUYV 2:1:1 + *****************************************************************************/ +#if defined (MODULE_NAME_IS_i422_yuy2) +static void I422_Y211( vout_thread_t *p_vout, picture_t *p_source, + picture_t *p_dest ) +{ + u8 *p_line = p_dest->p->p_pixels + p_dest->p->i_lines * p_dest->p->i_pitch; + u8 *p_y = p_source->Y_PIXELS; + u8 *p_u = p_source->U_PIXELS; + u8 *p_v = p_source->V_PIXELS; + + int i_x, i_y; + + for( i_y = p_vout->render.i_height ; i_y-- ; ) + { + for( i_x = p_vout->render.i_width / 8 ; i_x-- ; ) + { + C_YUV422_Y211( p_line, p_y, p_u, p_v ); + C_YUV422_Y211( p_line, p_y, p_u, p_v ); + } + } +} +#endif + diff --git a/modules/video_chroma/i422_yuy2.h b/modules/video_chroma/i422_yuy2.h new file mode 100644 index 0000000000..1ce334eb88 --- /dev/null +++ b/modules/video_chroma/i422_yuy2.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * i422_yuy2.h : YUV to YUV conversion module for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: i422_yuy2.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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. + *****************************************************************************/ + +#ifdef MODULE_NAME_IS_i422_yuy2_mmx + +#define MMX_YUV422_YUYV " \n\ +movq (%1), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movd (%2), %%mm1 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%3), %%mm2 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # v3 u3 v2 u2 v1 u1 v0 u0 \n\ +movq %%mm0, %%mm2 # y7 y6 y5 y4 y3 y2 y1 y0 \n\ +punpcklbw %%mm1, %%mm2 # v1 y3 u1 y2 v0 y1 u0 y0 \n\ +movq %%mm2, (%0) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # v3 y7 u3 y6 v2 y5 u2 y4 \n\ +movq %%mm0, 8(%0) # Store high YUYV \n\ +" + +#define MMX_YUV422_YVYU " \n\ +movq (%1), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movd (%2), %%mm2 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%3), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +movq %%mm0, %%mm2 # y7 y6 y5 y4 y3 y2 y1 y0 \n\ +punpcklbw %%mm1, %%mm2 # u1 y3 v1 y2 u0 y1 v0 y0 \n\ +movq %%mm2, (%0) # Store low YUYV \n\ +punpckhbw %%mm1, %%mm0 # u3 y7 v3 y6 u2 y5 v2 y4 \n\ +movq %%mm0, 8(%0) # Store high YUYV \n\ +" + +#define MMX_YUV422_UYVY " \n\ +movq (%1), %%mm0 # Load 8 Y y7 y6 y5 y4 y3 y2 y1 y0 \n\ +movd (%2), %%mm2 # Load 4 Cb 00 00 00 00 u3 u2 u1 u0 \n\ +movd (%3), %%mm1 # Load 4 Cr 00 00 00 00 v3 v2 v1 v0 \n\ +punpcklbw %%mm2, %%mm1 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +movq %%mm1, %%mm2 # u3 v3 u2 v2 u1 v1 u0 v0 \n\ +punpcklbw %%mm0, %%mm2 # y3 v1 y2 u1 y1 v0 y0 u0 \n\ +movq %%mm2, (%0) # Store low UYVY \n\ +punpckhbw %%mm0, %%mm1 # y7 v3 y6 u3 y5 v2 y4 u2 \n\ +movq %%mm1, 8(%0) # Store high UYVY \n\ +" + +#define MMX_YUV422_Y211 " \n\ +" + +#else + +#define C_YUV422_YUYV( p_line, p_y, p_u, p_v ) \ + *(p_line)++ = *(p_y)++; \ + *(p_line)++ = *(p_u)++; \ + *(p_line)++ = *(p_y)++; \ + *(p_line)++ = *(p_v)++; \ + +#define C_YUV422_YVYU( p_line, p_y, p_u, p_v ) \ + *(p_line)++ = *(p_y)++; \ + *(p_line)++ = *(p_v)++; \ + *(p_line)++ = *(p_y)++; \ + *(p_line)++ = *(p_u)++; \ + +#define C_YUV422_UYVY( p_line, p_y, p_u, p_v ) \ + *(p_line)++ = *(p_u)++; \ + *(p_line)++ = *(p_y)++; \ + *(p_line)++ = *(p_v)++; \ + *(p_line)++ = *(p_y)++; \ + +#define C_YUV422_Y211( p_line, p_y, p_u, p_v ) \ + *(p_line)++ = *(p_y); ((u16*)p_y)++; \ + *(p_line)++ = *(p_u) - 0x80; ((u16*)p_u)++; \ + *(p_line)++ = *(p_y); ((u16*)p_y)++; \ + *(p_line)++ = *(p_v) - 0x80; ((u16*)p_v)++; \ + +#endif + diff --git a/modules/video_filter/.cvsignore b/modules/video_filter/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_filter/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_filter/Makefile b/modules/video_filter/Makefile new file mode 100644 index 0000000000..a49a4798e7 --- /dev/null +++ b/modules/video_filter/Makefile @@ -0,0 +1,6 @@ +transform_SOURCES = transform.c +invert_SOURCES = invert.c +distort_SOURCES = distort.c +wall_SOURCES = wall.c +clone_SOURCES = clone.c +crop_SOURCES = crop.c diff --git a/modules/video_filter/clone.c b/modules/video_filter/clone.c new file mode 100644 index 0000000000..0607658613 --- /dev/null +++ b/modules/video_filter/clone.c @@ -0,0 +1,257 @@ +/***************************************************************************** + * clone.c : Clone video plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: clone.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "filter_common.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +static void RemoveAllVout ( vout_thread_t *p_vout ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define COUNT_TEXT N_("Number of clones") +#define COUNT_LONGTEXT N_("Select the number of video windows in which to "\ + "clone the video") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_integer( "clone-count", 2, NULL, COUNT_TEXT, COUNT_LONGTEXT ); + set_description( _("image clone video module") ); + set_capability( "video filter", 0 ); + add_shortcut( "clone" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Clone video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Clone specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + int i_clones; + vout_thread_t **pp_vout; +}; + +/***************************************************************************** + * Create: allocates Clone video thread output method + ***************************************************************************** + * This function allocates and initializes a Clone vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + /* Look what method was requested */ + p_vout->p_sys->i_clones = config_GetInt( p_vout, "clone-count" ); + + p_vout->p_sys->i_clones = __MAX( 1, __MIN( 99, p_vout->p_sys->i_clones ) ); + + msg_Dbg( p_vout, "spawning %i clone(s)", p_vout->p_sys->i_clones ); + + p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_clones * + sizeof(vout_thread_t *) ); + if( p_vout->p_sys->pp_vout == NULL ) + { + msg_Err( p_vout, "out of memory" ); + free( p_vout->p_sys ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Clone video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index, i_vout; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Try to open the real video output */ + msg_Dbg( p_vout, "spawning the real video outputs" ); + + for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ ) + { + p_vout->p_sys->pp_vout[ i_vout ] = + vout_CreateThread( p_vout, + p_vout->render.i_width, p_vout->render.i_height, + p_vout->render.i_chroma, p_vout->render.i_aspect ); + if( p_vout->p_sys->pp_vout[ i_vout ] == NULL ) + { + msg_Err( p_vout, "failed to clone %i vout threads", + p_vout->p_sys->i_clones ); + p_vout->p_sys->i_clones = i_vout; + RemoveAllVout( p_vout ); + return 0; + } + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Clone video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Clone video thread output method + ***************************************************************************** + * Terminate an output method created by CloneCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + RemoveAllVout( p_vout ); + + free( p_vout->p_sys->pp_vout ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Clone image, waits + * until it is displayed and switch the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic = NULL; + int i_vout, i_plane; + + for( i_vout = 0; i_vout < p_vout->p_sys->i_clones; i_vout++ ) + { + while( ( p_outpic = + vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ], 0, 0, 0 ) + ) == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + vout_DestroyPicture( + p_vout->p_sys->pp_vout[ i_vout ], p_outpic ); + return; + } + + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ], + p_outpic, p_pic->date ); + vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic ); + + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_in_end, *p_out; + int i_in_pitch = p_pic->p[i_plane].i_pitch; + const int i_out_pitch = p_outpic->p[i_plane].i_pitch; + + p_in = p_pic->p[i_plane].p_pixels; + + p_in_end = p_in + p_outpic->p[i_plane].i_lines + * p_pic->p[i_plane].i_pitch; + + p_out = p_outpic->p[i_plane].p_pixels; + + while( p_in < p_in_end ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, i_out_pitch ); + p_in += i_in_pitch; + p_out += i_out_pitch; + } + } + + vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic ); + vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ], p_outpic ); + } +} + +/***************************************************************************** + * RemoveAllVout: destroy all the child video output threads + *****************************************************************************/ +static void RemoveAllVout( vout_thread_t *p_vout ) +{ + while( p_vout->p_sys->i_clones ) + { + --p_vout->p_sys->i_clones; + vout_DestroyThread( p_vout->p_sys->pp_vout[p_vout->p_sys->i_clones] ); + } +} + diff --git a/modules/video_filter/crop.c b/modules/video_filter/crop.c new file mode 100644 index 0000000000..8c9bc286b7 --- /dev/null +++ b/modules/video_filter/crop.c @@ -0,0 +1,461 @@ +/***************************************************************************** + * crop.c : Crop video plugin for vlc + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: crop.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "filter_common.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +static void UpdateStats ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define GEOMETRY_TEXT N_("Crop geometry") +#define GEOMETRY_LONGTEXT N_("Set the geometry of the zone to crop") + +#define AUTOCROP_TEXT N_("Automatic cropping") +#define AUTOCROP_LONGTEXT N_("Activate automatic black border cropping") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "crop-geometry", NULL, NULL, GEOMETRY_TEXT, GEOMETRY_LONGTEXT ); + add_bool( "autocrop", 0, NULL, AUTOCROP_TEXT, AUTOCROP_LONGTEXT ); + set_description( _("image crop video module") ); + set_capability( "video filter", 0 ); + add_shortcut( "crop" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Crop video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Crop specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + vout_thread_t *p_vout; + + unsigned int i_x, i_y; + unsigned int i_width, i_height, i_aspect; + + vlc_bool_t b_autocrop; + + /* Autocrop specific variables */ + unsigned int i_lastchange; + vlc_bool_t b_changed; +}; + +/***************************************************************************** + * Create: allocates Crop video thread output method + ***************************************************************************** + * This function allocates and initializes a Crop vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return 1; + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + return 0; +} + +/***************************************************************************** + * Init: initialize Crop video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + char *psz_var; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + p_vout->p_sys->i_lastchange = 0; + p_vout->p_sys->b_changed = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Shall we use autocrop ? */ + p_vout->p_sys->b_autocrop = config_GetInt( p_vout, "autocrop" ); + + /* Get geometry value from the user */ + psz_var = config_GetPsz( p_vout, "crop-geometry" ); + if( psz_var ) + { + char *psz_parser, *psz_tmp; + + psz_parser = psz_tmp = psz_var; + while( *psz_tmp && *psz_tmp != 'x' ) psz_tmp++; + + if( *psz_tmp ) + { + psz_tmp[0] = '\0'; + p_vout->p_sys->i_width = atoi( psz_parser ); + + psz_parser = ++psz_tmp; + while( *psz_tmp && *psz_tmp != '+' ) psz_tmp++; + + if( *psz_tmp ) + { + psz_tmp[0] = '\0'; + p_vout->p_sys->i_height = atoi( psz_parser ); + + psz_parser = ++psz_tmp; + while( *psz_tmp && *psz_tmp != '+' ) psz_tmp++; + + if( *psz_tmp ) + { + psz_tmp[0] = '\0'; + p_vout->p_sys->i_x = atoi( psz_parser ); + p_vout->p_sys->i_y = atoi( ++psz_tmp ); + } + else + { + p_vout->p_sys->i_x = atoi( psz_parser ); + p_vout->p_sys->i_y = + ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2; + } + } + else + { + p_vout->p_sys->i_height = atoi( psz_parser ); + p_vout->p_sys->i_x = + ( p_vout->output.i_width - p_vout->p_sys->i_width ) / 2; + p_vout->p_sys->i_y = + ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2; + } + } + else + { + p_vout->p_sys->i_width = atoi( psz_parser ); + p_vout->p_sys->i_height = p_vout->output.i_height; + p_vout->p_sys->i_x = + ( p_vout->output.i_width - p_vout->p_sys->i_width ) / 2; + p_vout->p_sys->i_y = + ( p_vout->output.i_height - p_vout->p_sys->i_height ) / 2; + } + + /* Check for validity */ + if( p_vout->p_sys->i_x + p_vout->p_sys->i_width + > p_vout->output.i_width ) + { + p_vout->p_sys->i_x = 0; + if( p_vout->p_sys->i_width > p_vout->output.i_width ) + { + p_vout->p_sys->i_width = p_vout->output.i_width; + } + } + + if( p_vout->p_sys->i_y + p_vout->p_sys->i_height + > p_vout->output.i_height ) + { + p_vout->p_sys->i_y = 0; + if( p_vout->p_sys->i_height > p_vout->output.i_height ) + { + p_vout->p_sys->i_height = p_vout->output.i_height; + } + } + + free( psz_var ); + } + else + { + p_vout->p_sys->i_width = p_vout->output.i_width; + p_vout->p_sys->i_height = p_vout->output.i_height; + p_vout->p_sys->i_x = p_vout->p_sys->i_y = 0; + } + + /* Pheeew. Parsing done. */ + msg_Dbg( p_vout, "cropping at %ix%i+%i+%i, %sautocropping", + p_vout->p_sys->i_width, p_vout->p_sys->i_height, + p_vout->p_sys->i_x, p_vout->p_sys->i_y, + p_vout->p_sys->b_autocrop ? "" : "not " ); + + /* Set current output image properties */ + p_vout->p_sys->i_aspect = p_vout->output.i_aspect + * p_vout->output.i_height / p_vout->p_sys->i_height + * p_vout->p_sys->i_width / p_vout->output.i_width; + + /* Try to open the real video output */ + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->p_sys->i_width, p_vout->p_sys->i_height, + p_vout->render.i_chroma, p_vout->p_sys->i_aspect ); + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "failed to create vout" ); + return 0; + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return 0; +} + +/***************************************************************************** + * End: terminate Crop video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Crop video thread output method + ***************************************************************************** + * Terminate an output method created by CropCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + vout_DestroyThread( p_vout->p_sys->p_vout ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle Crop events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + if( !p_vout->p_sys->b_changed ) + { + return 0; + } + + vout_DestroyThread( p_vout->p_sys->p_vout ); + + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->p_sys->i_width, p_vout->p_sys->i_height, + p_vout->render.i_chroma, p_vout->p_sys->i_aspect ); + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "failed to create vout" ); + return 1; + } + + p_vout->p_sys->b_changed = 0; + p_vout->p_sys->i_lastchange = 0; + + return 0; +} + +/***************************************************************************** + * Render: display previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to Crop image, waits + * until it is displayed and switches the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic = NULL; + int i_plane; + + if( p_vout->p_sys->b_changed ) + { + return; + } + + while( ( p_outpic = + vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) + ) == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + vout_DestroyPicture( p_vout->p_sys->p_vout, p_outpic ); + return; + } + + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date ); + vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic ); + + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_out, *p_out_end; + int i_in_pitch = p_pic->p[i_plane].i_pitch; + const int i_out_pitch = p_outpic->p[i_plane].i_pitch; + + p_in = p_pic->p[i_plane].p_pixels + /* Skip the right amount of lines */ + + i_in_pitch * ( p_pic->p[i_plane].i_lines * p_vout->p_sys->i_y + / p_vout->output.i_height ) + /* Skip the right amount of columns */ + + i_in_pitch * p_vout->p_sys->i_x / p_vout->output.i_width; + + p_out = p_outpic->p[i_plane].p_pixels; + p_out_end = p_out + i_out_pitch * p_outpic->p[i_plane].i_lines; + + while( p_out < p_out_end ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, i_out_pitch ); + p_in += i_in_pitch; + p_out += i_out_pitch; + } + } + + vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic ); + vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic ); + + /* The source image may still be in the cache ... parse it! */ + if( !p_vout->p_sys->b_autocrop ) + { + return; + } + + UpdateStats( p_vout, p_pic ); +} + +static void UpdateStats( vout_thread_t *p_vout, picture_t *p_pic ) +{ + u8 *p_in = p_pic->p[0].p_pixels; + int i_pitch = p_pic->p[0].i_pitch; + int i_lines = p_pic->p[0].i_lines; + int i_firstwhite = -1, i_lastwhite = -1, i; + + /* Determine where black borders are */ + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + /* XXX: Do not laugh ! I know this is very naive. But it's just a + * proof of concept code snippet... */ + for( i = i_lines ; i-- ; ) + { + const int i_col = i * i_pitch / i_lines; + + if( p_in[i_col/2] > 40 + && p_in[i_pitch / 2] > 40 + && p_in[i_pitch/2 + i_col/2] > 40 ) + { + if( i_lastwhite == -1 ) + { + i_lastwhite = i; + } + i_firstwhite = i; + } + p_in += i_pitch; + } + break; + + default: + break; + } + + /* Decide whether it's worth changing the size */ + if( i_lastwhite == -1 ) + { + p_vout->p_sys->i_lastchange = 0; + return; + } + + if( i_lastwhite - i_firstwhite < p_vout->p_sys->i_height / 2 ) + { + p_vout->p_sys->i_lastchange = 0; + return; + } + + if( i_lastwhite - i_firstwhite < p_vout->p_sys->i_height + 16 + && i_lastwhite - i_firstwhite + 16 > p_vout->p_sys->i_height ) + { + p_vout->p_sys->i_lastchange = 0; + return; + } + + /* We need at least 25 images to make up our mind */ + p_vout->p_sys->i_lastchange++; + if( p_vout->p_sys->i_lastchange < 25 ) + { + return; + } + + /* Tune a few values */ + if( i_firstwhite & 1 ) + { + i_firstwhite--; + } + + if( !(i_lastwhite & 1) ) + { + i_lastwhite++; + } + + /* Change size */ + p_vout->p_sys->i_y = i_firstwhite; + p_vout->p_sys->i_height = i_lastwhite - i_firstwhite + 1; + + p_vout->p_sys->i_aspect = p_vout->output.i_aspect + * p_vout->output.i_height / p_vout->p_sys->i_height + * p_vout->p_sys->i_width / p_vout->output.i_width; + + p_vout->p_sys->b_changed = 1; +} diff --git a/modules/video_filter/deinterlace/.cvsignore b/modules/video_filter/deinterlace/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_filter/deinterlace/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_filter/deinterlace/Makefile b/modules/video_filter/deinterlace/Makefile new file mode 100644 index 0000000000..38beb063ee --- /dev/null +++ b/modules/video_filter/deinterlace/Makefile @@ -0,0 +1 @@ +deinterlace_SOURCES = deinterlace.c diff --git a/modules/video_filter/deinterlace/deinterlace.c b/modules/video_filter/deinterlace/deinterlace.c new file mode 100644 index 0000000000..3ea175e17b --- /dev/null +++ b/modules/video_filter/deinterlace/deinterlace.c @@ -0,0 +1,579 @@ +/***************************************************************************** + * deinterlace.c : deinterlacer plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: deinterlace.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "../filter_common.h" + +#define DEINTERLACE_DISCARD 1 +#define DEINTERLACE_MEAN 2 +#define DEINTERLACE_BLEND 3 +#define DEINTERLACE_BOB 4 +#define DEINTERLACE_LINEAR 5 + +/***************************************************************************** + * Local protypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +static void RenderBob ( vout_thread_t *, picture_t *, picture_t *, int ); +static void RenderMean ( vout_thread_t *, picture_t *, picture_t * ); +static void RenderBlend ( vout_thread_t *, picture_t *, picture_t * ); +static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int ); + +static void Merge ( void *, const void *, const void *, size_t ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define MODE_TEXT N_("Deinterlace mode") +#define MODE_LONGTEXT N_("one of \"discard\", \"blend\", \"mean\", \"bob\" or \"linear\"") + +static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear", NULL }; + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string_from_list( "deinterlace-mode", "discard", mode_list, NULL, + MODE_TEXT, MODE_LONGTEXT ); + set_description( _("deinterlacing module") ); + set_capability( "video filter", 0 ); + add_shortcut( "deinterlace" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Deinterlace video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Deinterlace specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + int i_mode; /* Deinterlace mode */ + vlc_bool_t b_double_rate; /* Shall we double the framerate? */ + + mtime_t last_date; + mtime_t next_date; + + vout_thread_t *p_vout; +}; + +/***************************************************************************** + * Create: allocates Deinterlace video thread output method + ***************************************************************************** + * This function allocates and initializes a Deinterlace vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char *psz_method; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return 1; + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + p_vout->p_sys->i_mode = DEINTERLACE_DISCARD; + p_vout->p_sys->b_double_rate = 0; + p_vout->p_sys->last_date = 0; + + /* Look what method was requested */ + psz_method = config_GetPsz( p_vout, "deinterlace-mode" ); + + if( psz_method == NULL ) + { + msg_Err( p_vout, "configuration variable %s empty", + "deinterlace-mode" ); + msg_Err( p_vout, "no deinterlace mode provided, using \"discard\"" ); + } + else + { + if( !strcmp( psz_method, "discard" ) ) + { + p_vout->p_sys->i_mode = DEINTERLACE_DISCARD; + } + else if( !strcmp( psz_method, "mean" ) ) + { + p_vout->p_sys->i_mode = DEINTERLACE_MEAN; + } + else if( !strcmp( psz_method, "blend" ) + || !strcmp( psz_method, "average" ) + || !strcmp( psz_method, "combine-fields" ) ) + { + p_vout->p_sys->i_mode = DEINTERLACE_BLEND; + } + else if( !strcmp( psz_method, "bob" ) + || !strcmp( psz_method, "progressive-scan" ) ) + { + p_vout->p_sys->i_mode = DEINTERLACE_BOB; + p_vout->p_sys->b_double_rate = 1; + } + else if( !strcmp( psz_method, "linear" ) ) + { + p_vout->p_sys->i_mode = DEINTERLACE_LINEAR; + p_vout->p_sys->b_double_rate = 1; + } + else + { + msg_Err( p_vout, "no valid deinterlace mode provided, " + "using \"discard\"" ); + } + + free( psz_method ); + } + + return 0; +} + +/***************************************************************************** + * Init: initialize Deinterlace video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure, full of directbuffers since we want + * the decoder to output directly to our structures. */ + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + case VLC_FOURCC('Y','V','1','2'): + case VLC_FOURCC('I','4','2','2'): + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + break; + + default: + return 0; /* unknown chroma */ + break; + } + + /* Try to open the real video output, with half the height our images */ + msg_Dbg( p_vout, "spawning the real video output" ); + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + case VLC_FOURCC('Y','V','1','2'): + switch( p_vout->p_sys->i_mode ) + { + case DEINTERLACE_BOB: + case DEINTERLACE_MEAN: + case DEINTERLACE_DISCARD: + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->output.i_width, p_vout->output.i_height / 2, + p_vout->output.i_chroma, p_vout->output.i_aspect ); + break; + + case DEINTERLACE_BLEND: + case DEINTERLACE_LINEAR: + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->output.i_width, p_vout->output.i_height, + p_vout->output.i_chroma, p_vout->output.i_aspect ); + break; + } + break; + + case VLC_FOURCC('I','4','2','2'): + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->output.i_width, p_vout->output.i_height, + VLC_FOURCC('I','4','2','0'), p_vout->output.i_aspect ); + break; + + default: + break; + } + + /* Everything failed */ + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "cannot open vout, aborting" ); + + return 0; + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return 0; +} + +/***************************************************************************** + * End: terminate Deinterlace video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Deinterlace video thread output method + ***************************************************************************** + * Terminate an output method created by DeinterlaceCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + vout_DestroyThread( p_vout->p_sys->p_vout ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Deinterlace image, + * waits until it is displayed and switch the two rendering buffers, preparing + * next frame. + *****************************************************************************/ +static void Render ( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *pp_outpic[2]; + + /* Get a new picture */ + while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout, + 0, 0, 0 ) ) + == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[0], p_pic->date ); + + /* If we are using double rate, get an additional new picture */ + if( p_vout->p_sys->b_double_rate ) + { + while( ( pp_outpic[1] = vout_CreatePicture( p_vout->p_sys->p_vout, + 0, 0, 0 ) ) + == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + vout_DestroyPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + /* 20ms is a bit arbitrary, but it's only for the first image we get */ + if( !p_vout->p_sys->last_date ) + { + vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1], + p_pic->date + 20000 ); + } + else + { + vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1], + (3 * p_pic->date - p_vout->p_sys->last_date) / 2 ); + } + p_vout->p_sys->last_date = p_pic->date; + } + + switch( p_vout->p_sys->i_mode ) + { + case DEINTERLACE_DISCARD: + RenderBob( p_vout, pp_outpic[0], p_pic, 0 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + break; + + case DEINTERLACE_BOB: + RenderBob( p_vout, pp_outpic[0], p_pic, 0 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + RenderBob( p_vout, pp_outpic[1], p_pic, 1 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] ); + break; + + case DEINTERLACE_LINEAR: + RenderLinear( p_vout, pp_outpic[0], p_pic, 0 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + RenderLinear( p_vout, pp_outpic[1], p_pic, 1 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] ); + break; + + case DEINTERLACE_MEAN: + RenderMean( p_vout, pp_outpic[0], p_pic ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + break; + + case DEINTERLACE_BLEND: + RenderBlend( p_vout, pp_outpic[0], p_pic ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + break; + } +} + +/***************************************************************************** + * RenderBob: renders a bob picture + *****************************************************************************/ +static void RenderBob( vout_thread_t *p_vout, + picture_t *p_outpic, picture_t *p_pic, int i_field ) +{ + int i_plane; + + /* Copy image and skip lines */ + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_out_end, *p_out; + int i_increment; + + p_in = p_pic->p[i_plane].p_pixels + + i_field * p_pic->p[i_plane].i_pitch; + + p_out = p_outpic->p[i_plane].p_pixels; + p_out_end = p_out + p_outpic->p[i_plane].i_pitch + * p_outpic->p[i_plane].i_lines; + + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + case VLC_FOURCC('Y','V','1','2'): + + for( ; p_out < p_out_end ; ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + + p_out += p_pic->p[i_plane].i_pitch; + p_in += 2 * p_pic->p[i_plane].i_pitch; + } + break; + + case VLC_FOURCC('I','4','2','2'): + + i_increment = 2 * p_pic->p[i_plane].i_pitch; + + if( i_plane == Y_PLANE ) + { + for( ; p_out < p_out_end ; ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + p_out += p_pic->p[i_plane].i_pitch; + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + p_out += p_pic->p[i_plane].i_pitch; + p_in += i_increment; + } + } + else + { + for( ; p_out < p_out_end ; ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + p_out += p_pic->p[i_plane].i_pitch; + p_in += i_increment; + } + } + break; + + default: + break; + } + } +} + +/***************************************************************************** + * RenderLinear: displays previously rendered output + *****************************************************************************/ +static void RenderLinear( vout_thread_t *p_vout, + picture_t *p_outpic, picture_t *p_pic, int i_field ) +{ + int i_plane; + + /* Copy image and skip lines */ + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_out_end, *p_out; + + p_in = p_pic->p[i_plane].p_pixels + + i_field * p_pic->p[i_plane].i_pitch; + + p_out = p_outpic->p[i_plane].p_pixels; + p_out_end = p_out + p_outpic->p[i_plane].i_pitch + * p_outpic->p[i_plane].i_lines; + + if( i_field == 0 ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + p_in += 2 * p_pic->p[i_plane].i_pitch; + p_out += p_pic->p[i_plane].i_pitch; + } + + p_out_end -= p_outpic->p[i_plane].i_pitch; + + for( ; p_out < p_out_end ; ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + + p_out += p_pic->p[i_plane].i_pitch; + + Merge( p_out, p_in, p_in + 2 * p_pic->p[i_plane].i_pitch, + p_pic->p[i_plane].i_pitch ); + + p_in += 2 * p_pic->p[i_plane].i_pitch; + p_out += p_pic->p[i_plane].i_pitch; + } + +#if 0 + if( i_field == 0 ) + { + p_in -= 2 * p_pic->p[i_plane].i_pitch; + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + } +#endif + } +} + +static void RenderMean( vout_thread_t *p_vout, + picture_t *p_outpic, picture_t *p_pic ) +{ + int i_plane; + + /* Copy image and skip lines */ + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_out_end, *p_out; + + p_in = p_pic->p[i_plane].p_pixels; + + p_out = p_outpic->p[i_plane].p_pixels; + p_out_end = p_out + p_outpic->p[i_plane].i_pitch + * p_outpic->p[i_plane].i_lines; + + /* All lines: mean value */ + for( ; p_out < p_out_end ; ) + { + Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch, + p_pic->p[i_plane].i_pitch ); + + p_out += p_pic->p[i_plane].i_pitch; + p_in += 2 * p_pic->p[i_plane].i_pitch; + } + } +} + +static void RenderBlend( vout_thread_t *p_vout, + picture_t *p_outpic, picture_t *p_pic ) +{ + int i_plane; + + /* Copy image and skip lines */ + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_out_end, *p_out; + + p_in = p_pic->p[i_plane].p_pixels; + + p_out = p_outpic->p[i_plane].p_pixels; + p_out_end = p_out + p_outpic->p[i_plane].i_pitch + * p_outpic->p[i_plane].i_lines; + + /* First line: simple copy */ + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_pic->p[i_plane].i_pitch ); + p_out += p_pic->p[i_plane].i_pitch; + + /* Remaining lines: mean value */ + for( ; p_out < p_out_end ; ) + { + Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch, + p_pic->p[i_plane].i_pitch ); + + p_out += p_pic->p[i_plane].i_pitch; + p_in += p_pic->p[i_plane].i_pitch; + } + } +} + +static void Merge( void *p_dest, const void *p_s1, + const void *p_s2, size_t i_bytes ) +{ + u8* p_end = (u8*)p_dest + i_bytes - 8; + + while( (u8*)p_dest < p_end ) + { + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + } + + p_end += 8; + + while( (u8*)p_dest < p_end ) + { + *(u8*)p_dest++ = ( (u16)(*(u8*)p_s1++) + (u16)(*(u8*)p_s2++) ) >> 1; + } +} diff --git a/modules/video_filter/distort.c b/modules/video_filter/distort.c new file mode 100644 index 0000000000..c3ba5fa82a --- /dev/null +++ b/modules/video_filter/distort.c @@ -0,0 +1,421 @@ +/***************************************************************************** + * distort.c : Misc video effects plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: distort.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include /* sin(), cos() */ + +#include +#include + +#include "filter_common.h" + +#define DISTORT_MODE_WAVE 1 +#define DISTORT_MODE_RIPPLE 2 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +static void DistortWave ( vout_thread_t *, picture_t *, picture_t * ); +static void DistortRipple ( vout_thread_t *, picture_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define MODE_TEXT N_("Distort mode") +#define MODE_LONGTEXT N_("one of \"wave\" and \"ripple\"") + +static char *mode_list[] = { "wave", "ripple", NULL }; + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string_from_list( "distort-mode", "wave", mode_list, NULL, + MODE_TEXT, MODE_LONGTEXT ); + set_description( _("miscellaneous video effects module") ); + set_capability( "video filter", 0 ); + add_shortcut( "distort" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Distort video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Distort specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + int i_mode; + vout_thread_t *p_vout; + + /* For the wave mode */ + double f_angle; + mtime_t last_date; +}; + +/***************************************************************************** + * Create: allocates Distort video thread output method + ***************************************************************************** + * This function allocates and initializes a Distort vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char *psz_method, *psz_method_tmp; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + p_vout->p_sys->i_mode = 0; + /* Look what method was requested from command line*/ + if( !(psz_method = psz_method_tmp = config_GetPsz( p_vout, "filter" )) ) + { + msg_Err( p_vout, "configuration variable %s empty", "filter" ); + return( 1 ); + } + while( *psz_method && *psz_method != ':' ) + { + psz_method++; + } + + if( !strcmp( psz_method, ":wave" ) ) + { + p_vout->p_sys->i_mode = DISTORT_MODE_WAVE; + } + else if( !strcmp( psz_method, ":ripple" ) ) + { + p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE; + } + free( psz_method_tmp ); + if( !p_vout->p_sys->i_mode ) + { + /* No method given in commandline. Look what method was + requested in configuration system */ + if( !(psz_method = psz_method_tmp + = config_GetPsz( p_vout, "distort-mode" )) ) + { + msg_Err( p_vout, "configuration variable %s empty, using 'wave'", + "distort-mode" ); + p_vout->p_sys->i_mode = DISTORT_MODE_WAVE; + } + else { + + if( !strcmp( psz_method, "wave" ) ) + { + p_vout->p_sys->i_mode = DISTORT_MODE_WAVE; + } + else if( !strcmp( psz_method, "ripple" ) ) + { + p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE; + } + + else + { + msg_Err( p_vout, "no valid distort mode provided, " + "using wave" ); + p_vout->p_sys->i_mode = DISTORT_MODE_WAVE; + } + } + } + free( psz_method_tmp ); + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Distort video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Try to open the real video output */ + msg_Dbg( p_vout, "spawning the real video output" ); + + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->render.i_width, p_vout->render.i_height, + p_vout->render.i_chroma, p_vout->render.i_aspect ); + + /* Everything failed */ + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "cannot open vout, aborting" ); + + return( 0 ); + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + p_vout->p_sys->f_angle = 0.0; + p_vout->p_sys->last_date = 0; + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Distort video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Distort video thread output method + ***************************************************************************** + * Terminate an output method created by DistortCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + vout_DestroyThread( p_vout->p_sys->p_vout ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Distort image, waits + * until it is displayed and switch the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic; + + /* This is a new frame. Get a structure from the video_output. */ + while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) ) + == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date ); + + switch( p_vout->p_sys->i_mode ) + { + case DISTORT_MODE_WAVE: + DistortWave( p_vout, p_pic, p_outpic ); + break; + + case DISTORT_MODE_RIPPLE: + DistortRipple( p_vout, p_pic, p_outpic ); + break; + + default: + break; + } + + vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic ); +} + +/***************************************************************************** + * DistortWave: draw a wave effect on the picture + *****************************************************************************/ +static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic, + picture_t *p_outpic ) +{ + int i_index; + double f_angle; + mtime_t new_date = mdate(); + + p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0; + p_vout->p_sys->last_date = new_date; + f_angle = p_vout->p_sys->f_angle; + + for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ ) + { + int i_line, i_num_lines, i_offset; + u8 black_pixel; + u8 *p_in, *p_out; + + p_in = p_inpic->p[i_index].p_pixels; + p_out = p_outpic->p[i_index].p_pixels; + + i_num_lines = p_inpic->p[i_index].i_lines; + + black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80; + + /* Ok, we do 3 times the sin() calculation for each line. So what ? */ + for( i_line = 0 ; i_line < i_num_lines ; i_line++ ) + { + /* Calculate today's offset, don't go above 1/20th of the screen */ + i_offset = (double)(p_inpic->p[i_index].i_pitch) + * sin( f_angle + 10.0 * (double)i_line + / (double)i_num_lines ) + / 20.0; + + if( i_offset ) + { + if( i_offset < 0 ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset, + p_inpic->p[i_index].i_pitch + i_offset ); + p_in += p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + memset( p_out + i_offset, black_pixel, -i_offset ); + } + else + { + p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in, + p_inpic->p[i_index].i_pitch - i_offset ); + memset( p_out, black_pixel, i_offset ); + p_in += p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + } + } + else + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_inpic->p[i_index].i_pitch ); + p_in += p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + } + + } + } +} + +/***************************************************************************** + * DistortRipple: draw a ripple effect at the bottom of the picture + *****************************************************************************/ +static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic, + picture_t *p_outpic ) +{ + int i_index; + double f_angle; + mtime_t new_date = mdate(); + + p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0; + p_vout->p_sys->last_date = new_date; + f_angle = p_vout->p_sys->f_angle; + + for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ ) + { + int i_line, i_first_line, i_num_lines, i_offset; + u8 black_pixel; + u8 *p_in, *p_out; + + black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80; + + i_num_lines = p_inpic->p[i_index].i_lines; + + i_first_line = i_num_lines * 4 / 5; + + p_in = p_inpic->p[i_index].p_pixels; + p_out = p_outpic->p[i_index].p_pixels; + + p_vout->p_vlc->pf_memcpy( p_out, p_in, + i_first_line * p_inpic->p[i_index].i_pitch ); + + p_in += i_first_line * p_inpic->p[i_index].i_pitch; + p_out += i_first_line * p_outpic->p[i_index].i_pitch; + + /* Ok, we do 3 times the sin() calculation for each line. So what ? */ + for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ ) + { + /* Calculate today's offset, don't go above 1/20th of the screen */ + i_offset = (double)(p_inpic->p[i_index].i_pitch) + * sin( f_angle + 2.0 * (double)i_line + / (double)( 1 + i_line + - i_first_line) ) + * (double)(i_line - i_first_line) + / (double)i_num_lines + / 8.0; + + if( i_offset ) + { + if( i_offset < 0 ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset, + p_inpic->p[i_index].i_pitch + i_offset ); + p_in -= p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + memset( p_out + i_offset, black_pixel, -i_offset ); + } + else + { + p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in, + p_inpic->p[i_index].i_pitch - i_offset ); + memset( p_out, black_pixel, i_offset ); + p_in -= p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + } + } + else + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, + p_inpic->p[i_index].i_pitch ); + p_in -= p_inpic->p[i_index].i_pitch; + p_out += p_outpic->p[i_index].i_pitch; + } + + } + } +} diff --git a/modules/video_filter/filter_common.h b/modules/video_filter/filter_common.h new file mode 100644 index 0000000000..bed8ed4afe --- /dev/null +++ b/modules/video_filter/filter_common.h @@ -0,0 +1,63 @@ +/***************************************************************************** + * filter_common.h: Common filter functions + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: filter_common.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#define ALLOCATE_DIRECTBUFFERS( i_max ) \ + /* Try to initialize i_max direct buffers */ \ + while( I_OUTPUTPICTURES < ( i_max ) ) \ + { \ + p_pic = NULL; \ + \ + /* Find an empty picture slot */ \ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) \ + { \ + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) \ + { \ + p_pic = p_vout->p_picture + i_index; \ + break; \ + } \ + } \ + \ + if( p_pic == NULL ) \ + { \ + break; \ + } \ + \ + /* Allocate the picture */ \ + vout_AllocatePicture( p_vout, p_pic, \ + p_vout->output.i_width, \ + p_vout->output.i_height, \ + p_vout->output.i_chroma ); \ + \ + if( !p_pic->i_planes ) \ + { \ + break; \ + } \ + \ + p_pic->i_status = DESTROYED_PICTURE; \ + p_pic->i_type = DIRECT_PICTURE; \ + \ + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; \ + \ + I_OUTPUTPICTURES++; \ + } \ + diff --git a/modules/video_filter/invert.c b/modules/video_filter/invert.c new file mode 100644 index 0000000000..1cbe3507c9 --- /dev/null +++ b/modules/video_filter/invert.c @@ -0,0 +1,221 @@ +/***************************************************************************** + * invert.c : Invert video plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: invert.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "filter_common.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("invert video module") ); + set_capability( "video filter", 0 ); + add_shortcut( "invert" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Invert video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Invert specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + vout_thread_t *p_vout; +}; + +/***************************************************************************** + * Create: allocates Invert video thread output method + ***************************************************************************** + * This function allocates and initializes a Invert vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Invert video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Try to open the real video output */ + msg_Dbg( p_vout, "spawning the real video output" ); + + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->render.i_width, p_vout->render.i_height, + p_vout->render.i_chroma, p_vout->render.i_aspect ); + + /* Everything failed */ + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "can't open vout, aborting" ); + + return( 0 ); + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Invert video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Invert video thread output method + ***************************************************************************** + * Terminate an output method created by InvertCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + vout_DestroyThread( p_vout->p_sys->p_vout ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Invert image, waits + * until it is displayed and switch the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic; + int i_index; + + /* This is a new frame. Get a structure from the video_output. */ + while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) ) + == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date ); + vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic ); + + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + u8 *p_in, *p_in_end, *p_out; + + p_in = p_pic->p[i_index].p_pixels; + p_in_end = p_in - 64 + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + p_out = p_outpic->p[i_index].p_pixels; + + for( ; p_in < p_in_end ; ) + { + /* Do 64 pixels at a time */ + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + *((u64*)p_out)++ = ~( *((u64*)p_in)++ ); + } + + p_in_end += 64; + + for( ; p_in < p_in_end ; ) + { + /* Do 1 pixel at a time */ + *p_out++ = ~( *p_in++ ); + } + } + + vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic ); + + vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic ); +} + diff --git a/modules/video_filter/transform.c b/modules/video_filter/transform.c new file mode 100644 index 0000000000..693d8c0ea7 --- /dev/null +++ b/modules/video_filter/transform.c @@ -0,0 +1,386 @@ +/***************************************************************************** + * transform.c : transform image plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: transform.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "filter_common.h" + +#define TRANSFORM_MODE_HFLIP 1 +#define TRANSFORM_MODE_VFLIP 2 +#define TRANSFORM_MODE_90 3 +#define TRANSFORM_MODE_180 4 +#define TRANSFORM_MODE_270 5 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define TYPE_TEXT N_("Transform type") +#define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'") + +static char *type_list[] = { "90", "180", "270", "hflip", "vflip", NULL }; + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string_from_list( "transform-type", "90", type_list, NULL, + TYPE_TEXT, TYPE_LONGTEXT); + set_description( _("image transformation module") ); + set_capability( "video filter", 0 ); + add_shortcut( "transform" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Transform video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Transform specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + int i_mode; + vlc_bool_t b_rotation; + vout_thread_t *p_vout; +}; + +/***************************************************************************** + * Create: allocates Transform video thread output method + ***************************************************************************** + * This function allocates and initializes a Transform vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char *psz_method; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + /* Look what method was requested */ + psz_method = config_GetPsz( p_vout, "transform-type" ); + + if( psz_method == NULL ) + { + msg_Err( p_vout, "configuration variable %s empty", "transform-type" ); + msg_Err( p_vout, "no valid transform mode provided, using '90'" ); + p_vout->p_sys->i_mode = TRANSFORM_MODE_90; + p_vout->p_sys->b_rotation = 1; + } + else + { + if( !strcmp( psz_method, "hflip" ) ) + { + p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP; + p_vout->p_sys->b_rotation = 0; + } + else if( !strcmp( psz_method, "vflip" ) ) + { + p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP; + p_vout->p_sys->b_rotation = 0; + } + else if( !strcmp( psz_method, "90" ) ) + { + p_vout->p_sys->i_mode = TRANSFORM_MODE_90; + p_vout->p_sys->b_rotation = 1; + } + else if( !strcmp( psz_method, "180" ) ) + { + p_vout->p_sys->i_mode = TRANSFORM_MODE_180; + p_vout->p_sys->b_rotation = 0; + } + else if( !strcmp( psz_method, "270" ) ) + { + p_vout->p_sys->i_mode = TRANSFORM_MODE_270; + p_vout->p_sys->b_rotation = 1; + } + else + { + msg_Err( p_vout, "no valid transform mode provided, using '90'" ); + p_vout->p_sys->i_mode = TRANSFORM_MODE_90; + p_vout->p_sys->b_rotation = 1; + } + + free( psz_method ); + } + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Transform video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Try to open the real video output */ + msg_Dbg( p_vout, "spawning the real video output" ); + + if( p_vout->p_sys->b_rotation ) + { + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->render.i_height, p_vout->render.i_width, + p_vout->render.i_chroma, + (u64)VOUT_ASPECT_FACTOR * (u64)VOUT_ASPECT_FACTOR + / (u64)p_vout->render.i_aspect ); + } + else + { + p_vout->p_sys->p_vout = + vout_CreateThread( p_vout, + p_vout->render.i_width, p_vout->render.i_height, + p_vout->render.i_chroma, p_vout->render.i_aspect ); + } + + /* Everything failed */ + if( p_vout->p_sys->p_vout == NULL ) + { + msg_Err( p_vout, "cannot open vout, aborting" ); + return( 0 ); + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Transform video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Transform video thread output method + ***************************************************************************** + * Terminate an output method created by TransformCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + vout_DestroyThread( p_vout->p_sys->p_vout ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Transform image, waits + * until it is displayed and switch the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic; + int i_index; + + /* This is a new frame. Get a structure from the video_output. */ + while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) ) + == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date ); + vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic ); + + switch( p_vout->p_sys->i_mode ) + { + case TRANSFORM_MODE_90: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + int i_pitch = p_pic->p[i_index].i_pitch; + + u8 *p_in = p_pic->p[i_index].p_pixels; + + u8 *p_out = p_outpic->p[i_index].p_pixels; + u8 *p_out_end = p_out + p_outpic->p[i_index].i_lines + * p_outpic->p[i_index].i_pitch; + + for( ; p_out < p_out_end ; ) + { + u8 *p_line_end; + + p_line_end = p_in + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + for( ; p_in < p_line_end ; ) + { + p_line_end -= i_pitch; + *(--p_out_end) = *p_line_end; + } + + p_in++; + } + } + break; + + case TRANSFORM_MODE_180: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + u8 *p_in = p_pic->p[i_index].p_pixels; + u8 *p_in_end = p_in + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + u8 *p_out = p_outpic->p[i_index].p_pixels; + + for( ; p_in < p_in_end ; ) + { + *p_out++ = *(--p_in_end); + } + } + break; + + case TRANSFORM_MODE_270: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + int i_pitch = p_pic->p[i_index].i_pitch; + + u8 *p_in = p_pic->p[i_index].p_pixels; + + u8 *p_out = p_outpic->p[i_index].p_pixels; + u8 *p_out_end = p_out + p_outpic->p[i_index].i_lines + * p_outpic->p[i_index].i_pitch; + + for( ; p_out < p_out_end ; ) + { + u8 *p_in_end; + + p_in_end = p_in + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + for( ; p_in < p_in_end ; ) + { + p_in_end -= i_pitch; + *p_out++ = *p_in_end; + } + + p_in++; + } + } + break; + + case TRANSFORM_MODE_VFLIP: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + u8 *p_in = p_pic->p[i_index].p_pixels; + u8 *p_in_end = p_in + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + u8 *p_out = p_outpic->p[i_index].p_pixels; + + for( ; p_in < p_in_end ; ) + { + p_in_end -= p_pic->p[i_index].i_pitch; + p_vout->p_vlc->pf_memcpy( p_out, p_in_end, + p_pic->p[i_index].i_pitch ); + p_out += p_pic->p[i_index].i_pitch; + } + } + break; + + case TRANSFORM_MODE_HFLIP: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + u8 *p_in = p_pic->p[i_index].p_pixels; + u8 *p_in_end = p_in + p_pic->p[i_index].i_lines + * p_pic->p[i_index].i_pitch; + + u8 *p_out = p_outpic->p[i_index].p_pixels; + + for( ; p_in < p_in_end ; ) + { + u8 *p_line_end = p_in + p_pic->p[i_index].i_pitch; + + for( ; p_in < p_line_end ; ) + { + *p_out++ = *(--p_line_end); + } + + p_in += p_pic->p[i_index].i_pitch; + } + } + break; + + default: + break; + } + + vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic ); + + vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic ); +} + diff --git a/modules/video_filter/wall.c b/modules/video_filter/wall.c new file mode 100644 index 0000000000..b05f962164 --- /dev/null +++ b/modules/video_filter/wall.c @@ -0,0 +1,421 @@ +/***************************************************************************** + * wall.c : Wall video plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: wall.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 +#include /* malloc(), free() */ +#include + +#include +#include + +#include "filter_common.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); + +static void RemoveAllVout ( vout_thread_t *p_vout ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define COLS_TEXT N_("Number of columns") +#define COLS_LONGTEXT N_("Select the number of horizontal videowindows in " \ + "which to split the video") + +#define ROWS_TEXT N_("Number of rows") +#define ROWS_LONGTEXT N_("Select the number of vertical videowindows in " \ + "which to split the video") + +#define ACTIVE_TEXT N_("Active windows") +#define ACTIVE_LONGTEXT N_("comma separated list of active windows, " \ + "defaults to all") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_integer( "wall-cols", 3, NULL, COLS_TEXT, COLS_LONGTEXT ); + add_integer( "wall-rows", 3, NULL, ROWS_TEXT, ROWS_LONGTEXT ); + add_string( "wall-active", NULL, NULL, ACTIVE_TEXT, ACTIVE_LONGTEXT ); + set_description( _("image wall video module") ); + set_capability( "video filter", 0 ); + add_shortcut( "wall" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Wall video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Wall specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + int i_col; + int i_row; + int i_vout; + struct vout_list_t + { + vlc_bool_t b_active; + int i_width; + int i_height; + vout_thread_t *p_vout; + } *pp_vout; +}; + +/***************************************************************************** + * Create: allocates Wall video thread output method + ***************************************************************************** + * This function allocates and initializes a Wall vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char *psz_method, *psz_tmp, *psz_method_tmp; + int i_vout; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = Render; + p_vout->pf_display = NULL; + + /* Look what method was requested */ + p_vout->p_sys->i_col = config_GetInt( p_vout, "wall-cols" ); + p_vout->p_sys->i_row = config_GetInt( p_vout, "wall-rows" ); + + p_vout->p_sys->i_col = __MAX( 1, __MIN( 15, p_vout->p_sys->i_col ) ); + p_vout->p_sys->i_row = __MAX( 1, __MIN( 15, p_vout->p_sys->i_row ) ); + + msg_Dbg( p_vout, "opening a %i x %i wall", + p_vout->p_sys->i_col, p_vout->p_sys->i_row ); + + p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_row * + p_vout->p_sys->i_col * + sizeof(struct vout_list_t) ); + if( p_vout->p_sys->pp_vout == NULL ) + { + msg_Err( p_vout, "out of memory" ); + free( p_vout->p_sys ); + return( 1 ); + } + + psz_method_tmp = psz_method = config_GetPsz( p_vout, "wall-active" ); + + /* If no trailing vout are specified, take them all */ + if( psz_method == NULL ) + { + for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col; + i_vout--; ) + { + p_vout->p_sys->pp_vout[i_vout].b_active = 1; + } + } + /* If trailing vout are specified, activate only the requested ones */ + else + { + for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col; + i_vout--; ) + { + p_vout->p_sys->pp_vout[i_vout].b_active = 0; + } + + while( *psz_method ) + { + psz_tmp = psz_method; + while( *psz_tmp && *psz_tmp != ',' ) + { + psz_tmp++; + } + + if( *psz_tmp ) + { + *psz_tmp = '\0'; + i_vout = atoi( psz_method ); + psz_method = psz_tmp + 1; + } + else + { + i_vout = atoi( psz_method ); + psz_method = psz_tmp; + } + + if( i_vout >= 0 && + i_vout < p_vout->p_sys->i_row * p_vout->p_sys->i_col ) + { + p_vout->p_sys->pp_vout[i_vout].b_active = 1; + } + } + } + + free( psz_method_tmp ); + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Wall video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index, i_row, i_col, i_width, i_height; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + p_vout->output.i_chroma = p_vout->render.i_chroma; + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Try to open the real video output */ + msg_Dbg( p_vout, "spawning the real video outputs" ); + + p_vout->p_sys->i_vout = 0; + + /* FIXME: use bresenham instead of those ugly divisions */ + for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ ) + { + for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ ) + { + if( i_col + 1 < p_vout->p_sys->i_col ) + { + i_width = ( p_vout->render.i_width + / p_vout->p_sys->i_col ) & ~0x1; + } + else + { + i_width = p_vout->render.i_width + - ( ( p_vout->render.i_width + / p_vout->p_sys->i_col ) & ~0x1 ) * i_col; + } + + if( i_row + 1 < p_vout->p_sys->i_row ) + { + i_height = ( p_vout->render.i_height + / p_vout->p_sys->i_row ) & ~0x3; + } + else + { + i_height = p_vout->render.i_height + - ( ( p_vout->render.i_height + / p_vout->p_sys->i_row ) & ~0x3 ) * i_row; + } + + p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_width = i_width; + p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_height = i_height; + + if( !p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active ) + { + p_vout->p_sys->i_vout++; + continue; + } + + p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout = + vout_CreateThread( p_vout, i_width, i_height, + p_vout->render.i_chroma, + p_vout->render.i_aspect + * p_vout->render.i_height / i_height + * i_width / p_vout->render.i_width ); + if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout == NULL ) + { + msg_Err( p_vout, "failed to get %ix%i vout threads", + p_vout->p_sys->i_col, p_vout->p_sys->i_row ); + RemoveAllVout( p_vout ); + return 0; + } + + p_vout->p_sys->i_vout++; + } + } + + ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES ); + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Wall video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the fake output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig ); + } +} + +/***************************************************************************** + * Destroy: destroy Wall video thread output method + ***************************************************************************** + * Terminate an output method created by WallCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + RemoveAllVout( p_vout ); + + free( p_vout->p_sys->pp_vout ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Render: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to Wall image, waits + * until it is displayed and switch the two rendering buffers, preparing next + * frame. + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + picture_t *p_outpic = NULL; + int i_col, i_row, i_vout, i_plane; + int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES]; + + i_vout = 0; + + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + pi_top_skip[i_plane] = 0; + } + + for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ ) + { + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + pi_left_skip[i_plane] = 0; + } + + for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ ) + { + if( !p_vout->p_sys->pp_vout[ i_vout ].b_active ) + { + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + pi_left_skip[i_plane] += + p_vout->p_sys->pp_vout[ i_vout ].i_width + * p_pic->p[i_plane].i_pitch / p_vout->output.i_width; + } + i_vout++; + continue; + } + + while( ( p_outpic = + vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout, + 0, 0, 0 ) + ) == NULL ) + { + if( p_vout->b_die || p_vout->b_error ) + { + vout_DestroyPicture( + p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic ); + return; + } + + msleep( VOUT_OUTMEM_SLEEP ); + } + + vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout, + p_outpic, p_pic->date ); + vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout, + p_outpic ); + + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + u8 *p_in, *p_in_end, *p_out; + int i_in_pitch = p_pic->p[i_plane].i_pitch; + int i_out_pitch = p_outpic->p[i_plane].i_pitch; + + p_in = p_pic->p[i_plane].p_pixels + + pi_top_skip[i_plane] + pi_left_skip[i_plane]; + + p_in_end = p_in + p_outpic->p[i_plane].i_lines + * p_pic->p[i_plane].i_pitch; + + p_out = p_outpic->p[i_plane].p_pixels; + + while( p_in < p_in_end ) + { + p_vout->p_vlc->pf_memcpy( p_out, p_in, i_out_pitch ); + p_in += i_in_pitch; + p_out += i_out_pitch; + } + + pi_left_skip[i_plane] += i_out_pitch; + } + + vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout, + p_outpic ); + vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout, + p_outpic ); + + i_vout++; + } + + for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) + { + pi_top_skip[i_plane] += p_vout->p_sys->pp_vout[ i_vout ].i_height + * p_pic->p[i_plane].i_lines + / p_vout->output.i_height + * p_pic->p[i_plane].i_pitch; + } + } +} + +/***************************************************************************** + * RemoveAllVout: destroy all the child video output threads + *****************************************************************************/ +static void RemoveAllVout( vout_thread_t *p_vout ) +{ + while( p_vout->p_sys->i_vout ) + { + --p_vout->p_sys->i_vout; + if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active ) + { + vout_DestroyThread( + p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout ); + } + } +} diff --git a/modules/video_output/aa/.cvsignore b/modules/video_output/aa/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/aa/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/aa/Makefile b/modules/video_output/aa/Makefile new file mode 100644 index 0000000000..f4187c7614 --- /dev/null +++ b/modules/video_output/aa/Makefile @@ -0,0 +1 @@ +aa_SOURCES = aa.c diff --git a/modules/video_output/aa/aa.c b/modules/video_output/aa/aa.c new file mode 100644 index 0000000000..d125c52327 --- /dev/null +++ b/modules/video_output/aa/aa.c @@ -0,0 +1,260 @@ +/***************************************************************************** + * vout_aa.c: Aa video output display method for testing purposes + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: aa.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Sigmund Augdal + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include + +#include +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Render ( vout_thread_t *, picture_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ASCII-art video output module") ); + set_capability( "video output", 10 ); + add_shortcut( "aalib" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: aa video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the aa specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + struct aa_context* aa_context; + aa_palette palette; + int i_width; /* width of main window */ + int i_height; /* height of main window */ +}; + +/***************************************************************************** + * Create: allocates aa video thread output method + ***************************************************************************** + * This function allocates and initializes a aa vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* Don't parse any options, but take $AAOPTS into account */ + aa_parseoptions( NULL, NULL, NULL, NULL ); + + if (!(p_vout->p_sys->aa_context = aa_autoinit(&aa_defparams))) + { + msg_Err( p_vout, "cannot initialize aalib" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = Render; + p_vout->pf_display = Display; + + p_vout->p_sys->i_width = aa_imgwidth(p_vout->p_sys->aa_context); + p_vout->p_sys->i_height = aa_imgheight(p_vout->p_sys->aa_context); + aa_autoinitkbd( p_vout->p_sys->aa_context, 0 ); + aa_autoinitmouse( p_vout->p_sys->aa_context, AA_MOUSEPRESSMASK ); + aa_hidemouse( p_vout->p_sys->aa_context ); + return( 0 ); +} + +/***************************************************************************** + * Init: initialize aa video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic = NULL; + + I_OUTPUTPICTURES = 0; + + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); + p_vout->output.i_width = p_vout->p_sys->i_width; + p_vout->output.i_height = p_vout->p_sys->i_height; + p_vout->output.i_aspect = p_vout->p_sys->i_width + * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height; + p_vout->output.pf_setpalette = SetPalette; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + if( p_pic == NULL ) + { + return -1; + } + + /* Allocate the picture */ + p_pic->p->p_pixels = aa_image( p_vout->p_sys->aa_context ); + p_pic->p->i_lines = p_vout->p_sys->i_height; + p_pic->p->i_pitch = p_vout->p_sys->i_width; + p_pic->p->i_pixel_pitch = 1; + p_pic->p->i_visible_pitch = p_vout->p_sys->i_width; + p_pic->i_planes = 1; + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + I_OUTPUTPICTURES++; + + return 0; +} + +/***************************************************************************** + * End: terminate aa video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + ; +} + +/***************************************************************************** + * Destroy: destroy aa video thread output method + ***************************************************************************** + * Terminate an output method created by AaCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + aa_close( p_vout->p_sys->aa_context ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle aa events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + int event, x, y, b; + event = aa_getevent( p_vout->p_sys->aa_context, 0 ); + switch ( event ) + { + case AA_MOUSE: + aa_getmouse( p_vout->p_sys->aa_context, &x, &y, &b ); + if ( b & AA_BUTTON3 ) + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + case AA_RESIZE: + p_vout->i_changes |= VOUT_SIZE_CHANGE; + aa_resize( p_vout->p_sys->aa_context ); + p_vout->p_sys->i_width = aa_imgwidth( p_vout->p_sys->aa_context ); + p_vout->p_sys->i_height = aa_imgheight( p_vout->p_sys->aa_context ); + break; + default: + break; + } + return( 0 ); +} + +/***************************************************************************** + * Render: render previously calculated output + *****************************************************************************/ +static void Render( vout_thread_t *p_vout, picture_t *p_pic ) +{ + aa_fastrender( p_vout->p_sys->aa_context, 0, 0, + aa_imgwidth( p_vout->p_sys->aa_context ), + aa_imgheight( p_vout->p_sys->aa_context ) ); +} + +/***************************************************************************** + * Display: displays previously rendered output + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* No need to do anything, the fake direct buffers stay as they are */ + int i_width, i_height, i_x, i_y; + + vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, + &i_x, &i_y, &i_width, &i_height ); + + aa_flush(p_vout->p_sys->aa_context); +} + +/***************************************************************************** + * SetPalette: set the 8bpp palette + *****************************************************************************/ +static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) +{ + int i; + + /* Fill colors with color information */ + for( i = 0; i < 256; i++ ) + { + aa_setpalette( p_vout->p_sys->palette, 256 -i, + red[ i ], green[ i ], blue[ i ] ); + } +} + diff --git a/modules/video_output/directx/.cvsignore b/modules/video_output/directx/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/directx/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/directx/Makefile b/modules/video_output/directx/Makefile new file mode 100644 index 0000000000..4f6b1d3cf0 --- /dev/null +++ b/modules/video_output/directx/Makefile @@ -0,0 +1 @@ +directx_SOURCES = directx.c vout.c events.c aout.c diff --git a/modules/video_output/directx/aout.c b/modules/video_output/directx/aout.c new file mode 100644 index 0000000000..84cc2abc4a --- /dev/null +++ b/modules/video_output/directx/aout.c @@ -0,0 +1,761 @@ +/***************************************************************************** + * aout.c: Windows DirectX audio output method + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: aout.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* strerror() */ + +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include +#include + +/***************************************************************************** + * DirectSound GUIDs. + * Defining them here allows us to get rid of the dxguid library during + * the linking stage. + *****************************************************************************/ +#include +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +/***************************************************************************** + * notification_thread_t: DirectX event thread + *****************************************************************************/ +typedef struct notification_thread_t +{ + VLC_COMMON_MEMBERS + + aout_thread_t * p_aout; + DSBPOSITIONNOTIFY p_events[2]; /* play notification events */ + +} notification_thread_t; + +/***************************************************************************** + * aout_sys_t: directx audio output method descriptor + ***************************************************************************** + * This structure is part of the audio output thread descriptor. + * It describes the direct sound specific properties of an audio device. + *****************************************************************************/ + +struct aout_sys_t +{ + LPDIRECTSOUND p_dsobject; /* main Direct Sound object */ + + LPDIRECTSOUNDBUFFER p_dsbuffer_primary; /* the actual sound card buffer + (not used directly) */ + + LPDIRECTSOUNDBUFFER p_dsbuffer; /* the sound buffer we use (direct sound + * takes care of mixing all the + * secondary buffers into the primary) */ + + LPDIRECTSOUNDNOTIFY p_dsnotify; /* the position notify interface */ + + HINSTANCE hdsound_dll; /* handle of the opened dsound dll */ + + long l_buffer_size; /* secondary sound buffer size */ + long l_write_position; /* next write position for the buffer */ + + volatile vlc_bool_t b_buffer_underflown; /* buffer underflow detection */ + volatile long l_data_played_from_beginning; /* for underflow detection */ + volatile long l_data_written_from_beginning; /* for underflow detection */ + + vlc_mutex_t buffer_lock; /* audio buffer lock */ + + notification_thread_t * p_notif; /* DirectSoundThread id */ +}; + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +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 DirectxCreateSecondaryBuffer ( aout_thread_t * ); +static void DirectxDestroySecondaryBuffer( aout_thread_t * ); +static int DirectxInitDSound ( aout_thread_t * ); +static void DirectSoundThread ( notification_thread_t * ); + +/***************************************************************************** + * OpenAudio: open the audio device + ***************************************************************************** + * This function opens and setups Direct Sound. + *****************************************************************************/ +int E_(OpenAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + HRESULT dsresult; + DSBUFFERDESC dsbuffer_desc; + + msg_Dbg( p_aout, "Open" ); + + /* 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->p_sys->p_dsobject = NULL; + p_aout->p_sys->p_dsbuffer_primary = NULL; + p_aout->p_sys->p_dsbuffer = NULL; + p_aout->p_sys->p_dsnotify = NULL; + p_aout->p_sys->l_data_written_from_beginning = 0; + p_aout->p_sys->l_data_played_from_beginning = 0; + vlc_mutex_init( p_aout, &p_aout->p_sys->buffer_lock ); + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = Play; + + /* Initialise DirectSound */ + if( DirectxInitDSound( p_aout ) ) + { + msg_Warn( p_aout, "cannot initialize DirectSound" ); + return( 1 ); + } + + /* Obtain (not create) Direct Sound primary buffer */ + memset( &dsbuffer_desc, 0, sizeof(DSBUFFERDESC) ); + dsbuffer_desc.dwSize = sizeof(DSBUFFERDESC); + dsbuffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER; + msg_Warn( p_aout, "create direct sound primary buffer" ); + dsresult = IDirectSound_CreateSoundBuffer(p_aout->p_sys->p_dsobject, + &dsbuffer_desc, + &p_aout->p_sys->p_dsbuffer_primary, + NULL); + if( dsresult != DS_OK ) + { + msg_Warn( p_aout, "cannot create direct sound primary buffer" ); + IDirectSound_Release( p_aout->p_sys->p_dsobject ); + p_aout->p_sys->p_dsobject = NULL; + p_aout->p_sys->p_dsbuffer_primary = NULL; + return( 1 ); + } + + + /* Now we need to setup DirectSound play notification */ + + /* first we need to create the notification events */ + p_aout->p_sys->p_notif->p_events[0].hEventNotify = + CreateEvent( NULL, FALSE, FALSE, NULL ); + p_aout->p_sys->p_notif->p_events[1].hEventNotify = + CreateEvent( NULL, FALSE, FALSE, NULL ); + + /* then launch the notification thread */ + msg_Dbg( p_aout, "creating DirectSoundThread" ); + p_aout->p_sys->p_notif = + vlc_object_create( p_aout, sizeof(notification_thread_t) ); + p_aout->p_sys->p_notif->p_aout = p_aout; + if( vlc_thread_create( p_aout->p_sys->p_notif, + "DirectSound Notification Thread", DirectSoundThread, 1 ) ) + { + msg_Err( p_aout, "cannot create DirectSoundThread" ); + /* Let's go on anyway */ + } + + vlc_object_attach( p_aout->p_sys->p_notif, p_aout ); + + return( 0 ); +} + +/***************************************************************************** + * SetFormat: reset the audio device and sets its format + ***************************************************************************** + * This functions set a new audio format. + * For this we need to close the current secondary buffer and create another + * one with the desired format. + *****************************************************************************/ +static int SetFormat( aout_thread_t *p_aout ) +{ + HRESULT dsresult; + WAVEFORMATEX *p_waveformat; + unsigned long i_size_struct; + + msg_Dbg( p_aout, "SetFormat" ); + + /* Set the format of Direct Sound primary buffer */ + + /* first we need to know the current format */ + dsresult = IDirectSoundBuffer_GetFormat( p_aout->p_sys->p_dsbuffer_primary, + NULL, 0, &i_size_struct ); + if( dsresult == DS_OK ) + { + p_waveformat = malloc( i_size_struct ); + dsresult = IDirectSoundBuffer_GetFormat( + p_aout->p_sys->p_dsbuffer_primary, + p_waveformat, i_size_struct, + NULL ); + } + + if( dsresult == DS_OK ) + { + /* Here we'll change the format */ + p_waveformat->nChannels = 2; + p_waveformat->nSamplesPerSec = (p_aout->i_rate < 44100) ? 44100 + : p_aout->i_rate; + p_waveformat->wBitsPerSample = 16; + p_waveformat->nBlockAlign = p_waveformat->wBitsPerSample / 8 * + p_waveformat->nChannels; + p_waveformat->nAvgBytesPerSec = p_waveformat->nSamplesPerSec * + p_waveformat->nBlockAlign; + + dsresult = IDirectSoundBuffer_SetFormat( + p_aout->p_sys->p_dsbuffer_primary, + p_waveformat ); + } + else msg_Warn( p_aout, "cannot get primary buffer format" ); + + if( dsresult != DS_OK ) + msg_Warn( p_aout, "cannot set primary buffer format" ); + + + /* Now we need to take care of Direct Sound secondary buffer */ + + vlc_mutex_lock( &p_aout->p_sys->buffer_lock ); + + /* first release the current secondary buffer */ + DirectxDestroySecondaryBuffer( p_aout ); + + /* then create a new secondary buffer */ + if( DirectxCreateSecondaryBuffer( p_aout ) ) + { + msg_Warn( p_aout, "cannot create buffer" ); + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + return( 1 ); + } + + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + + 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 ) +{ + long l_play_position, l_notused, l_result; + HRESULT dsresult; + + if( p_aout->p_sys->b_buffer_underflown ) + { + msg_Warn( p_aout, "GetBufInfo underflow" ); + return( i_buffer_limit ); + } + + dsresult = IDirectSoundBuffer_GetCurrentPosition(p_aout->p_sys->p_dsbuffer, + &l_play_position, &l_notused); + if( dsresult != DS_OK ) + { + msg_Warn( p_aout, "GetBufInfo cannot get current pos" ); + return( i_buffer_limit ); + } + + l_result = (p_aout->p_sys->l_write_position >= l_play_position) ? + (p_aout->p_sys->l_write_position - l_play_position) + : (p_aout->p_sys->l_buffer_size - l_play_position + + p_aout->p_sys->l_write_position); + +#if 0 + msg_Dbg( p_aout, "GetBufInfo: %i", i_result); +#endif + return l_result; +} + +/***************************************************************************** + * Play: play a sound buffer + ***************************************************************************** + * This function writes a buffer of i_length bytes + * Don't forget that DirectSound buffers are circular buffers. + *****************************************************************************/ +static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) +{ + VOID *p_write_position, *p_start_buffer; + long l_bytes1, l_bytes2, l_play_position; + HRESULT dsresult; + + /* protect buffer access (because of DirectSoundThread) */ + vlc_mutex_lock( &p_aout->p_sys->buffer_lock ); + + if( p_aout->p_sys->b_buffer_underflown ) + { + /* there has been an underflow so we need to play the new sample + * as soon as possible. This is why we query the play position */ + dsresult = IDirectSoundBuffer_GetCurrentPosition( + p_aout->p_sys->p_dsbuffer, + &l_play_position, + &p_aout->p_sys->l_write_position ); + if( dsresult != DS_OK ) + { + msg_Warn( p_aout, "cannot get buffer position" ); + p_aout->p_sys->l_write_position = 0; + } + + msg_Warn( p_aout, "Play underflow" ); + /* reinitialise the underflow detection counters */ + p_aout->p_sys->b_buffer_underflown = 0; + p_aout->p_sys->l_data_written_from_beginning = 0; + +#define WRITE_P p_aout->p_sys->l_write_position +#define PLAY_P l_play_position +#define BUF_SIZE p_aout->p_sys->l_buffer_size + p_aout->p_sys->l_data_played_from_beginning = -(WRITE_P %(BUF_SIZE/2)); + if( PLAY_P < BUF_SIZE/2 && WRITE_P > BUF_SIZE/2 ) + { + p_aout->p_sys->l_data_played_from_beginning -= (BUF_SIZE/2); + } + if( PLAY_P > BUF_SIZE/2 && WRITE_P < BUF_SIZE/2 ) + { + p_aout->p_sys->l_data_played_from_beginning -= (BUF_SIZE/2); + } +#undef WRITE_P +#undef PLAY_P +#undef BUF_SIZE + } + + /* Before copying anything, we have to lock the buffer */ + dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer, + p_aout->p_sys->l_write_position, /* Offset of lock start */ + i_size, /* Number of bytes to lock */ + &p_write_position, /* Address of lock start */ + &l_bytes1, /* Count of bytes locked before wrap around */ + &p_start_buffer, /* Buffer adress (if wrap around) */ + &l_bytes2, /* Count of bytes after wrap around */ + 0); /* Flags */ + if( dsresult == DSERR_BUFFERLOST ) + { + IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer ); + dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer, + p_aout->p_sys->l_write_position, + i_size, + &p_write_position, + &l_bytes1, + &p_start_buffer, + &l_bytes2, + 0); + + } + if( dsresult != DS_OK ) + { + msg_Warn( p_aout, "Play cannot lock buffer" ); + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + return; + } + + /* Now do the actual memcpy (two memcpy because the buffer is circular) */ + memcpy( p_write_position, buffer, l_bytes1 ); + if( p_start_buffer != NULL ) + { + memcpy( p_start_buffer, buffer + l_bytes1, l_bytes2 ); + } + + /* Now the data has been copied, unlock the buffer */ + IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer, + p_write_position, l_bytes1, p_start_buffer, l_bytes2 ); + + /* Update the write position index of the buffer*/ + p_aout->p_sys->l_write_position += i_size; + p_aout->p_sys->l_write_position %= p_aout->p_sys->l_buffer_size; + p_aout->p_sys->l_data_written_from_beginning += i_size; + + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + + /* The play function has no effect if the buffer is already playing */ + dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer, + 0, /* Unused */ + 0, /* Unused */ + DSBPLAY_LOOPING ); /* Flags */ + if( dsresult == DSERR_BUFFERLOST ) + { + IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer ); + dsresult = IDirectSoundBuffer_Play( p_aout->p_sys->p_dsbuffer, + 0, /* Unused */ + 0, /* Unused */ + DSBPLAY_LOOPING ); /* Flags */ + } + if( dsresult != DS_OK ) + { + msg_Warn( p_aout, "Play cannot play buffer" ); + return; + } + +} + +/***************************************************************************** + * CloseAudio: close the audio device + *****************************************************************************/ +void E_(CloseAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + msg_Dbg( p_aout, "Close" ); + + /* kill the position notification thread, if any */ + vlc_object_detach_all( p_aout->p_sys->p_notif ); + if( p_aout->p_sys->p_notif->b_thread ) + { + p_aout->p_sys->p_notif->b_die = 1; + vlc_thread_join( p_aout->p_sys->p_notif ); + } + vlc_object_destroy( p_aout->p_sys->p_notif ); + + /* release the secondary buffer */ + DirectxDestroySecondaryBuffer( p_aout ); + + /* then release the primary buffer */ + if( p_aout->p_sys->p_dsbuffer_primary != NULL ) + { + IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer_primary ); + p_aout->p_sys->p_dsbuffer_primary = NULL; + } + + /* finally release the DirectSound object */ + if( p_aout->p_sys->p_dsobject != NULL ) + { + IDirectSound_Release( p_aout->p_sys->p_dsobject ); + p_aout->p_sys->p_dsobject = NULL; + } + + /* free DSOUND.DLL */ + if( p_aout->p_sys->hdsound_dll != NULL ) + { + FreeLibrary( p_aout->p_sys->hdsound_dll ); + p_aout->p_sys->hdsound_dll = NULL; + } + + /* Close the Output. */ + if ( p_aout->p_sys != NULL ) + { + free( p_aout->p_sys ); + p_aout->p_sys = NULL; + } +} + +/***************************************************************************** + * DirectxInitDSound + ***************************************************************************** + *****************************************************************************/ +static int DirectxInitDSound( aout_thread_t *p_aout ) +{ + HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); + + p_aout->p_sys->hdsound_dll = LoadLibrary("DSOUND.DLL"); + if( p_aout->p_sys->hdsound_dll == NULL ) + { + msg_Warn( p_aout, "cannot open DSOUND.DLL" ); + return( 1 ); + } + + OurDirectSoundCreate = (void *)GetProcAddress( p_aout->p_sys->hdsound_dll, + "DirectSoundCreate" ); + + if( OurDirectSoundCreate == NULL ) + { + msg_Warn( p_aout, "GetProcAddress FAILED" ); + FreeLibrary( p_aout->p_sys->hdsound_dll ); + p_aout->p_sys->hdsound_dll = NULL; + return( 1 ); + } + + /* Create the direct sound object */ + if( OurDirectSoundCreate(NULL, &p_aout->p_sys->p_dsobject, NULL) != DS_OK ) + { + msg_Warn( p_aout, "cannot create a direct sound device" ); + p_aout->p_sys->p_dsobject = NULL; + FreeLibrary( p_aout->p_sys->hdsound_dll ); + p_aout->p_sys->hdsound_dll = NULL; + return( 1 ); + } + + /* Set DirectSound Cooperative level, ie what control we want over Windows + * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the + * settings of the primary buffer, but also that only the sound of our + * application will be hearable when it will have the focus. + * !!! (this is not really working as intended yet because to set the + * cooperative level you need the window handle of your application, and + * I don't know of any easy way to get it. Especially since we might play + * sound without any video, and so what window handle should we use ??? + * The hack for now is to use the Desktop window handle - it seems to be + * working */ + if( IDirectSound_SetCooperativeLevel(p_aout->p_sys->p_dsobject, + GetDesktopWindow(), + DSSCL_EXCLUSIVE) ) + { + msg_Warn( p_aout, "cannot set direct sound cooperative level" ); + } + + return( 0 ); +} + +/***************************************************************************** + * DirectxCreateSecondaryBuffer + ***************************************************************************** + * This function creates the buffer we'll use to play audio. + * In DirectSound there are two kinds of buffers: + * - the primary buffer: which is the actual buffer that the soundcard plays + * - the secondary buffer(s): these buffers are the one actually used by + * applications and DirectSound takes care of mixing them into the primary. + * + * Once you create a secondary buffer, you cannot change its format anymore so + * you have to release the current and create another one. + *****************************************************************************/ +static int DirectxCreateSecondaryBuffer( aout_thread_t *p_aout ) +{ + WAVEFORMATEX waveformat; + DSBUFFERDESC dsbdesc; + DSBCAPS dsbcaps; + + /* First set the buffer format */ + memset(&waveformat, 0, sizeof(WAVEFORMATEX)); + waveformat.wFormatTag = WAVE_FORMAT_PCM; + waveformat.nChannels = p_aout->i_channels; + waveformat.nSamplesPerSec = p_aout->i_rate; + waveformat.wBitsPerSample = 16; + waveformat.nBlockAlign = waveformat.wBitsPerSample / 8 * + waveformat.nChannels; + waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec * + waveformat.nBlockAlign; + + /* Then fill in the descriptor */ + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */ + | DSBCAPS_CTRLPOSITIONNOTIFY /* We need notification */ + | DSBCAPS_GLOBALFOCUS; /* Allows background playing */ + dsbdesc.dwBufferBytes = waveformat.nAvgBytesPerSec * 2; /* 2 sec buffer */ + dsbdesc.lpwfxFormat = &waveformat; + + if( IDirectSound_CreateSoundBuffer( p_aout->p_sys->p_dsobject, + &dsbdesc, + &p_aout->p_sys->p_dsbuffer, + NULL) != DS_OK ) + { + msg_Warn( p_aout, "cannot create direct sound secondary buffer" ); + p_aout->p_sys->p_dsbuffer = NULL; + return( 1 ); + } + + /* backup the size of the secondary sound buffer */ + memset(&dsbcaps, 0, sizeof(DSBCAPS)); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSoundBuffer_GetCaps( p_aout->p_sys->p_dsbuffer, &dsbcaps ); + p_aout->p_sys->l_buffer_size = dsbcaps.dwBufferBytes; + p_aout->p_sys->l_write_position = 0; + + msg_Dbg( p_aout, "DirectxCreateSecondaryBuffer: %li", + p_aout->p_sys->l_buffer_size ); + + /* Now the secondary buffer is created, we need to setup its position + * notification */ + p_aout->p_sys->p_notif->p_events[0].dwOffset = 0; /* notif position */ + p_aout->p_sys->p_notif->p_events[1].dwOffset = dsbcaps.dwBufferBytes / 2; + + /* Get the IDirectSoundNotify interface */ + if FAILED( IDirectSoundBuffer_QueryInterface( p_aout->p_sys->p_dsbuffer, + &IID_IDirectSoundNotify, + (LPVOID *)&p_aout->p_sys->p_dsnotify ) ) + { + msg_Warn( p_aout, "cannot get Notify interface" ); + /* Go on anyway */ + p_aout->p_sys->p_dsnotify = NULL; + return( 0 ); + } + + if FAILED( IDirectSoundNotify_SetNotificationPositions( + p_aout->p_sys->p_dsnotify, + 2, + p_aout->p_sys->p_notif->p_events ) ) + { + msg_Warn( p_aout, "cannot set position Notification" ); + /* Go on anyway */ + } + + return( 0 ); +} + +/***************************************************************************** + * DirectxCreateSecondaryBuffer + ***************************************************************************** + * This function destroy the secondary buffer. + *****************************************************************************/ +static void DirectxDestroySecondaryBuffer( aout_thread_t *p_aout ) +{ + /* make sure the buffer isn't playing */ + if( p_aout->p_sys->p_dsbuffer != NULL ) + { + IDirectSoundBuffer_Stop( p_aout->p_sys->p_dsbuffer ); + } + + if( p_aout->p_sys->p_dsnotify != NULL ) + { + IDirectSoundNotify_Release( p_aout->p_sys->p_dsnotify ); + p_aout->p_sys->p_dsnotify = NULL; + } + + if( p_aout->p_sys->p_dsbuffer != NULL ) + { + IDirectSoundBuffer_Release( p_aout->p_sys->p_dsbuffer ); + p_aout->p_sys->p_dsbuffer = NULL; + } +} + +/***************************************************************************** + * DirectSoundThread: this thread will capture play notification events. + ***************************************************************************** + * As Direct Sound uses circular buffers, we need to use event notification to + * manage them. + * Using event notification implies blocking the thread until the event is + * signaled so we really need to run this in a separate thread. + *****************************************************************************/ +static void DirectSoundThread( notification_thread_t *p_notif ) +{ + HANDLE notification_events[2]; + VOID *p_write_position, *p_start_buffer; + long l_bytes1, l_bytes2; + HRESULT dsresult; + long l_buffer_size, l_play_position, l_data_in_buffer; + + aout_thread_t *p_aout = p_notif->p_aout; + +#define P_EVENTS p_aout->p_sys->p_notif->p_events + notification_events[0] = P_EVENTS[0].hEventNotify; + notification_events[1] = P_EVENTS[1].hEventNotify; + + /* Tell the main thread that we are ready */ + vlc_thread_ready( p_notif ); + + /* this thread must be high-priority */ + if( !SetThreadPriority( GetCurrentThread(), + THREAD_PRIORITY_ABOVE_NORMAL ) ) + { + msg_Warn( p_notif, "DirectSoundThread could not renice itself" ); + } + + msg_Dbg( p_notif, "DirectSoundThread ready" ); + + while( !p_notif->b_die ) + { + /* wait for the position notification */ + l_play_position = WaitForMultipleObjects( 2, notification_events, + 0, INFINITE ); + vlc_mutex_lock( &p_aout->p_sys->buffer_lock ); + + if( p_notif->b_die ) + { + break; + } + + /* check for buffer underflow (bodge for wrap around) */ + l_buffer_size = p_aout->p_sys->l_buffer_size; + l_play_position = (l_play_position - WAIT_OBJECT_0) * l_buffer_size/2; + p_aout->p_sys->l_data_played_from_beginning += (l_buffer_size/2); + l_data_in_buffer = p_aout->p_sys->l_data_written_from_beginning - + p_aout->p_sys->l_data_played_from_beginning; + + /* detect wrap-around */ + if( l_data_in_buffer < (-l_buffer_size/2) ) + { + msg_Dbg( p_notif, "DirectSoundThread wrap around: %li", + l_data_in_buffer ); + l_data_in_buffer += l_buffer_size; + } + + /* detect underflow */ + if( l_data_in_buffer <= 0 ) + { + msg_Warn( p_notif, + "DirectSoundThread underflow: %li", l_data_in_buffer ); + p_aout->p_sys->b_buffer_underflown = 1; + p_aout->p_sys->l_write_position = + (l_play_position + l_buffer_size/2) % l_buffer_size; + l_data_in_buffer = l_buffer_size / 2; + p_aout->p_sys->l_data_played_from_beginning -= (l_buffer_size/2); + } + + + /* Clear the data which has already been played */ + + /* Before copying anything, we have to lock the buffer */ + dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer, + p_aout->p_sys->l_write_position, /* Offset of lock start */ + l_buffer_size - l_data_in_buffer, /* Number of bytes */ + &p_write_position, /* Address of lock start */ + &l_bytes1, /* Count of bytes locked before wrap around */ + &p_start_buffer, /* Buffer adress (if wrap around) */ + &l_bytes2, /* Count of bytes after wrap around */ + 0); /* Flags */ + if( dsresult == DSERR_BUFFERLOST ) + { + IDirectSoundBuffer_Restore( p_aout->p_sys->p_dsbuffer ); + dsresult = IDirectSoundBuffer_Lock( p_aout->p_sys->p_dsbuffer, + p_aout->p_sys->l_write_position, + l_buffer_size - l_data_in_buffer, + &p_write_position, + &l_bytes1, + &p_start_buffer, + &l_bytes2, + 0); + } + if( dsresult != DS_OK ) + { + msg_Warn( p_notif, "Play cannot lock buffer" ); + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + return; + } + + /* Now do the actual memcpy (two because the buffer is circular) */ + memset( p_write_position, 0, l_bytes1 ); + if( p_start_buffer != NULL ) + { + memset( p_start_buffer, 0, l_bytes2 ); + } + + /* Now the data has been copied, unlock the buffer */ + IDirectSoundBuffer_Unlock( p_aout->p_sys->p_dsbuffer, + p_write_position, l_bytes1, p_start_buffer, l_bytes2 ); + + vlc_mutex_unlock( &p_aout->p_sys->buffer_lock ); + + } + + /* free the events */ + CloseHandle( notification_events[0] ); + CloseHandle( notification_events[1] ); + + msg_Dbg( p_notif, "DirectSoundThread exiting" ); + +} diff --git a/modules/video_output/directx/directx.c b/modules/video_output/directx/directx.c new file mode 100644 index 0000000000..9196667ddb --- /dev/null +++ b/modules/video_output/directx/directx.c @@ -0,0 +1,75 @@ +/***************************************************************************** + * directx.c : Windows DirectX plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: directx.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +int E_(OpenAudio) ( vlc_object_t * ); +void E_(CloseAudio) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define HW_YUV_TEXT N_("use hardware YUV->RGB conversions") +#define HW_YUV_LONGTEXT N_( \ + "Try to use hardware acceleration for YUV->RGB conversions. " \ + "This option doesn't have any effect when using overlays." ) +#define SYSMEM_TEXT N_("use video buffers in system memory") +#define SYSMEM_LONGTEXT N_( \ + "Create video buffers in system memory instead of video memory. This " \ + "isn't recommended as usually using video memory allows to benefit from " \ + "more hardware acceleration (like rescaling or YUV->RGB conversions). " \ + "This option doesn't have any effect when using overlays." ) + +vlc_module_begin(); + add_category_hint( N_("Video"), NULL ); + add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT ); + add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT ); + set_description( _("DirectX extension module") ); + add_submodule(); + set_capability( "video output", 150 ); + set_callbacks( E_(OpenVideo), E_(CloseVideo) ); + add_submodule(); + set_capability( "audio output", 150 ); + set_callbacks( E_(OpenAudio), E_(CloseAudio) ); +vlc_module_end(); + +#if 0 /* FIXME */ + /* check if we registered a window class because we need to + * unregister it */ + WNDCLASS wndclass; + if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) ) + UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) ); +#endif + diff --git a/modules/video_output/directx/events.c b/modules/video_output/directx/events.c new file mode 100644 index 0000000000..6e55e719ea --- /dev/null +++ b/modules/video_output/directx/events.c @@ -0,0 +1,580 @@ +/***************************************************************************** + * events.c: Windows DirectX video output events handler + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: events.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * + * 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: This file contains the functions related to the creation of + * a window and the handling of its messages (events). + *****************************************************************************/ +#include /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include + +#include "netutils.h" + +#include +#include +#include + +#include + +#include "vout.h" + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int DirectXCreateWindow( vout_thread_t *p_vout ); +static void DirectXCloseWindow ( vout_thread_t *p_vout ); +static void DirectXUpdateRects( vout_thread_t *p_vout ); +static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ); + +/***************************************************************************** + * DirectXEventThread: Create video window & handle its messages + ***************************************************************************** + * This function creates a video window and then enters an infinite loop + * that handles the messages sent to that window. + * The main goal of this thread is to isolate the Win32 PeekMessage function + * because this one can block for a long time. + *****************************************************************************/ +void DirectXEventThread( event_thread_t *p_event ) +{ + MSG msg; + POINT old_mouse_pos; + + /* Initialisation */ + + /* Create a window for the video */ + /* Creating a window under Windows also initializes the thread's event + * message qeue */ + if( DirectXCreateWindow( p_event->p_vout ) ) + { + msg_Err( p_event, "out of memory" ); + p_event->b_dead = 1; + } + + /* signal the creation of the window */ + vlc_thread_ready( p_event ); + + /* Main loop */ + /* GetMessage will sleep if there's no message in the queue */ + while( !p_event->b_die + && GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) ) + { + /* Check if we are asked to exit */ + if( p_event->b_die ) + break; + + switch( msg.message ) + { + + case WM_NCMOUSEMOVE: + case WM_MOUSEMOVE: + if( (abs(GET_X_LPARAM(msg.lParam) - old_mouse_pos.x) > 2 || + (abs(GET_Y_LPARAM(msg.lParam) - old_mouse_pos.y)) > 2 ) ) + { + GetCursorPos( &old_mouse_pos ); + p_event->p_vout->p_sys->i_lastmoved = mdate(); + + if( p_event->p_vout->p_sys->b_cursor_hidden ) + { + p_event->p_vout->p_sys->b_cursor_hidden = 0; + ShowCursor( TRUE ); + } + } + break; + + case WM_VLC_HIDE_MOUSE: + GetCursorPos( &old_mouse_pos ); + ShowCursor( FALSE ); + break; + + case WM_RBUTTONUP: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_event, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + + case WM_LBUTTONDOWN: + break; + + case WM_LBUTTONDBLCLK: + p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + case WM_KEYDOWN: + /* the key events are first processed here. The next + * message processed by this main message loop will be the + * char translation of the key event */ + msg_Dbg( p_event, "WM_KEYDOWN" ); + switch( msg.wParam ) + { + case VK_ESCAPE: + /* exit application */ + p_event->p_vlc->b_die = 1; + break; + + case VK_F1: network_ChannelJoin( p_event, 1 ); break; + case VK_F2: network_ChannelJoin( p_event, 2 ); break; + case VK_F3: network_ChannelJoin( p_event, 3 ); break; + case VK_F4: network_ChannelJoin( p_event, 4 ); break; + case VK_F5: network_ChannelJoin( p_event, 5 ); break; + case VK_F6: network_ChannelJoin( p_event, 6 ); break; + case VK_F7: network_ChannelJoin( p_event, 7 ); break; + case VK_F8: network_ChannelJoin( p_event, 8 ); break; + case VK_F9: network_ChannelJoin( p_event, 9 ); break; + case VK_F10: network_ChannelJoin( p_event, 10 ); break; + case VK_F11: network_ChannelJoin( p_event, 11 ); break; + case VK_F12: network_ChannelJoin( p_event, 12 ); break; + } + TranslateMessage(&msg); + break; + + case WM_CHAR: + switch( msg.wParam ) + { + case 'q': + case 'Q': + /* exit application */ + p_event->p_vlc->b_die = 1; + break; + + case 'f': /* switch to fullscreen */ + case 'F': + p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + case 'c': /* toggle grayscale */ + case 'C': + p_event->p_vout->b_grayscale = ! p_event->p_vout->b_grayscale; + p_event->p_vout->p_sys->i_changes |= VOUT_GRAYSCALE_CHANGE; + break; + + case 'i': /* toggle info */ + case 'I': + p_event->p_vout->b_info = ! p_event->p_vout->b_info; + p_event->p_vout->p_sys->i_changes |= VOUT_INFO_CHANGE; + break; + + case 's': /* toggle scaling */ + case 'S': + p_event->p_vout->b_scale = ! p_event->p_vout->b_scale; + p_event->p_vout->p_sys->i_changes |= VOUT_SCALE_CHANGE; + break; + + case ' ': /* toggle interface */ + p_event->p_vout->b_interface = ! p_event->p_vout->b_interface; + p_event->p_vout->p_sys->i_changes |= VOUT_INTF_CHANGE; + break; + + default: + break; + } + + default: + /* Messages we don't handle directly are dispatched to the + * window procedure */ + TranslateMessage(&msg); + DispatchMessage(&msg); + break; + + } /* End Switch */ + + } /* End Main loop */ + + if( msg.message == WM_QUIT ) + { + msg_Warn( p_event, "WM_QUIT... should not happen!!" ); + p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */ + } + + msg_Dbg( p_event, "DirectXEventThread Terminating" ); + + /* clear the changes formerly signaled */ + p_event->p_vout->p_sys->i_changes = 0; + + DirectXCloseWindow( p_event->p_vout ); +} + + +/* following functions are local */ + +/***************************************************************************** + * DirectXCreateWindow: create a window for the video. + ***************************************************************************** + * Before creating a direct draw surface, we need to create a window in which + * the video will be displayed. This window will also allow us to capture the + * events. + *****************************************************************************/ +static int DirectXCreateWindow( vout_thread_t *p_vout ) +{ + HINSTANCE hInstance; + WNDCLASSEX wc; /* window class components */ + RECT rect_window; + COLORREF colorkey; + HDC hdc; + HICON vlc_icon = NULL; + char vlc_path[_MAX_PATH+1]; + + msg_Dbg( p_vout, "DirectXCreateWindow" ); + + /* get this module's instance */ + hInstance = GetModuleHandle(NULL); + + /* Create a BRUSH that will be used by Windows to paint the window + * background. + * This window background is important for us as it will be used by the + * graphics card to display the overlay. + * This is why we carefully choose the color for this background, the goal + * being to choose a color which isn't complete black but nearly. We + * obviously don't want to use black as a colorkey for the overlay because + * black is one of the most used color and thus would give us undesirable + * effects */ + /* the first step is to find the colorkey we want to use. The difficulty + * comes from the potential dithering (depends on the display depth) + * because we need to know the real RGB value of the chosen colorkey */ + hdc = GetDC( NULL ); + for( colorkey = 5; colorkey < 0xFF /*all shades of red*/; colorkey++ ) + { + if( colorkey == GetNearestColor( hdc, colorkey ) ) + break; + } + msg_Dbg( p_vout, "background color: %i", colorkey ); + + /* create the actual brush */ + p_vout->p_sys->hbrush = CreateSolidBrush(colorkey); + p_vout->p_sys->i_rgb_colorkey = (int)colorkey; + + /* Get the current size of the display and its colour depth */ + p_vout->p_sys->rect_display.right = GetDeviceCaps( hdc, HORZRES ); + p_vout->p_sys->rect_display.bottom = GetDeviceCaps( hdc, VERTRES ); + p_vout->p_sys->i_display_depth = GetDeviceCaps( hdc, BITSPIXEL ); + msg_Dbg( p_vout, "screen dimensions %ix%i colour depth %i", + p_vout->p_sys->rect_display.right, + p_vout->p_sys->rect_display.bottom, + p_vout->p_sys->i_display_depth ); + + ReleaseDC( NULL, hdc ); + + /* Get the Icon from the main app */ + vlc_icon = NULL; + if( GetModuleFileName( NULL, vlc_path, _MAX_PATH ) ) + { + vlc_icon = ExtractIcon( hInstance, vlc_path, 0 ); + } + + + /* fill in the window class structure */ + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_DBLCLKS; /* style: dbl click */ + wc.lpfnWndProc = (WNDPROC)DirectXEventProc; /* event handler */ + wc.cbClsExtra = 0; /* no extra class data */ + wc.cbWndExtra = 0; /* no extra window data */ + wc.hInstance = hInstance; /* instance */ + wc.hIcon = vlc_icon; /* load the vlc icon */ + wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */ + wc.hbrBackground = p_vout->p_sys->hbrush; /* background color */ + wc.lpszMenuName = NULL; /* no menu */ + wc.lpszClassName = "VLC DirectX"; /* use a special class */ + wc.hIconSm = vlc_icon; /* load the vlc icon */ + + /* register the window class */ + if (!RegisterClassEx(&wc)) + { + WNDCLASS wndclass; + + /* free window background brush */ + if( p_vout->p_sys->hbrush ) + { + DeleteObject( p_vout->p_sys->hbrush ); + p_vout->p_sys->hbrush = NULL; + } + + if( vlc_icon ) + DestroyIcon( vlc_icon ); + + /* Check why it failed. If it's because one already exists then fine */ + if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) ) + { + msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" ); + return (1); + } + } + + /* when you create a window you give the dimensions you wish it to have. + * Unfortunatly these dimensions will include the borders and title bar. + * We use the following function to find out the size of the window + * corresponding to the useable surface we want */ + rect_window.top = 10; + rect_window.left = 10; + rect_window.right = rect_window.left + p_vout->p_sys->i_window_width; + rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height; + AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 ); + + /* create the window */ + p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */ + VOUT_TITLE " (DirectX Output)", /* window title bar text */ + WS_OVERLAPPEDWINDOW + | WS_SIZEBOX, /* window style */ + CW_USEDEFAULT, /* default X coordinate */ + 0, /* default Y coordinate */ + rect_window.right - rect_window.left, /* window width */ + rect_window.bottom - rect_window.top, /* window height */ + NULL, /* no parent window */ + NULL, /* no menu in this window */ + hInstance, /* handle of this program instance */ + NULL); /* no additional arguments */ + + if (p_vout->p_sys->hwnd == NULL) { + msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" ); + return (1); + } + + /* store a p_vout pointer into the window local storage (for later use + * in DirectXEventProc). + * We need to use SetWindowLongPtr when it is available in mingw */ + SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout ); + + /* now display the window */ + ShowWindow(p_vout->p_sys->hwnd, SW_SHOW); + + return ( 0 ); +} + +/***************************************************************************** + * DirectXCloseWindow: close the window created by DirectXCreateWindow + ***************************************************************************** + * This function returns all resources allocated by DirectXCreateWindow. + *****************************************************************************/ +static void DirectXCloseWindow( vout_thread_t *p_vout ) +{ + msg_Dbg( p_vout, "DirectXCloseWindow" ); + + if( p_vout->p_sys->hwnd != NULL ) + { + DestroyWindow( p_vout->p_sys->hwnd ); + p_vout->p_sys->hwnd = NULL; + } + + /* We don't unregister the Window Class because it could lead to race + * conditions and it will be done anyway by the system when the app will + * exit */ +} + +/***************************************************************************** + * DirectXUpdateRects: + ***************************************************************************** + * This function is called when the window position and size is changed, and + * its job is to update the source and destination RECTs used to display the + * picture. + *****************************************************************************/ +static void DirectXUpdateRects( vout_thread_t *p_vout ) +{ + int i_width, i_height, i_x, i_y; + +#define rect_src p_vout->p_sys->rect_src +#define rect_src_clipped p_vout->p_sys->rect_src_clipped +#define rect_dest p_vout->p_sys->rect_dest +#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped +#define rect_display p_vout->p_sys->rect_display + + vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width, + p_vout->p_sys->i_window_height, + &i_x, &i_y, &i_width, &i_height ); + + /* Destination image position and dimensions */ + rect_dest.left = i_x + p_vout->p_sys->i_window_x; + rect_dest.top = i_y + p_vout->p_sys->i_window_y; + rect_dest.right = rect_dest.left + i_width; + rect_dest.bottom = rect_dest.top + i_height; + + + /* UpdateOverlay directdraw function doesn't automatically clip to the + * display size so we need to do it otherwise it will fails */ + + /* Clip the destination window */ + IntersectRect( &rect_dest_clipped, &rect_dest, &rect_display ); + +#if 0 + msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:" + " %i,%i,%i,%i", + rect_dest_clipped.left, rect_dest_clipped.top, + rect_dest_clipped.right, rect_dest_clipped.bottom ); +#endif + + /* the 2 following lines are to fix a bug when clicking on the desktop */ + if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 || + (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 ) + { + SetRectEmpty( &rect_src_clipped ); + return; + } + + /* src image dimensions */ + rect_src.left = 0; + rect_src.top = 0; + rect_src.right = p_vout->render.i_width; + rect_src.bottom = p_vout->render.i_height; + + /* Clip the source image */ + rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) * + p_vout->render.i_width / (rect_dest.right - rect_dest.left); + rect_src_clipped.right = p_vout->render.i_width - + (rect_dest.right - rect_dest_clipped.right) * p_vout->render.i_width / + (rect_dest.right - rect_dest.left); + rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) * + p_vout->render.i_height / (rect_dest.bottom - rect_dest.top); + rect_src_clipped.bottom = p_vout->render.i_height - + (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->render.i_height / + (rect_dest.bottom - rect_dest.top); + +#if 0 + msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped" + " coords: %i,%i,%i,%i", + rect_src_clipped.left, rect_src_clipped.top, + rect_src_clipped.right, rect_src_clipped.bottom ); +#endif + +#undef rect_src +#undef rect_src_clipped +#undef rect_dest +#undef rect_dest_clipped +#undef rect_display +} + +/***************************************************************************** + * DirectXEventProc: This is the window event processing function. + ***************************************************************************** + * On Windows, when you create a window you have to attach an event processing + * function to it. The aim of this function is to manage "Queued Messages" and + * "Nonqueued Messages". + * Queued Messages are those picked up and retransmitted by vout_Manage + * (using the GetMessage and DispatchMessage functions). + * Nonqueued Messages are those that Windows will send directly to this + * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...) + *****************************************************************************/ +static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + vout_thread_t *p_vout = + (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA ); + + switch( message ) + { + + case WM_WINDOWPOSCHANGED: + { + RECT rect_window; + POINT point_window; + + /* update the window position */ + point_window.x = 0; + point_window.y = 0; + ClientToScreen( hwnd, &point_window ); + p_vout->p_sys->i_window_x = point_window.x; + p_vout->p_sys->i_window_y = point_window.y; + + /* update the window size */ + GetClientRect( hwnd, &rect_window ); + p_vout->p_sys->i_window_width = rect_window.right; + p_vout->p_sys->i_window_height = rect_window.bottom; + + DirectXUpdateRects( p_vout ); + if( p_vout->p_sys->b_using_overlay && + !p_vout->p_sys->p_event->b_die ) + DirectXUpdateOverlay( p_vout ); + + /* signal the size change */ + if( !p_vout->p_sys->b_using_overlay && + !p_vout->p_sys->p_event->b_die ) + p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE; + + return 0; + } + break; + + /* the user wants to close the window */ + case WM_CLOSE: + msg_Dbg( p_vout, "WinProc WM_CLOSE" ); + /* exit application */ + p_vout->p_vlc->b_die = 1; + return 0; + break; + + /* the window has been closed so shut down everything now */ + case WM_DESTROY: + msg_Dbg( p_vout, "WinProc WM_DESTROY" ); + /* just destroy the window */ + PostQuitMessage( 0 ); + return 0; + break; + + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_SCREENSAVE: /* catch the screensaver */ + case SC_MONITORPOWER: /* catch the monitor turn-off */ + msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" ); + return 0; /* this stops them from happening */ + } + break; + + case WM_ERASEBKGND: + if( !p_vout->p_sys->b_using_overlay ) + { + /* We want to eliminate unnecessary background redraws which create + * an annoying flickering */ + int i_width, i_height, i_x, i_y; + RECT rect_temp; + GetClipBox( (HDC)wParam, &rect_temp ); +#if 0 + msg_Dbg( p_vout, "WinProc WM_ERASEBKGND %i,%i,%i,%i", + rect_temp.left, rect_temp.top, + rect_temp.right, rect_temp.bottom ); +#endif + vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width, + p_vout->p_sys->i_window_height, + &i_x, &i_y, &i_width, &i_height ); + ExcludeClipRect( (HDC)wParam, i_x, i_y, + i_x + i_width, i_y + i_height ); + } + break; + + default: + //msg_Dbg( p_vout, "WinProc WM Default %i", message ); + break; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} diff --git a/modules/video_output/directx/vout.c b/modules/video_output/directx/vout.c new file mode 100644 index 0000000000..a0d566da91 --- /dev/null +++ b/modules/video_output/directx/vout.c @@ -0,0 +1,1350 @@ +/***************************************************************************** + * vout.c: Windows DirectX video output display method + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: vout.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * + * 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: + * + * This plugin will use YUV overlay if supported, using overlay will result in + * the best video quality (hardware interpolation when rescaling the picture) + * and the fastest display as it requires less processing. + * + * If YUV overlay is not supported this plugin will use RGB offscreen video + * surfaces that will be blitted onto the primary surface (display) to + * effectively display the pictures. This fallback method also enables us to + * display video in window mode. + * + *****************************************************************************/ +#include /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include + +#include + +#include "netutils.h" + +#include "vout.h" + +/***************************************************************************** + * DirectDraw GUIDs. + * Defining them here allows us to get rid of the dxguid library during + * the linking stage. + *****************************************************************************/ +#include +DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 ); + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int NewPictureVec ( vout_thread_t *, picture_t *, int ); +static void FreePictureVec ( vout_thread_t *, picture_t *, int ); +static int UpdatePictureStruct( vout_thread_t *, picture_t *, int ); + +static int DirectXInitDDraw ( vout_thread_t *p_vout ); +static void DirectXCloseDDraw ( vout_thread_t *p_vout ); +static int DirectXCreateDisplay ( vout_thread_t *p_vout ); +static void DirectXCloseDisplay ( vout_thread_t *p_vout ); +static int DirectXCreateSurface ( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE2 *, int, int, int ); +static void DirectXCloseSurface ( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE2 ); +static int DirectXCreateClipper ( vout_thread_t *p_vout ); +static void DirectXGetDDrawCaps ( vout_thread_t *p_vout ); +static int DirectXGetSurfaceDesc ( picture_t *p_pic ); + +/***************************************************************************** + * OpenVideo: allocate DirectX video thread output method + ***************************************************************************** + * This function allocates and initialize the DirectX vout method. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return 1; + } + + /* Initialisations */ + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + p_vout->p_sys->p_ddobject = NULL; + p_vout->p_sys->p_display = NULL; + p_vout->p_sys->p_current_surface = NULL; + p_vout->p_sys->p_clipper = NULL; + p_vout->p_sys->hbrush = NULL; + p_vout->p_sys->hwnd = NULL; + p_vout->p_sys->i_changes = 0; + p_vout->p_sys->b_caps_overlay_clipping = 0; + SetRectEmpty( &p_vout->p_sys->rect_display ); + p_vout->p_sys->b_using_overlay = config_GetInt( p_vout, "overlay" ); + p_vout->p_sys->b_use_sysmem = config_GetInt( p_vout, "directx-use-sysmem"); + p_vout->p_sys->b_hw_yuv = config_GetInt( p_vout, "directx-hw-yuv" ); + + p_vout->p_sys->b_cursor_hidden = 0; + p_vout->p_sys->i_lastmoved = mdate(); + + /* Set main window's size */ + p_vout->p_sys->i_window_width = p_vout->i_window_width; + p_vout->p_sys->i_window_height = p_vout->i_window_height; + + /* Create the DirectXEventThread, this thread is created by us to isolate + * the Win32 PeekMessage function calls. We want to do this because + * Windows can stay blocked inside this call for a long time, and when + * this happens it thus blocks vlc's video_output thread. + * DirectXEventThread will take care of the creation of the video + * window (because PeekMessage has to be called from the same thread which + * created the window). */ + msg_Dbg( p_vout, "creating DirectXEventThread" ); + p_vout->p_sys->p_event = + vlc_object_create( p_vout, sizeof(event_thread_t) ); + p_vout->p_sys->p_event->p_vout = p_vout; + if( vlc_thread_create( p_vout->p_sys->p_event, + "DirectX Events Thread", DirectXEventThread, 1 ) ) + { + msg_Err( p_vout, "cannot create DirectXEventThread" ); + vlc_object_destroy( p_vout->p_sys->p_event ); + p_vout->p_sys->p_event = NULL; + goto error; + } + + if( p_vout->p_sys->p_event->b_error ) + { + msg_Err( p_vout, "DirectXEventThread failed" ); + goto error; + } + + vlc_object_attach( p_vout->p_sys->p_event, p_vout ); + + msg_Dbg( p_vout, "DirectXEventThread running" ); + + /* Initialise DirectDraw */ + if( DirectXInitDDraw( p_vout ) ) + { + msg_Err( p_vout, "cannot initialize DirectDraw" ); + goto error; + } + + /* Create the directx display */ + if( DirectXCreateDisplay( p_vout ) ) + { + msg_Err( p_vout, "cannot initialize DirectDraw" ); + goto error; + } + + return 0; + + error: + E_(CloseVideo)( VLC_OBJECT(p_vout) ); + return 1; + +} + +/***************************************************************************** + * Init: initialize DirectX video thread output method + ***************************************************************************** + * This function create the directx surfaces needed by the output thread. + * It is called at the beginning of the thread. + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_chroma_backup; + + /* Initialize the output structure. + * Since DirectDraw can do rescaling for us, stick to the default + * coordinates and aspect. */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + +#define MAX_DIRECTBUFFERS 1 + /* Right now we use only 1 directbuffer because we don't want the + * video decoder to decode directly into direct buffers as they are + * created into video memory and video memory is _really_ slow */ + + /* Choose the chroma we will try first. */ + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('Y','U','Y','2'): + case VLC_FOURCC('Y','U','N','V'): + p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2'); + break; + case VLC_FOURCC('U','Y','V','Y'): + case VLC_FOURCC('U','Y','N','V'): + case VLC_FOURCC('Y','4','2','2'): + p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y'); + break; + case VLC_FOURCC('Y','V','Y','U'): + p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U'); + break; + default: + p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2'); + break; + } + + NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS ); + + i_chroma_backup = p_vout->output.i_chroma; + + if( !I_OUTPUTPICTURES ) + { + /* hmmm, it didn't work! Let's try commonly supported chromas */ + p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2'); + NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS ); + if( !I_OUTPUTPICTURES ) + { + /* hmmm, it didn't work! Let's try commonly supported chromas */ + p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2'); + NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS ); + } + } + + if( !I_OUTPUTPICTURES ) + { + /* If it still didn't work then don't try to use an overlay */ + p_vout->output.i_chroma = i_chroma_backup; + p_vout->p_sys->b_using_overlay = 0; + NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS ); + } + + /* Change the window title bar text */ + if( p_vout->p_sys->b_using_overlay ) + SetWindowText( p_vout->p_sys->hwnd, + VOUT_TITLE " (hardware YUV overlay DirectX output)" ); + else if( p_vout->p_sys->b_hw_yuv ) + SetWindowText( p_vout->p_sys->hwnd, + VOUT_TITLE " (hardware YUV DirectX output)" ); + else SetWindowText( p_vout->p_sys->hwnd, + VOUT_TITLE " (software RGB DirectX output)" ); + + return 0; +} + +/***************************************************************************** + * End: terminate Sys video thread output method + ***************************************************************************** + * Terminate an output method created by Create. + * It is called at the end of the thread. + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES ); + return; +} + +/***************************************************************************** + * CloseVideo: destroy Sys video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +void E_(CloseVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + msg_Dbg( p_vout, "CloseVideo" ); + + DirectXCloseDisplay( p_vout ); + DirectXCloseDDraw( p_vout ); + + if( p_vout->p_sys->p_event ) + { + vlc_object_detach_all( p_vout->p_sys->p_event ); + + /* Kill DirectXEventThread */ + p_vout->p_sys->p_event->b_die = 1; + + /* we need to be sure DirectXEventThread won't stay stuck in + * GetMessage, so we send a fake message */ + if( p_vout->p_sys->hwnd ) + PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0); + + vlc_thread_join( p_vout->p_sys->p_event ); + vlc_object_destroy( p_vout->p_sys->p_event ); + } + + if( p_vout->p_sys ) + { + free( p_vout->p_sys ); + p_vout->p_sys = NULL; + } +} + +/***************************************************************************** + * Manage: handle Sys events + ***************************************************************************** + * This function should be called regularly by the video output thread. + * It returns a non null value if an error occured. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + WINDOWPLACEMENT window_placement; + + /* We used to call the Win32 PeekMessage function here to read the window + * messages. But since window can stay blocked into this function for a + * long time (for example when you move your window on the screen), I + * decided to isolate PeekMessage in another thread. */ + + /* + * Scale Change + */ + if( p_vout->i_changes & VOUT_SCALE_CHANGE + || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE) + { + msg_Dbg( p_vout, "Scale Change" ); + if( !p_vout->p_sys->b_using_overlay ) + InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); + else + DirectXUpdateOverlay( p_vout ); + p_vout->i_changes &= ~VOUT_SCALE_CHANGE; + p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE; + } + + /* + * Size Change + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE + || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE ) + { + msg_Dbg( p_vout, "Size Change" ); + if( !p_vout->p_sys->b_using_overlay ) + InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE ); + else + DirectXUpdateOverlay( p_vout ); + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE; + } + + /* + * Fullscreen change + */ + if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE + || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + p_vout->b_fullscreen = ! p_vout->b_fullscreen; + + /* We need to switch between Maximized and Normal sized window */ + window_placement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement ); + if( p_vout->b_fullscreen ) + { + /* Maximized window */ + window_placement.showCmd = SW_SHOWMAXIMIZED; + /* Change window style, no borders and no title bar */ + SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, 0 ); + + } + else + { + /* Normal window */ + window_placement.showCmd = SW_SHOWNORMAL; + /* Change window style, borders and title bar */ + SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, + WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE ); + } + + SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement ); + + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + } + + /* + * Pointer change + */ + if( (!p_vout->p_sys->b_cursor_hidden) && + ( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) ) + { + /* Hide the mouse automatically */ + p_vout->p_sys->b_cursor_hidden = 1; + PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 ); + } + + /* Check if the event thread is still running */ + if( p_vout->p_sys->p_event->b_die ) + return 1; /* exit */ + + return 0; +} + +/***************************************************************************** + * Display: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to the display, wait until + * it is displayed and switch the two rendering buffers, preparing next frame. + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + HRESULT dxresult; + + if( (p_vout->p_sys->p_display == NULL) ) + { + msg_Warn( p_vout, "no display!!" ); + return; + } + + if( !p_vout->p_sys->b_using_overlay ) + { + DDBLTFX ddbltfx; + + /* We ask for the "NOTEARING" option */ + memset( &ddbltfx, 0, sizeof(DDBLTFX) ); + ddbltfx.dwSize = sizeof(DDBLTFX); + ddbltfx.dwDDFX = DDBLTFX_NOTEARING; + + /* Blit video surface to display */ + dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display, + &p_vout->p_sys->rect_dest_clipped, + p_pic->p_sys->p_surface, + &p_vout->p_sys->rect_src_clipped, + DDBLT_ASYNC, &ddbltfx ); + if ( dxresult == DDERR_SURFACELOST ) + { + /* Our surface can be lost so be sure + * to check this and restore it if needed */ + IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ); + + /* Now that the surface has been restored try to display again */ + dxresult = IDirectDrawSurface2_Blt(p_vout->p_sys->p_display, + &p_vout->p_sys->rect_dest_clipped, + p_pic->p_sys->p_surface, + &p_vout->p_sys->rect_src_clipped, + DDBLT_ASYNC, &ddbltfx ); + } + + if( dxresult != DD_OK ) + { + msg_Warn( p_vout, "could not Blit the surface" ); + return; + } + + } + else /* using overlay */ + { + + /* Flip the overlay buffers if we are using back buffers */ + if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface ) + return; + + dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface, + NULL, DDFLIP_WAIT ); + if ( dxresult == DDERR_SURFACELOST ) + { + /* Our surface can be lost so be sure + * to check this and restore it if needed */ + IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ); + IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface ); + + /* Now that the surface has been restored try to display again */ + dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface, + NULL, DDFLIP_WAIT ); + DirectXUpdateOverlay( p_vout ); + } + + if( dxresult != DD_OK ) + msg_Warn( p_vout, "could not flip overlay surface" ); + + if( !DirectXGetSurfaceDesc( p_pic ) ) + { + /* AAARRGG */ + msg_Err( p_vout, "cannot get surface desc" ); + return; + } + + if( !UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) ) + { + /* AAARRGG */ + msg_Err( p_vout, "invalid pic chroma" ); + return; + } + + /* set currently displayed pic */ + p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface; + } + +} + + +/* following functions are local */ + +/***************************************************************************** + * DirectXInitDDraw: Takes care of all the DirectDraw initialisations + ***************************************************************************** + * This function initialise and allocate resources for DirectDraw. + *****************************************************************************/ +static int DirectXInitDDraw( vout_thread_t *p_vout ) +{ + HRESULT dxresult; + HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *); + LPDIRECTDRAW p_ddobject; + + msg_Dbg( p_vout, "DirectXInitDDraw" ); + + /* load direct draw DLL */ + p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL"); + if( p_vout->p_sys->hddraw_dll == NULL ) + { + msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" ); + goto error; + } + + OurDirectDrawCreate = + (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate"); + if ( OurDirectDrawCreate == NULL ) + { + msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" ); + goto error; + } + + /* Initialize DirectDraw now */ + dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL ); + if( dxresult != DD_OK ) + { + msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" ); + goto error; + } + + /* Get the IDirectDraw2 interface */ + dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2, + (LPVOID *)&p_vout->p_sys->p_ddobject ); + /* Release the unused interface */ + IDirectDraw_Release( p_ddobject ); + if( dxresult != DD_OK ) + { + msg_Err( p_vout, "cannot get IDirectDraw2 interface" ); + goto error; + } + + /* Set DirectDraw Cooperative level, ie what control we want over Windows + * display */ + dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject, + p_vout->p_sys->hwnd, DDSCL_NORMAL ); + if( dxresult != DD_OK ) + { + msg_Err( p_vout, "cannot set direct draw cooperative level" ); + goto error; + } + + /* Probe the capabilities of the hardware */ + DirectXGetDDrawCaps( p_vout ); + + msg_Dbg( p_vout, "End DirectXInitDDraw" ); + return 0; + + error: + if( p_vout->p_sys->p_ddobject ) + IDirectDraw2_Release( p_vout->p_sys->p_ddobject ); + if( p_vout->p_sys->hddraw_dll ) + FreeLibrary( p_vout->p_sys->hddraw_dll ); + p_vout->p_sys->hddraw_dll = NULL; + p_vout->p_sys->p_ddobject = NULL; + return 1; +} + +/***************************************************************************** + * DirectXCreateDisplay: create the DirectDraw display. + ***************************************************************************** + * Create and initialize display according to preferences specified in the vout + * thread fields. + *****************************************************************************/ +static int DirectXCreateDisplay( vout_thread_t *p_vout ) +{ + HRESULT dxresult; + DDSURFACEDESC ddsd; + LPDIRECTDRAWSURFACE p_display; + DDPIXELFORMAT pixel_format; + + msg_Dbg( p_vout, "DirectXCreateDisplay" ); + + /* Now get the primary surface. This surface is what you actually see + * on your screen */ + memset( &ddsd, 0, sizeof( DDSURFACEDESC )); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject, + &ddsd, + &p_display, NULL ); + if( dxresult != DD_OK ) + { + msg_Err( p_vout, "cannot get direct draw primary surface" ); + return 1; + } + + dxresult = IDirectDrawSurface_QueryInterface( p_display, + &IID_IDirectDrawSurface2, + (LPVOID *)&p_vout->p_sys->p_display ); + /* Release the old interface */ + IDirectDrawSurface_Release( p_display ); + if ( dxresult != DD_OK ) + { + msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" ); + return 1; + } + + /* The clipper will be used only in non-overlay mode */ + DirectXCreateClipper( p_vout ); + + +#if 1 + /* compute the colorkey pixel value from the RGB value we've got */ + memset( &pixel_format, 0, sizeof( DDPIXELFORMAT )); + pixel_format.dwSize = sizeof( DDPIXELFORMAT ); + dxresult = IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display, + &pixel_format ); + if( dxresult != DD_OK ) + msg_Warn( p_vout, "DirectXUpdateOverlay GetPixelFormat failed" ); + p_vout->p_sys->i_colorkey = (DWORD)((( p_vout->p_sys->i_rgb_colorkey + * pixel_format.dwRBitMask) / 255) + & pixel_format.dwRBitMask); +#endif + + return 0; +} + + +/***************************************************************************** + * DirectXCreateClipper: Create a clipper that will be used when blitting the + * RGB surface to the main display. + ***************************************************************************** + * This clipper prevents us to modify by mistake anything on the screen + * which doesn't belong to our window. For example when a part of our video + * window is hidden by another window. + *****************************************************************************/ +static int DirectXCreateClipper( vout_thread_t *p_vout ) +{ + HRESULT dxresult; + + msg_Dbg( p_vout, "DirectXCreateClipper" ); + + /* Create the clipper */ + dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0, + &p_vout->p_sys->p_clipper, NULL ); + if( dxresult != DD_OK ) + { + msg_Warn( p_vout, "DirectXCreateClipper cannot create clipper" ); + goto error; + } + + /* associate the clipper to the window */ + dxresult = IDirectDrawClipper_SetHWnd(p_vout->p_sys->p_clipper, 0, + p_vout->p_sys->hwnd); + if( dxresult != DD_OK ) + { + msg_Warn( p_vout, + "DirectXCreateClipper cannot attach clipper to window" ); + goto error; + } + + /* associate the clipper with the surface */ + dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display, + p_vout->p_sys->p_clipper); + if( dxresult != DD_OK ) + { + msg_Warn( p_vout, + "DirectXCreateClipper cannot attach clipper to surface" ); + goto error; + } + + return 0; + + error: + if( p_vout->p_sys->p_clipper ) + IDirectDrawClipper_Release( p_vout->p_sys->p_clipper ); + p_vout->p_sys->p_clipper = NULL; + return 1; + +} + +/***************************************************************************** + * DirectXCreateSurface: create an YUV overlay or RGB surface for the video. + ***************************************************************************** + * The best method of display is with an YUV overlay because the YUV->RGB + * conversion is done in hardware. + * You can also create a plain RGB surface. + * ( Maybe we could also try an RGB overlay surface, which could have hardware + * scaling and which would also be faster in window mode because you don't + * need to do any blitting to the main display...) + *****************************************************************************/ +static int DirectXCreateSurface( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE2 *pp_surface_final, + int i_chroma, int b_overlay, + int i_backbuffers ) +{ + HRESULT dxresult; + LPDIRECTDRAWSURFACE p_surface; + DDSURFACEDESC ddsd; + + /* Create the video surface */ + if( b_overlay ) + { + /* Now try to create the YUV overlay surface. + * This overlay will be displayed on top of the primary surface. + * A color key is used to determine whether or not the overlay will be + * displayed, ie the overlay will be displayed in place of the primary + * surface wherever the primary surface will have this color. + * The video window has been created with a background of this color so + * the overlay will be only displayed on top of this window */ + + memset( &ddsd, 0, sizeof( DDSURFACEDESC )); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + ddsd.ddpfPixelFormat.dwFourCC = i_chroma; + ddsd.dwFlags = DDSD_CAPS | + DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_PIXELFORMAT; + ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0); + ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | + DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP + : 0 ); + ddsd.dwHeight = p_vout->render.i_height; + ddsd.dwWidth = p_vout->render.i_width; + ddsd.dwBackBufferCount = i_backbuffers; + + dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject, + &ddsd, + &p_surface, NULL ); + if( dxresult != DD_OK ) + { + *pp_surface_final = NULL; + return 0; + } + } + + if( !b_overlay ) + { + vlc_bool_t b_rgb_surface = + ( i_chroma == VLC_FOURCC('R','G','B','2') ) + || ( i_chroma == VLC_FOURCC('R','V','1','5') ) + || ( i_chroma == VLC_FOURCC('R','V','1','6') ) + || ( i_chroma == VLC_FOURCC('R','V','2','4') ) + || ( i_chroma == VLC_FOURCC('R','V','3','2') ); + + memset( &ddsd, 0, sizeof( DDSURFACEDESC ) ); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.dwFlags = DDSD_HEIGHT | + DDSD_WIDTH | + DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwHeight = p_vout->render.i_height; + ddsd.dwWidth = p_vout->render.i_width; + + if( p_vout->p_sys->b_use_sysmem ) + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + else + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + + if( !b_rgb_surface ) + { + ddsd.dwFlags |= DDSD_PIXELFORMAT; + ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; + ddsd.ddpfPixelFormat.dwFourCC = i_chroma; + } + + dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject, + &ddsd, + &p_surface, NULL ); + if( dxresult != DD_OK ) + { + *pp_surface_final = NULL; + return 0; + } + } + + /* Now that the surface is created, try to get a newer DirectX interface */ + dxresult = IDirectDrawSurface_QueryInterface( p_surface, + &IID_IDirectDrawSurface2, + (LPVOID *)pp_surface_final ); + IDirectDrawSurface_Release( p_surface ); /* Release the old interface */ + if ( dxresult != DD_OK ) + { + msg_Err( p_vout, "cannot get IDirectDrawSurface2 interface" ); + *pp_surface_final = NULL; + return 0; + } + + return 1; +} + +/***************************************************************************** + * DirectXUpdateOverlay: Move or resize overlay surface on video display. + ***************************************************************************** + * This function is used to move or resize an overlay surface on the screen. + * Ususally the overlay is moved by the user and thus, by a move or resize + * event (in Manage). + *****************************************************************************/ +void DirectXUpdateOverlay( vout_thread_t *p_vout ) +{ + DDOVERLAYFX ddofx; + DWORD dwFlags; + HRESULT dxresult; + + if( p_vout->p_sys->p_current_surface == NULL || + !p_vout->p_sys->b_using_overlay ) + return; + + /* The new window dimensions should already have been computed by the + * caller of this function */ + + /* Position and show the overlay */ + memset(&ddofx, 0, sizeof(DDOVERLAYFX)); + ddofx.dwSize = sizeof(DDOVERLAYFX); + ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey; + ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey; + + dwFlags = DDOVER_SHOW; + if( !p_vout->p_sys->b_caps_overlay_clipping ) + dwFlags |= DDOVER_KEYDESTOVERRIDE; + + dxresult = IDirectDrawSurface2_UpdateOverlay( + p_vout->p_sys->p_current_surface, + &p_vout->p_sys->rect_src_clipped, + p_vout->p_sys->p_display, + &p_vout->p_sys->rect_dest_clipped, + dwFlags, + &ddofx ); + if(dxresult != DD_OK) + { + msg_Warn( p_vout, + "DirectXUpdateOverlay cannot move or resize overlay" ); + } + +} + +/***************************************************************************** + * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw + ***************************************************************************** + * This function returns all resources allocated by DirectXInitDDraw. + *****************************************************************************/ +static void DirectXCloseDDraw( vout_thread_t *p_vout ) +{ + msg_Dbg( p_vout, "DirectXCloseDDraw" ); + if( p_vout->p_sys->p_ddobject != NULL ) + { + IDirectDraw2_Release(p_vout->p_sys->p_ddobject); + p_vout->p_sys->p_ddobject = NULL; + } + + if( p_vout->p_sys->hddraw_dll != NULL ) + { + FreeLibrary( p_vout->p_sys->hddraw_dll ); + p_vout->p_sys->hddraw_dll = NULL; + } +} + +/***************************************************************************** + * DirectXCloseDisplay: close and reset the DirectX display device + ***************************************************************************** + * This function returns all resources allocated by DirectXCreateDisplay. + *****************************************************************************/ +static void DirectXCloseDisplay( vout_thread_t *p_vout ) +{ + msg_Dbg( p_vout, "DirectXCloseDisplay" ); + + if( p_vout->p_sys->p_clipper != NULL ) + { + msg_Dbg( p_vout, "DirectXCloseDisplay clipper" ); + IDirectDrawClipper_Release( p_vout->p_sys->p_clipper ); + p_vout->p_sys->p_clipper = NULL; + } + + if( p_vout->p_sys->p_display != NULL ) + { + msg_Dbg( p_vout, "DirectXCloseDisplay display" ); + IDirectDrawSurface2_Release( p_vout->p_sys->p_display ); + p_vout->p_sys->p_display = NULL; + } +} + +/***************************************************************************** + * DirectXCloseSurface: close the YUV overlay or RGB surface. + ***************************************************************************** + * This function returns all resources allocated for the surface. + *****************************************************************************/ +static void DirectXCloseSurface( vout_thread_t *p_vout, + LPDIRECTDRAWSURFACE2 p_surface ) +{ + msg_Dbg( p_vout, "DirectXCloseSurface" ); + if( p_surface != NULL ) + { + IDirectDrawSurface2_Release( p_surface ); + } +} + +/***************************************************************************** + * NewPictureVec: allocate a vector of identical pictures + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic, + int i_num_pics ) +{ + int i; + vlc_bool_t b_result_ok; + LPDIRECTDRAWSURFACE2 p_surface; + + msg_Dbg( p_vout, "NewPictureVec" ); + + I_OUTPUTPICTURES = 0; + + /* First we try to use an YUV overlay surface. + * The overlay surface that we create won't be used to decode directly + * into it because accessing video memory directly is way to slow (remember + * that pictures are decoded macroblock per macroblock). Instead the video + * will be decoded in picture buffers in system memory which will then be + * memcpy() to the overlay surface. */ + if( p_vout->p_sys->b_using_overlay ) + { + /* Triple buffering rocks! it doesn't have any processing overhead + * (you don't have to wait for the vsync) and provides for a very nice + * video quality (no tearing). */ + + b_result_ok = DirectXCreateSurface( p_vout, &p_surface, + p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay, + 2 /* number of backbuffers */ ); + + if( !b_result_ok ) + /* Try to reduce the number of backbuffers */ + b_result_ok = DirectXCreateSurface( p_vout, &p_surface, + p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay, + 0 /* number of backbuffers */); + + if( b_result_ok ) + { + DDSCAPS dds_caps; + picture_t front_pic; + picture_sys_t front_pic_sys; + front_pic.p_sys = &front_pic_sys; + + /* Allocate internal structure */ + p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) ); + if( p_pic[0].p_sys == NULL ) + { + DirectXCloseSurface( p_vout, p_surface ); + return -1; + } + + /* set front buffer */ + p_pic[0].p_sys->p_front_surface = p_surface; + + /* Get the back buffer */ + memset( &dds_caps, 0, sizeof( DDSCAPS ) ); + dds_caps.dwCaps = DDSCAPS_BACKBUFFER; + if( DD_OK != IDirectDrawSurface2_GetAttachedSurface( + p_surface, &dds_caps, + &p_pic[0].p_sys->p_surface ) ) + { + msg_Warn( p_vout, "NewPictureVec could not get back buffer" ); + /* front buffer is the same as back buffer */ + p_pic[0].p_sys->p_surface = p_surface; + } + + + p_vout->p_sys->p_current_surface = front_pic.p_sys->p_surface = + p_pic[0].p_sys->p_front_surface; + + /* reset the front buffer memory */ + if( DirectXGetSurfaceDesc( &front_pic ) && + UpdatePictureStruct( p_vout, &front_pic, + p_vout->output.i_chroma ) ) + { + int i,j; + for( i = 0; i < front_pic.i_planes; i++ ) + for( j = 0; j < front_pic.p[i].i_lines; j++) + memset( front_pic.p[i].p_pixels + j * + front_pic.p[i].i_pitch, 127, + front_pic.p[i].i_visible_pitch ); + } + + DirectXUpdateOverlay( p_vout ); + I_OUTPUTPICTURES = 1; + msg_Dbg( p_vout, "DirectX YUV overlay created successfully" ); + } + } + + /* As we can't have an overlay, we'll try to create a plain offscreen + * surface. This surface will reside in video memory because there's a + * better chance then that we'll be able to use some kind of hardware + * acceleration like rescaling, blitting or YUV->RGB conversions. + * We then only need to blit this surface onto the main display when we + * want to display it */ + if( !p_vout->p_sys->b_using_overlay ) + { + + if( p_vout->p_sys->b_hw_yuv ) + b_result_ok = DirectXCreateSurface( p_vout, &p_surface, + p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay, + 0 /* no back buffers */ ); + + if( !p_vout->p_sys->b_hw_yuv || !b_result_ok ) + { + /* Our last choice is to use a plain RGB surface */ + DDPIXELFORMAT ddpfPixelFormat; + + ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display, + &ddpfPixelFormat ); + + if( ddpfPixelFormat.dwFlags & DDPF_RGB ) + { + switch( ddpfPixelFormat.dwRGBBitCount ) + { + case 8: /* FIXME: set the palette */ + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); + break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); + break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); + break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); + break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); + break; + default: + msg_Err( p_vout, "unknown screen depth" ); + return 0; + } + p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask; + p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask; + p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask; + } + + p_vout->p_sys->b_hw_yuv = 0; + + b_result_ok = DirectXCreateSurface( p_vout, &p_surface, + p_vout->output.i_chroma, + p_vout->p_sys->b_using_overlay, + 0 /* no back buffers */ ); + } + + if( b_result_ok ) + { + /* Allocate internal structure */ + p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) ); + if( p_pic[0].p_sys == NULL ) + { + DirectXCloseSurface( p_vout, p_surface ); + return -1; + } + p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface + = p_surface; + + I_OUTPUTPICTURES = 1; + + msg_Dbg( p_vout, "DirectX plain surface created successfully" ); + } + } + + + /* Now that we've got all our direct-buffers, we can finish filling in the + * picture_t structures */ + for( i = 0; i < I_OUTPUTPICTURES; i++ ) + { + p_pic[i].i_status = DESTROYED_PICTURE; + p_pic[i].i_type = DIRECT_PICTURE; + PP_OUTPUTPICTURE[i] = &p_pic[i]; + + if( !DirectXGetSurfaceDesc( &p_pic[i] ) ) + { + /* AAARRGG */ + FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES ); + I_OUTPUTPICTURES = 0; + return -1; + } + + if( !UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) ) + { + + /* Unknown chroma, tell the guy to get lost */ + msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)", + p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma ); + FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES ); + I_OUTPUTPICTURES = 0; + return -1; + } + } + + msg_Dbg( p_vout, "End NewPictureVec"); + return 0; +} + +/***************************************************************************** + * FreePicture: destroy a picture vector allocated with NewPictureVec + ***************************************************************************** + * + *****************************************************************************/ +static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic, + int i_num_pics ) +{ + int i; + + for( i = 0; i < i_num_pics; i++ ) + { + DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface ); + + for( i = 0; i < i_num_pics; i++ ) + { + free( p_pic[i].p_sys ); + } + } +} + +/***************************************************************************** + * UpdatePictureStruct: updates the internal data in the picture_t structure + ***************************************************************************** + * This will setup stuff for use by the video_output thread + *****************************************************************************/ +static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic, + int i_chroma ) +{ + + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('R','G','B','2'): + case VLC_FOURCC('R','V','1','5'): + case VLC_FOURCC('R','V','1','6'): + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch; + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('R','G','B','2'): + p_pic->p->i_pixel_pitch = 1; + break; + case VLC_FOURCC('R','V','1','5'): + case VLC_FOURCC('R','V','1','6'): + p_pic->p->i_pixel_pitch = 2; + break; + case VLC_FOURCC('R','V','2','4'): + case VLC_FOURCC('R','V','3','2'): + p_pic->p->i_pixel_pitch = 4; + break; + default: + return -1; + } + p_pic->p->i_visible_pitch = p_vout->output.i_width * + p_pic->p->i_pixel_pitch; + p_pic->i_planes = 1; + break; + + case VLC_FOURCC('Y','V','1','2'): + + p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[Y_PLANE].i_pixel_pitch; + + p_pic->V_PIXELS = p_pic->Y_PIXELS + + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[V_PLANE].i_pixel_pitch; + + p_pic->U_PIXELS = p_pic->V_PIXELS + + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[U_PLANE].i_pixel_pitch; + + p_pic->i_planes = 3; + break; + + case VLC_FOURCC('I','Y','U','V'): + + p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[Y_PLANE].i_pixel_pitch; + + p_pic->U_PIXELS = p_pic->Y_PIXELS + + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[U_PLANE].i_pixel_pitch; + + p_pic->V_PIXELS = p_pic->U_PIXELS + + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width * + p_pic->p[V_PLANE].i_pixel_pitch; + + p_pic->i_planes = 3; + break; + + case VLC_FOURCC('Y','U','Y','2'): + + p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch; + p_pic->p->i_pixel_pitch = 2; + p_pic->p->i_visible_pitch = p_vout->output.i_width * + p_pic->p->i_pixel_pitch; + + p_pic->i_planes = 1; + break; + + default: + /* Not supported */ + return 0; + + } + + return 1; +} + +/***************************************************************************** + * DirectXGetDDrawCaps: Probe the capabilities of the hardware + ***************************************************************************** + * It is nice to know which features are supported by the hardware so we can + * find ways to optimize our rendering. + *****************************************************************************/ +static void DirectXGetDDrawCaps( vout_thread_t *p_vout ) +{ + DDCAPS ddcaps; + HRESULT dxresult; + + /* This is just an indication of whether or not we'll support overlay, + * but with this test we don't know if we support YUV overlay */ + memset( &ddcaps, 0, sizeof( DDCAPS )); + ddcaps.dwSize = sizeof(DDCAPS); + dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject, + &ddcaps, NULL ); + if(dxresult != DD_OK ) + { + msg_Warn( p_vout, "cannot get caps" ); + } + else + { + BOOL bHasOverlay, bHasOverlayFourCC, bCanClipOverlay, + bHasColorKey, bCanStretch; + + /* Determine if the hardware supports overlay surfaces */ + bHasOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAY) == + DDCAPS_OVERLAY) ? TRUE : FALSE; + /* Determine if the hardware supports overlay surfaces */ + bHasOverlayFourCC = ((ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) == + DDCAPS_OVERLAYFOURCC) ? TRUE : FALSE; + /* Determine if the hardware supports overlay surfaces */ + bCanClipOverlay = ((ddcaps.dwCaps & DDCAPS_OVERLAYCANTCLIP) == + 0 ) ? TRUE : FALSE; + /* Determine if the hardware supports colorkeying */ + bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) == + DDCAPS_COLORKEY) ? TRUE : FALSE; + /* Determine if the hardware supports scaling of the overlay surface */ + bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) == + DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE; + msg_Dbg( p_vout, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i " + "can_clip_overlay=%i colorkey=%i stretch=%i", + bHasOverlay, bHasOverlayFourCC, bCanClipOverlay, + bHasColorKey, bCanStretch ); + + /* Overlay clipping support is interesting for us as it means we can + * get rid of the colorkey alltogether */ + p_vout->p_sys->b_caps_overlay_clipping = bCanClipOverlay; + + } +} + +/***************************************************************************** + * DirectXGetSurfaceDesc: Get some more information about the surface + ***************************************************************************** + * This function get and stores the surface descriptor which among things + * has the pointer to the picture data. + *****************************************************************************/ +static int DirectXGetSurfaceDesc( picture_t *p_pic ) +{ + HRESULT dxresult; + + /* Lock the surface to get a valid pointer to the picture buffer */ + memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC )); + p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC); + dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, + NULL, &p_pic->p_sys->ddsd, + DDLOCK_NOSYSLOCK | DDLOCK_WAIT, + NULL ); + if ( dxresult == DDERR_SURFACELOST ) + { + /* Your surface can be lost so be sure + * to check this and restore it if needed */ + dxresult = IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface ); + dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL, + &p_pic->p_sys->ddsd, + DDLOCK_NOSYSLOCK | DDLOCK_WAIT, + NULL); + } + if( dxresult != DD_OK ) + { +//X msg_Err( p_vout, "DirectXGetSurfaceDesc cannot lock surface" ); + return 0; + } + + /* Unlock the Surface */ + dxresult = IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ); + + return 1; +} diff --git a/modules/video_output/directx/vout.h b/modules/video_output/directx/vout.h new file mode 100644 index 0000000000..6cfaed8e18 --- /dev/null +++ b/modules/video_output/directx/vout.h @@ -0,0 +1,112 @@ +/***************************************************************************** + * vout.h: Windows DirectX video output header file + ***************************************************************************** + * Copyright (C) 1998, 1999, 2000 VideoLAN + * $Id: vout.h,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Gildas Bazin + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * event_thread_t: DirectX event thread + *****************************************************************************/ +typedef struct event_thread_t +{ + VLC_COMMON_MEMBERS + + vout_thread_t * p_vout; + +} event_thread_t; + +/***************************************************************************** + * vout_sys_t: video output DirectX method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the DirectX specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + LPDIRECTDRAW2 p_ddobject; /* DirectDraw object */ + LPDIRECTDRAWSURFACE2 p_display; /* Display device */ + LPDIRECTDRAWSURFACE2 p_current_surface; /* surface currently displayed */ + LPDIRECTDRAWCLIPPER p_clipper; /* clipper used for blitting */ + HINSTANCE hddraw_dll; /* handle of the opened ddraw dll */ + HBRUSH hbrush; /* window backgound brush (color) */ + HWND hwnd; /* Handle of the main window */ + + vlc_bool_t b_using_overlay; /* Are we using an overlay surface */ + vlc_bool_t b_use_sysmem; /* Should we use system memory for surfaces */ + vlc_bool_t b_hw_yuv; /* Should we use hardware YUV->RGB conversions */ + + /* size of the display */ + RECT rect_display; + int i_display_depth; + + /* Window position and size */ + int i_window_x; + int i_window_y; + int i_window_width; + int i_window_height; + + /* Coordinates of src and dest images (used when blitting to display) */ + RECT rect_src; + RECT rect_src_clipped; + RECT rect_dest; + RECT rect_dest_clipped; + + /* DDraw capabilities */ + int b_caps_overlay_clipping; + + int i_rgb_colorkey; /* colorkey in RGB used by the overlay */ + int i_colorkey; /* colorkey used by the overlay */ + + volatile u16 i_changes; /* changes made to the video display */ + + /* Mouse */ + volatile vlc_bool_t b_cursor_hidden; + volatile mtime_t i_lastmoved; + + event_thread_t * p_event; +}; + +/***************************************************************************** + * picture_sys_t: direct buffer method descriptor + ***************************************************************************** + * This structure is part of the picture descriptor, it describes the + * DirectX specific properties of a direct buffer. + *****************************************************************************/ +struct picture_sys_t +{ + LPDIRECTDRAWSURFACE2 p_surface; + DDSURFACEDESC ddsd; + LPDIRECTDRAWSURFACE2 p_front_surface; +}; + +/***************************************************************************** + * Prototypes from vout.c + *****************************************************************************/ + +/***************************************************************************** + * Prototypes from events.c + *****************************************************************************/ +void DirectXEventThread ( event_thread_t *p_event ); +void DirectXUpdateOverlay( vout_thread_t *p_vout ); + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define WM_VLC_HIDE_MOUSE WM_APP diff --git a/modules/video_output/fb/.cvsignore b/modules/video_output/fb/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/fb/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/fb/Makefile b/modules/video_output/fb/Makefile new file mode 100644 index 0000000000..d993d4e844 --- /dev/null +++ b/modules/video_output/fb/Makefile @@ -0,0 +1 @@ +fb_SOURCES = fb.c diff --git a/modules/video_output/fb/fb.c b/modules/video_output/fb/fb.c new file mode 100644 index 0000000000..6709163dc6 --- /dev/null +++ b/modules/video_output/fb/fb.c @@ -0,0 +1,695 @@ +/***************************************************************************** + * fb.c : framebuffer plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: fb.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* SIGUSR1, SIGUSR2 */ +#include /* free() */ +#include /* strerror() */ +#include /* open() */ +#include /* close() */ + +#include /* struct termios */ +#include +#include /* mmap() */ + +#include +#include /* VT_* */ +#include /* KD* */ + +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int OpenDisplay ( vout_thread_t * ); +static void CloseDisplay ( vout_thread_t * ); +static void SwitchDisplay ( int i_signal ); +static void TextMode ( int i_tty ); +static void GfxMode ( int i_tty ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define FB_DEV_VAR "fbdev" + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( FB_DEV_VAR, "/dev/fb0", NULL, N_("framebuffer device"), NULL ); + set_description( _("Linux console framebuffer module") ); + set_capability( "video output", 30 ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: video output framebuffer method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the FB specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + /* System informations */ + int i_tty; /* tty device handle */ + struct termios old_termios; + + /* Original configuration informations */ + struct sigaction sig_usr1; /* USR1 previous handler */ + struct sigaction sig_usr2; /* USR2 previous handler */ + struct vt_mode vt_mode; /* previous VT mode */ + + /* Framebuffer information */ + int i_fd; /* device handle */ + struct fb_var_screeninfo old_info; /* original mode informations */ + struct fb_var_screeninfo var_info; /* current mode informations */ + vlc_bool_t b_pan; /* does device supports panning ? */ + struct fb_cmap fb_cmap; /* original colormap */ + u16 *p_palette; /* original palette */ + + /* Video information */ + int i_width; + int i_height; + int i_bytes_per_pixel; + + /* Video memory */ + byte_t * p_video; /* base adress */ + size_t i_page_size; /* page size */ +}; + +/***************************************************************************** + * Create: allocates FB video thread output method + ***************************************************************************** + * This function allocates and initializes a FB vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + struct sigaction sig_tty; /* sigaction for tty change */ + struct vt_mode vt_mode; /* vt current mode */ + struct termios new_termios; + + /* Allocate instance and initialize some members */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + return( 1 ); + }; + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + /* Set tty and fb devices */ + p_vout->p_sys->i_tty = 0; /* 0 == /dev/tty0 == current console */ + + GfxMode( p_vout->p_sys->i_tty ); + + /* Set keyboard settings */ + if (tcgetattr(0, &p_vout->p_sys->old_termios) == -1) + { + msg_Err( p_vout, "tcgetattr failed" ); + } + + if (tcgetattr(0, &new_termios) == -1) + { + msg_Err( p_vout, "tcgetattr failed" ); + } + + /* new_termios.c_lflag &= ~ (ICANON | ISIG); + new_termios.c_lflag |= (ECHO | ECHOCTL); */ + new_termios.c_lflag &= ~ (ICANON); + new_termios.c_lflag &= ~(ECHO | ECHOCTL); + new_termios.c_iflag = 0; + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + if (tcsetattr(0, TCSAFLUSH, &new_termios) == -1) + { + msg_Err( p_vout, "tcsetattr failed" ); + } + + ioctl( p_vout->p_sys->i_tty, VT_RELDISP, VT_ACKACQ ); + + /* Set-up tty signal handler to be aware of tty changes */ + memset( &sig_tty, 0, sizeof( sig_tty ) ); + sig_tty.sa_handler = SwitchDisplay; + sigemptyset( &sig_tty.sa_mask ); + if( sigaction( SIGUSR1, &sig_tty, &p_vout->p_sys->sig_usr1 ) || + sigaction( SIGUSR2, &sig_tty, &p_vout->p_sys->sig_usr2 ) ) + { + msg_Err( p_vout, "cannot set signal handler (%s)", strerror(errno) ); + tcsetattr(0, 0, &p_vout->p_sys->old_termios); + TextMode( p_vout->p_sys->i_tty ); + free( p_vout->p_sys ); + return( 1 ); + } + + /* Set-up tty according to new signal handler */ + if( -1 == ioctl( p_vout->p_sys->i_tty, + VT_GETMODE, &p_vout->p_sys->vt_mode ) ) + { + msg_Err( p_vout, "cannot get terminal mode (%s)", strerror(errno) ); + sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); + sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); + tcsetattr(0, 0, &p_vout->p_sys->old_termios); + TextMode( p_vout->p_sys->i_tty ); + free( p_vout->p_sys ); + return( 1 ); + } + memcpy( &vt_mode, &p_vout->p_sys->vt_mode, sizeof( vt_mode ) ); + vt_mode.mode = VT_PROCESS; + vt_mode.waitv = 0; + vt_mode.relsig = SIGUSR1; + vt_mode.acqsig = SIGUSR2; + + if( -1 == ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &vt_mode ) ) + { + msg_Err( p_vout, "cannot set terminal mode (%s)", strerror(errno) ); + sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); + sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); + tcsetattr(0, 0, &p_vout->p_sys->old_termios); + TextMode( p_vout->p_sys->i_tty ); + free( p_vout->p_sys ); + return( 1 ); + } + + if( OpenDisplay( p_vout ) ) + { + ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode ); + sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); + sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); + tcsetattr(0, 0, &p_vout->p_sys->old_termios); + TextMode( p_vout->p_sys->i_tty ); + free( p_vout->p_sys ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize framebuffer video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure: RGB with square pixels, whatever + * the input format is, since it's the only format we know */ + switch( p_vout->p_sys->var_info.bits_per_pixel ) + { + case 8: /* FIXME: set the palette */ + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break; + default: + msg_Err( p_vout, "unknown screen depth %i", + p_vout->p_sys->var_info.bits_per_pixel ); + return 0; + } + + /* Only useful for p_vout->p_sys->var_info.bits_per_pixel != 8 */ + p_vout->output.i_rmask = ( (1 << p_vout->p_sys->var_info.red.length) - 1 ) + << p_vout->p_sys->var_info.red.offset; + p_vout->output.i_gmask = ( (1 << p_vout->p_sys->var_info.green.length) - 1 ) + << p_vout->p_sys->var_info.green.offset; + p_vout->output.i_bmask = ( (1 << p_vout->p_sys->var_info.blue.length) - 1 ) + << p_vout->p_sys->var_info.blue.offset; + + p_vout->output.i_width = p_vout->p_sys->i_width; + p_vout->output.i_height = p_vout->p_sys->i_height; + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->p_sys->i_width + * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height; + + /* Clear the screen */ + memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + + /* Try to initialize 1 direct buffer */ + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL ) + { + return 0; + } + + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p->p_pixels = p_vout->p_sys->p_video; + p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; + p_pic->p->i_lines = p_vout->p_sys->var_info.yres; + + if( p_vout->p_sys->var_info.xres_virtual ) + { + p_pic->p->i_pitch = p_vout->p_sys->var_info.xres_virtual + * p_vout->p_sys->i_bytes_per_pixel; + } + else + { + p_pic->p->i_pitch = p_vout->p_sys->var_info.xres + * p_vout->p_sys->i_bytes_per_pixel; + } + + p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres + * p_vout->p_sys->i_bytes_per_pixel; + + p_pic->i_planes = 1; + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + + return 0; +} + +/***************************************************************************** + * End: terminate framebuffer video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + /* Clear the screen */ + memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); +} + +/***************************************************************************** + * Destroy: destroy FB video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + CloseDisplay( p_vout ); + + /* Reset the terminal */ + ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode ); + + /* Remove signal handlers */ + sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); + sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); + + /* Reset the keyboard state */ + tcsetattr( 0, 0, &p_vout->p_sys->old_termios ); + + /* Return to text mode */ + TextMode( p_vout->p_sys->i_tty ); + + /* Destroy structure */ + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle FB events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ +#if 0 + u8 buf; + + if ( read(0, &buf, 1) == 1) + { + switch( buf ) + { + case 'q': + p_vout->p_vlc->b_die = 1; + break; + + default: + break; + } + } +#endif + + /* + * Size change + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + msg_Dbg( p_vout, "reinitializing framebuffer screen" ); + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + + /* Destroy XImages to change their size */ + End( p_vout ); + + /* Recreate XImages. If SysInit failed, the thread can't go on. */ + if( Init( p_vout ) ) + { + msg_Err( p_vout, "cannot reinit framebuffer screen" ); + return( 1 ); + } + + /* Clear screen */ + memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + +#if 0 + /* Tell the video output thread that it will need to rebuild YUV + * tables. This is needed since conversion buffer size may have changed */ + p_vout->i_changes |= VOUT_YUV_CHANGE; +#endif + } + + return 0; +} + +/***************************************************************************** + * Display: displays previously rendered output + ***************************************************************************** + * This function send the currently rendered image to FB image, waits until + * it is displayed and switch the two rendering buffers, preparing next frame. + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* swap the two Y offsets if the drivers supports panning */ + if( p_vout->p_sys->b_pan ) + { + p_vout->p_sys->var_info.yoffset = 0; + //p_vout->p_sys->var_info.yoffset = p_vout->p_sys->var_info.yres; + + /* the X offset should be 0, but who knows ... + * some other app might have played with the framebuffer */ + p_vout->p_sys->var_info.xoffset = 0; + + ioctl( p_vout->p_sys->i_fd, + FBIOPAN_DISPLAY, &p_vout->p_sys->var_info ); + } +} + +#if 0 +static void SetPalette( vout_thread_t *p_vout, + u16 *red, u16 *green, u16 *blue, u16 *transp ) +{ + struct fb_cmap cmap = { 0, 256, red, green, blue, transp }; + + ioctl( p_vout->p_sys->i_fd, FBIOPUTCMAP, &cmap ); +} +#endif + +/* following functions are local */ + +/***************************************************************************** + * OpenDisplay: initialize framebuffer + *****************************************************************************/ +static int OpenDisplay( vout_thread_t *p_vout ) +{ + char *psz_device; /* framebuffer device path */ + struct fb_fix_screeninfo fix_info; /* framebuffer fix information */ + + /* Open framebuffer device */ + if( !(psz_device = config_GetPsz( p_vout, FB_DEV_VAR )) ) + { + msg_Err( p_vout, "don't know which fb device to open" ); + return( 1 ); + } + + p_vout->p_sys->i_fd = open( psz_device, O_RDWR); + + if( p_vout->p_sys->i_fd == -1 ) + { + msg_Err( p_vout, "cannot open %s (%s)", psz_device, strerror(errno) ); + free( psz_device ); + return( 1 ); + } + free( psz_device ); + + /* Get framebuffer device informations */ + if( ioctl( p_vout->p_sys->i_fd, + FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) ) + { + msg_Err( p_vout, "cannot get fb info (%s)", strerror(errno) ); + close( p_vout->p_sys->i_fd ); + return( 1 ); + } + + if( ioctl( p_vout->p_sys->i_fd, + FBIOGET_VSCREENINFO, &p_vout->p_sys->old_info ) ) + { + msg_Err( p_vout, "cannot get 2nd fb info (%s)", strerror(errno) ); + close( p_vout->p_sys->i_fd ); + return( 1 ); + } + + /* Set some attributes */ + p_vout->p_sys->var_info.activate = FB_ACTIVATE_NXTOPEN; + p_vout->p_sys->var_info.xoffset = 0; + p_vout->p_sys->var_info.yoffset = 0; + + if( ioctl( p_vout->p_sys->i_fd, + FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ) ) + { + msg_Err( p_vout, "cannot set fb info (%s)", strerror(errno) ); + close( p_vout->p_sys->i_fd ); + return( 1 ); + } + + /* Get some informations again, in the definitive configuration */ + if( ioctl( p_vout->p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) + || ioctl( p_vout->p_sys->i_fd, + FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) ) + { + msg_Err( p_vout, "cannot get additional fb info (%s)", + strerror(errno) ); + + /* Restore fb config */ + ioctl( p_vout->p_sys->i_fd, + FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ); + + close( p_vout->p_sys->i_fd ); + return( 1 ); + } + + /* FIXME: if the image is full-size, it gets cropped on the left + * because of the xres / xres_virtual slight difference */ + msg_Dbg( p_vout, "%ix%i (virtual %ix%i)", + p_vout->p_sys->var_info.xres, p_vout->p_sys->var_info.yres, + p_vout->p_sys->var_info.xres_virtual, + p_vout->p_sys->var_info.yres_virtual ); + + p_vout->p_sys->i_height = p_vout->p_sys->var_info.yres; + p_vout->p_sys->i_width = p_vout->p_sys->var_info.xres_virtual + ? p_vout->p_sys->var_info.xres_virtual + : p_vout->p_sys->var_info.xres; + + p_vout->p_sys->p_palette = NULL; + p_vout->p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep ); + + switch( p_vout->p_sys->var_info.bits_per_pixel ) + { + case 8: + p_vout->p_sys->p_palette = malloc( 8 * 256 * sizeof( u16 ) ); + p_vout->p_sys->fb_cmap.start = 0; + p_vout->p_sys->fb_cmap.len = 256; + p_vout->p_sys->fb_cmap.red = p_vout->p_sys->p_palette; + p_vout->p_sys->fb_cmap.green = p_vout->p_sys->p_palette + 256 * sizeof( u16 ); + p_vout->p_sys->fb_cmap.blue = p_vout->p_sys->p_palette + 2 * 256 * sizeof( u16 ); + p_vout->p_sys->fb_cmap.transp = p_vout->p_sys->p_palette + 3 * 256 * sizeof( u16 ); + + /* Save the colormap */ + ioctl( p_vout->p_sys->i_fd, FBIOGETCMAP, &p_vout->p_sys->fb_cmap ); + + p_vout->p_sys->i_bytes_per_pixel = 1; + break; + + case 15: + case 16: + p_vout->p_sys->i_bytes_per_pixel = 2; + break; + + case 24: + p_vout->p_sys->i_bytes_per_pixel = 3; + break; + + case 32: + p_vout->p_sys->i_bytes_per_pixel = 4; + break; + + default: + msg_Err( p_vout, "screen depth %d is not supported", + p_vout->p_sys->var_info.bits_per_pixel ); + + /* Restore fb config */ + ioctl( p_vout->p_sys->i_fd, + FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ); + + close( p_vout->p_sys->i_fd ); + return 1; + } + + p_vout->p_sys->i_page_size = p_vout->p_sys->i_width * + p_vout->p_sys->i_height * p_vout->p_sys->i_bytes_per_pixel; + + /* Map a framebuffer at the beginning */ + p_vout->p_sys->p_video = mmap( 0, p_vout->p_sys->i_page_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + p_vout->p_sys->i_fd, 0 ); + + if( p_vout->p_sys->p_video == ((void*)-1) ) + { + msg_Err( p_vout, "cannot map video memory (%s)", strerror(errno) ); + + if( p_vout->p_sys->var_info.bits_per_pixel == 8 ) + { + free( p_vout->p_sys->p_palette ); + } + + /* Restore fb config */ + ioctl( p_vout->p_sys->i_fd, + FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ); + + close( p_vout->p_sys->i_fd ); + return( 1 ); + } + + msg_Dbg( p_vout, "framebuffer type=%d, visual=%d, ypanstep=%d, " + "ywrap=%d, accel=%d", fix_info.type, fix_info.visual, + fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel ); + return( 0 ); +} + +/***************************************************************************** + * CloseDisplay: terminate FB video thread output method + *****************************************************************************/ +static void CloseDisplay( vout_thread_t *p_vout ) +{ + /* Clear display */ + memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + + /* Restore palette */ + if( p_vout->p_sys->var_info.bits_per_pixel == 8 ); + { + ioctl( p_vout->p_sys->i_fd, + FBIOPUTCMAP, &p_vout->p_sys->fb_cmap ); + free( p_vout->p_sys->p_palette ); + } + + /* Restore fb config */ + ioctl( p_vout->p_sys->i_fd, + FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ); + + /* Close fb */ + close( p_vout->p_sys->i_fd ); +} + +/***************************************************************************** + * SwitchDisplay: VT change signal handler + ***************************************************************************** + * This function activates or deactivates the output of the thread. It is + * called by the VT driver, on terminal change. + *****************************************************************************/ +static void SwitchDisplay(int i_signal) +{ +#if 0 + vout_thread_t *p_vout; + + vlc_mutex_lock( &p_vout_bank->lock ); + + /* XXX: only test the first video output */ + if( p_vout_bank->i_count ) + { + p_vout = p_vout_bank->pp_vout[0]; + + switch( i_signal ) + { + case SIGUSR1: /* vt has been released */ + p_vout->b_active = 0; + ioctl( p_vout->p_sys->i_tty, VT_RELDISP, 1 ); + break; + case SIGUSR2: /* vt has been acquired */ + p_vout->b_active = 1; + ioctl( p_vout->p_sys->i_tty, VT_RELDISP, VT_ACTIVATE ); + /* handle blanking */ + vlc_mutex_lock( &p_vout->change_lock ); + p_vout->i_changes |= VOUT_SIZE_CHANGE; + vlc_mutex_unlock( &p_vout->change_lock ); + break; + } + } + + vlc_mutex_unlock( &p_vout_bank->lock ); +#endif +} + +/***************************************************************************** + * TextMode and GfxMode : switch tty to text/graphic mode + ***************************************************************************** + * These functions toggle the tty mode. + *****************************************************************************/ +static void TextMode( int i_tty ) +{ + /* return to text mode */ + if( -1 == ioctl(i_tty, KDSETMODE, KD_TEXT) ) + { +//X msg_Err( p_vout, "failed ioctl KDSETMODE KD_TEXT" ); + } +} + +static void GfxMode( int i_tty ) +{ + /* switch to graphic mode */ + if( -1 == ioctl(i_tty, KDSETMODE, KD_GRAPHICS) ) + { +//X msg_Err( p_vout, "failed ioctl KDSETMODE KD_GRAPHICS" ); + } +} + diff --git a/modules/video_output/ggi/.cvsignore b/modules/video_output/ggi/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/ggi/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/ggi/Makefile b/modules/video_output/ggi/Makefile new file mode 100644 index 0000000000..3be0c18327 --- /dev/null +++ b/modules/video_output/ggi/Makefile @@ -0,0 +1 @@ +ggi_SOURCES = ggi.c diff --git a/modules/video_output/ggi/ggi.c b/modules/video_output/ggi/ggi.c new file mode 100644 index 0000000000..b737b55a42 --- /dev/null +++ b/modules/video_output/ggi/ggi.c @@ -0,0 +1,529 @@ +/***************************************************************************** + * ggi.c : GGI plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: ggi.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Vincent Seguin + * Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include +#include /* ENOMEM */ + +#include + +#include +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int OpenDisplay ( vout_thread_t * ); +static void CloseDisplay ( vout_thread_t * ); +static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define DISPLAY_TEXT N_("X11 display name") +#define DISPLAY_LONGTEXT N_("Specify the X11 hardware display you want to use."\ + "\nBy default vlc will use the value of the DISPLAY"\ + " environment variable.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "ggi-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT ); + set_description( "General Graphics Interface video output" ); + set_capability( "video output", 30 ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: video output GGI method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the GGI specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + /* GGI system informations */ + ggi_visual_t p_display; /* display device */ + + ggi_mode mode; /* mode descriptor */ + int i_bits_per_pixel; + + /* Buffer information */ + ggi_directbuffer * pp_buffer[2]; /* buffers */ + int i_index; + + vlc_bool_t b_must_acquire; /* must be acquired before writing */ +}; + +/***************************************************************************** + * Create: allocate GGI video thread output method + ***************************************************************************** + * This function allocate and initialize a GGI vout method. It uses some of the + * vout properties to choose the correct mode, and change them according to the + * mode actually used. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* Open and initialize device */ + if( OpenDisplay( p_vout ) ) + { + msg_Err( p_vout, "cannot initialize GGI display" ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize GGI video thread output method + ***************************************************************************** + * This function initialize the GGI display device. + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ +#define p_b p_vout->p_sys->pp_buffer + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + p_vout->output.i_width = p_vout->p_sys->mode.visible.x; + p_vout->output.i_height = p_vout->p_sys->mode.visible.y; + p_vout->output.i_aspect = p_vout->p_sys->mode.visible.x + * VOUT_ASPECT_FACTOR + / p_vout->p_sys->mode.visible.y; + + switch( p_vout->p_sys->i_bits_per_pixel ) + { + case 8: + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); + p_vout->output.pf_setpalette = SetPalette; + break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break; + default: + msg_Err( p_vout, "unknown screen depth %i", + p_vout->p_sys->i_bits_per_pixel ); + return 0; + } + + /* Only useful for bits_per_pixel != 8 */ + p_vout->output.i_rmask = p_b[ 0 ]->buffer.plb.pixelformat->red_mask; + p_vout->output.i_gmask = p_b[ 0 ]->buffer.plb.pixelformat->green_mask; + p_vout->output.i_bmask = p_b[ 0 ]->buffer.plb.pixelformat->blue_mask; + + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + if( p_pic == NULL ) + { + return 0; + } + + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_vout->p_sys->i_index = 0; + p_pic->p->p_pixels = p_b[ 0 ]->write; + p_pic->p->i_pixel_pitch = p_b[ 0 ]->buffer.plb.pixelformat->size / 8; + p_pic->p->i_lines = p_vout->p_sys->mode.visible.y; + + p_pic->p->i_pitch = p_b[ 0 ]->buffer.plb.stride; + + if( p_b[ 0 ]->buffer.plb.pixelformat->size / 8 + * p_vout->p_sys->mode.visible.x + != p_b[ 0 ]->buffer.plb.stride ) + { + p_pic->p->i_visible_pitch = p_b[ 0 ]->buffer.plb.pixelformat->size + / 8 * p_vout->p_sys->mode.visible.x; + } + else + { + p_pic->p->i_visible_pitch = p_b[ 0 ]->buffer.plb.stride; + } + + p_pic->i_planes = 1; + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + + /* Acquire first buffer */ + if( p_vout->p_sys->b_must_acquire ) + { + ggiResourceAcquire( p_b[ 0 ]->resource, + GGI_ACTYPE_WRITE ); + } + + /* Listen to the keyboard and the mouse buttons */ + ggiSetEventMask( p_vout->p_sys->p_display, + emKeyboard | emPtrButtonPress | emPtrButtonRelease ); + + /* Set asynchronous display mode -- usually quite faster */ + ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC ); + + return( 0 ); +#undef p_b +} + +/***************************************************************************** + * End: terminate GGI video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ +#define p_b p_vout->p_sys->pp_buffer + /* Release buffer */ + if( p_vout->p_sys->b_must_acquire ) + { + ggiResourceRelease( p_b[ p_vout->p_sys->i_index ]->resource ); + } +#undef p_b +} + +/***************************************************************************** + * Destroy: destroy GGI video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + CloseDisplay( p_vout ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle GGI events + ***************************************************************************** + * This function should be called regularly by video output thread. It returns + * a non null value if an error occured. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + struct timeval tv = { 0, 1000 }; /* 1 millisecond */ + gii_event_mask mask; + gii_event event; + + mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease; + + ggiEventPoll( p_vout->p_sys->p_display, mask, &tv ); + + while( ggiEventsQueued( p_vout->p_sys->p_display, mask) ) + { + ggiEventRead( p_vout->p_sys->p_display, &event, mask); + + switch( event.any.type ) + { + case evKeyRelease: + + switch( event.key.sym ) + { + case 'q': + case 'Q': + case GIIUC_Escape: + /* FIXME pass message ! */ + p_vout->p_vlc->b_die = 1; + break; + + default: + break; + } + break; + + case evPtrButtonRelease: + + switch( event.pbutton.button ) + { + case GII_PBUTTON_RIGHT: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + } + break; + + default: + break; + } + } + + return( 0 ); +} + +/***************************************************************************** + * Display: displays previously rendered output + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ +#define p_b p_vout->p_sys->pp_buffer + p_pic->p->p_pixels = p_b[ p_vout->p_sys->i_index ]->write; + + /* Change display frame */ + if( p_vout->p_sys->b_must_acquire ) + { + ggiResourceRelease( p_b[ p_vout->p_sys->i_index ]->resource ); + } + ggiSetDisplayFrame( p_vout->p_sys->p_display, + p_b[ p_vout->p_sys->i_index ]->frame ); + + /* Swap buffers and change write frame */ + p_vout->p_sys->i_index ^= 1; + p_pic->p->p_pixels = p_b[ p_vout->p_sys->i_index ]->write; + + if( p_vout->p_sys->b_must_acquire ) + { + ggiResourceAcquire( p_b[ p_vout->p_sys->i_index ]->resource, + GGI_ACTYPE_WRITE ); + } + ggiSetWriteFrame( p_vout->p_sys->p_display, + p_b[ p_vout->p_sys->i_index ]->frame ); + + /* Flush the output so that it actually displays */ + ggiFlush( p_vout->p_sys->p_display ); +#undef p_b +} + +/* following functions are local */ + +/***************************************************************************** + * OpenDisplay: open and initialize GGI device + ***************************************************************************** + * Open and initialize display according to preferences specified in the vout + * thread fields. + *****************************************************************************/ +static int OpenDisplay( vout_thread_t *p_vout ) +{ +#define p_b p_vout->p_sys->pp_buffer + ggi_color col_fg; /* foreground color */ + ggi_color col_bg; /* background color */ + int i_index; /* all purposes index */ + char *psz_display; + + /* Initialize library */ + if( ggiInit() ) + { + msg_Err( p_vout, "cannot initialize GGI library" ); + return( 1 ); + } + + /* Open display */ + psz_display = config_GetPsz( p_vout, "ggi_display" ); + + p_vout->p_sys->p_display = ggiOpen( psz_display, NULL ); + if( psz_display ) free( psz_display ); + + if( p_vout->p_sys->p_display == NULL ) + { + msg_Err( p_vout, "cannot open GGI default display" ); + ggiExit(); + return( 1 ); + } + + /* Find most appropriate mode */ + p_vout->p_sys->mode.frames = 2; /* 2 buffers */ + p_vout->p_sys->mode.visible.x = config_GetInt( p_vout, "width" ); + p_vout->p_sys->mode.visible.y = config_GetInt( p_vout, "height" ); + p_vout->p_sys->mode.virt.x = GGI_AUTO; + p_vout->p_sys->mode.virt.y = GGI_AUTO; + p_vout->p_sys->mode.size.x = GGI_AUTO; + p_vout->p_sys->mode.size.y = GGI_AUTO; + p_vout->p_sys->mode.graphtype = GT_15BIT; /* minimum usable depth */ + p_vout->p_sys->mode.dpp.x = GGI_AUTO; + p_vout->p_sys->mode.dpp.y = GGI_AUTO; + ggiCheckMode( p_vout->p_sys->p_display, &p_vout->p_sys->mode ); + + /* FIXME: Check that returned mode has some minimum properties */ + + /* Set mode */ + if( ggiSetMode( p_vout->p_sys->p_display, &p_vout->p_sys->mode ) ) + { + msg_Err( p_vout, "cannot set GGI mode" ); + ggiClose( p_vout->p_sys->p_display ); + ggiExit(); + return( 1 ); + } + + /* Check buffers properties */ + p_vout->p_sys->b_must_acquire = 0; + for( i_index = 0; i_index < 2; i_index++ ) + { + /* Get buffer address */ + p_vout->p_sys->pp_buffer[ i_index ] = + (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display, + i_index ); + if( p_b[ i_index ] == NULL ) + { + msg_Err( p_vout, "double buffering is not possible" ); + ggiClose( p_vout->p_sys->p_display ); + ggiExit(); + return( 1 ); + } + + /* Check buffer properties */ + if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB ) + || ( p_b[ i_index ]->page_size != 0 ) + || ( p_b[ i_index ]->write == NULL ) + || ( p_b[ i_index ]->noaccess != 0 ) + || ( p_b[ i_index ]->align != 0 ) ) + { + msg_Err( p_vout, "incorrect video memory type" ); + ggiClose( p_vout->p_sys->p_display ); + ggiExit(); + return( 1 ); + } + + /* Check if buffer needs to be acquired before write */ + if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) ) + { + p_vout->p_sys->b_must_acquire = 1; + } + } + + /* Set graphic context colors */ + col_fg.r = col_fg.g = col_fg.b = -1; + col_bg.r = col_bg.g = col_bg.b = 0; + if( ggiSetGCForeground(p_vout->p_sys->p_display, + ggiMapColor(p_vout->p_sys->p_display,&col_fg)) || + ggiSetGCBackground(p_vout->p_sys->p_display, + ggiMapColor(p_vout->p_sys->p_display,&col_bg)) ) + { + msg_Err( p_vout, "cannot set colors" ); + ggiClose( p_vout->p_sys->p_display ); + ggiExit(); + return( 1 ); + } + + /* Set clipping for text */ + if( ggiSetGCClipping( p_vout->p_sys->p_display, 0, 0, + p_vout->p_sys->mode.visible.x, + p_vout->p_sys->mode.visible.y ) ) + { + msg_Err( p_vout, "cannot set clipping" ); + ggiClose( p_vout->p_sys->p_display ); + ggiExit(); + return( 1 ); + } + + /* FIXME: set palette in 8bpp */ + p_vout->p_sys->i_bits_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->depth; + + return( 0 ); +#undef p_b +} + +/***************************************************************************** + * CloseDisplay: close and reset GGI device + ***************************************************************************** + * This function returns all resources allocated by OpenDisplay and restore + * the original state of the device. + *****************************************************************************/ +static void CloseDisplay( vout_thread_t *p_vout ) +{ + /* Restore original mode and close display */ + ggiClose( p_vout->p_sys->p_display ); + + /* Exit library */ + ggiExit(); +} + +/***************************************************************************** + * SetPalette: sets an 8 bpp palette + *****************************************************************************/ +static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) +{ + ggi_color colors[256]; + int i; + + /* Fill colors with color information */ + for( i = 0; i < 256; i++ ) + { + colors[ i ].r = red[ i ]; + colors[ i ].g = green[ i ]; + colors[ i ].b = blue[ i ]; + colors[ i ].a = 0; + } + + /* Set palette */ + if( ggiSetPalette( p_vout->p_sys->p_display, 0, 256, colors ) < 0 ) + { + msg_Err( p_vout, "failed setting palette" ); + } +} + diff --git a/modules/video_output/glide/.cvsignore b/modules/video_output/glide/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/glide/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/glide/Makefile b/modules/video_output/glide/Makefile new file mode 100644 index 0000000000..9f3bd7a905 --- /dev/null +++ b/modules/video_output/glide/Makefile @@ -0,0 +1 @@ +glide_SOURCES = glide.c diff --git a/modules/video_output/glide/glide.c b/modules/video_output/glide/glide.c new file mode 100644 index 0000000000..cc484c97f9 --- /dev/null +++ b/modules/video_output/glide/glide.c @@ -0,0 +1,325 @@ +/***************************************************************************** + * glide.c : 3dfx Glide plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: glide.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* malloc(), free() */ +#include + +#include +#include +#include + +#ifndef __linux__ +# include /* for glide ? */ +#endif +#include +#include /* Glide kbhit() and getch() */ + +#define GLIDE_WIDTH 800 +#define GLIDE_HEIGHT 600 +#define GLIDE_BITS_PER_PLANE 16 +#define GLIDE_BYTES_PER_PIXEL 2 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int OpenDisplay ( vout_thread_t * ); +static void CloseDisplay ( vout_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("3dfx Glide module") ); + set_capability( "video output", 20 ); + add_shortcut( "3dfx" ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: Glide video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the Glide specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + GrLfbInfo_t p_buffer_info; /* back buffer info */ + + u8* pp_buffer[2]; + int i_index; +}; + +/***************************************************************************** + * Create: allocates Glide video thread output method + ***************************************************************************** + * This function allocates and initializes a Glide vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* Open and initialize device */ + if( OpenDisplay( p_vout ) ) + { + msg_Err( p_vout, "cannot open display" ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize Glide video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + /* FIXME: we don't set i_chroma !! */ + p_vout->output.i_rmask = 0xf800; + p_vout->output.i_gmask = 0x07e0; + p_vout->output.i_bmask = 0x001f; + + I_OUTPUTPICTURES = 0; + + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + if( p_pic == NULL ) + { + return -1; + } + + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->i_planes = 1; + + p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index]; + p_pic->p->i_lines = GLIDE_HEIGHT; + p_pic->p->i_pitch = p_vout->p_sys->p_buffer_info.strideInBytes; + /*1024 * GLIDE_BYTES_PER_PIXEL*/ + p_pic->p->i_pixel_pitch = GLIDE_BYTES_PER_PIXEL; + p_pic->p->i_visible_pitch = GLIDE_WIDTH * GLIDE_BYTES_PER_PIXEL; + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ 0 ] = p_pic; + + I_OUTPUTPICTURES = 1; + + return 0; +} + +/***************************************************************************** + * End: terminate Glide video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + ; +} + +/***************************************************************************** + * Destroy: destroy Glide video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + CloseDisplay( p_vout ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle Glide events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * console events. It returns a non null value on error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + int buf; + + /* very Linux specific - see tlib.c in Glide for other versions */ + while( kbhit() ) + { + buf = getch(); + + switch( (char)buf ) + { + case 'q': + p_vout->p_vlc->b_die = 1; + break; + + default: + break; + } + } + + return 0; +} + +/***************************************************************************** + * Display: displays previously rendered output + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) + +{ + grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER ); + + grBufferSwap( 0 ); + + if ( grLfbLock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, + GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, + &p_vout->p_sys->p_buffer_info) == FXFALSE ) + { + msg_Err( p_vout, "cannot take 3dfx back buffer lock" ); + } +} + +/* following functions are local */ + +/***************************************************************************** + * OpenDisplay: open and initialize 3dfx device + *****************************************************************************/ + +static int OpenDisplay( vout_thread_t *p_vout ) +{ + static char version[80]; + GrHwConfiguration hwconfig; + GrScreenResolution_t resolution = GR_RESOLUTION_800x600; + GrLfbInfo_t p_front_buffer_info; /* front buffer info */ + + grGlideGetVersion( version ); + grGlideInit(); + + if( !grSstQueryHardware(&hwconfig) ) + { + msg_Err( p_vout, "cannot get 3dfx hardware config" ); + return( 1 ); + } + + grSstSelect( 0 ); + if( !grSstWinOpen( 0, resolution, GR_REFRESH_60Hz, + GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ) + { + msg_Err( p_vout, "cannot open 3dfx screen" ); + return( 1 ); + } + + /* disable dithering */ + //grDitherMode( GR_DITHER_DISABLE ); + + /* clear both buffers */ + grRenderBuffer( GR_BUFFER_BACKBUFFER ); + grBufferClear( 0, 0, 0 ); + grRenderBuffer( GR_BUFFER_FRONTBUFFER ); + grBufferClear( 0, 0, 0 ); + grRenderBuffer( GR_BUFFER_BACKBUFFER ); + + p_vout->p_sys->p_buffer_info.size = sizeof( GrLfbInfo_t ); + p_front_buffer_info.size = sizeof( GrLfbInfo_t ); + + /* lock the buffers to find their adresses */ + if ( grLfbLock(GR_LFB_WRITE_ONLY, GR_BUFFER_FRONTBUFFER, + GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, + &p_front_buffer_info) == FXFALSE ) + { + msg_Err( p_vout, "cannot take 3dfx front buffer lock" ); + grGlideShutdown(); + return( 1 ); + } + grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_FRONTBUFFER ); + + if ( grLfbLock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, + GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, + &p_vout->p_sys->p_buffer_info) == FXFALSE ) + { + msg_Err( p_vout, "cannot take 3dfx back buffer lock" ); + grGlideShutdown(); + return( 1 ); + } + grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER ); + + grBufferClear( 0, 0, 0 ); + + p_vout->p_sys->pp_buffer[0] = p_vout->p_sys->p_buffer_info.lfbPtr; + p_vout->p_sys->pp_buffer[1] = p_front_buffer_info.lfbPtr; + p_vout->p_sys->i_index = 0; + + return( 0 ); +} + +/***************************************************************************** + * CloseDisplay: close and reset 3dfx device + ***************************************************************************** + * Returns all resources allocated by OpenDisplay and restore the original + * state of the device. + *****************************************************************************/ +static void CloseDisplay( vout_thread_t *p_vout ) +{ + /* unlock the hidden buffer */ + grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER ); + + /* shutdown Glide */ + grGlideShutdown(); +} + diff --git a/modules/video_output/mga/.cvsignore b/modules/video_output/mga/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/mga/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/mga/Makefile b/modules/video_output/mga/Makefile new file mode 100644 index 0000000000..5f2c872a31 --- /dev/null +++ b/modules/video_output/mga/Makefile @@ -0,0 +1,2 @@ +mga_SOURCES = mga.c +xmga_SOURCES = xmga.c diff --git a/modules/video_output/mga/mga.c b/modules/video_output/mga/mga.c new file mode 100644 index 0000000000..82114c106c --- /dev/null +++ b/modules/video_output/mga/mga.c @@ -0,0 +1,343 @@ +/***************************************************************************** + * mga.c : Matrox Graphic Array plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: mga.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Aaron Holtzman + * Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* close() */ +#include /* free() */ +#include /* strerror() */ +#include /* open() */ +#include /* ioctl() */ +#include /* PROT_WRITE */ + +#include +#include + +#ifdef SYS_BSD +#include /* typedef ushort */ +#endif + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int NewPicture ( vout_thread_t *, picture_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Matrox Graphic Array video module") ); + set_capability( "video output", 10 ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: video output MGA method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the MGA specific properties of an output thread. + *****************************************************************************/ +#ifndef __LINUX_MGAVID_H +# define __LINUX_MGAVID_H + +# define MGA_VID_CONFIG _IOR('J', 1, mga_vid_config_t) +# define MGA_VID_ON _IO ('J', 2) +# define MGA_VID_OFF _IO ('J', 3) +# define MGA_VID_FSEL _IOR('J', 4, int) +# define MGA_G200 0x1234 +# define MGA_G400 0x5678 + +# define MGA_VID_FORMAT_YV12 0x32315659 +# define MGA_VID_FORMAT_IYUV (('I'<<24)|('Y'<<16)|('U'<<8)|'V') +# define MGA_VID_FORMAT_I420 (('I'<<24)|('4'<<16)|('2'<<8)|'0') +# define MGA_VID_FORMAT_YUY2 (('Y'<<24)|('U'<<16)|('Y'<<8)|'2') +# define MGA_VID_FORMAT_UYVY (('U'<<24)|('Y'<<16)|('V'<<8)|'Y') + +# define MGA_VID_VERSION 0x0201 + +# define MGA_NUM_FRAMES 1 + +typedef struct mga_vid_config_t +{ + u16 version; + u16 card_type; + u32 ram_size; + u32 src_width; + u32 src_height; + u32 dest_width; + u32 dest_height; + u32 x_org; + u32 y_org; + u8 colkey_on; + u8 colkey_red; + u8 colkey_green; + u8 colkey_blue; + u32 format; + u32 frame_size; + u32 num_frames; +} mga_vid_config_t; +#endif + +struct vout_sys_t +{ + mga_vid_config_t mga; + int i_fd; + byte_t * p_video; +}; + +struct picture_sys_t +{ + int i_frame; +}; + +#define CEIL32(x) (((x)+31)&~31) + +/***************************************************************************** + * Create: allocates dummy video thread output method + ***************************************************************************** + * This function allocates and initializes a dummy vout method. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->p_sys->i_fd = open( "/dev/mga_vid", O_RDWR ); + if( p_vout->p_sys->i_fd == -1 ) + { + msg_Err( p_vout, "cannot open MGA driver /dev/mga_vid" ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = NULL; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize dummy video thread output method + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + + /* create the MGA output */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + /* Set coordinates and aspect ratio */ + p_vout->p_sys->mga.src_width = CEIL32(p_vout->output.i_width); + p_vout->p_sys->mga.src_height = p_vout->output.i_height; + vout_PlacePicture( p_vout, 1024, 768, + &p_vout->p_sys->mga.x_org, &p_vout->p_sys->mga.y_org, + &p_vout->p_sys->mga.dest_width, + &p_vout->p_sys->mga.dest_height ); + + /* Initialize a video buffer */ + p_vout->p_sys->mga.colkey_on = 0; + p_vout->p_sys->mga.num_frames = MGA_NUM_FRAMES; + p_vout->p_sys->mga.frame_size = CEIL32(p_vout->output.i_width) + * p_vout->output.i_height * 2; + p_vout->p_sys->mga.version = MGA_VID_VERSION; + + /* Assume we only do YMGA for the moment. XXX: mga_vid calls this + * YV12, but it's actually some strange format with packed UV. */ + p_vout->output.i_chroma = VLC_FOURCC('Y','M','G','A'); + p_vout->p_sys->mga.format = MGA_VID_FORMAT_YV12; + + if( ioctl(p_vout->p_sys->i_fd, MGA_VID_CONFIG, &p_vout->p_sys->mga) ) + { + msg_Err( p_vout, "MGA config ioctl failed" ); + return -1; + } + + if( p_vout->p_sys->mga.card_type == MGA_G200 ) + { + msg_Dbg( p_vout, "detected MGA G200 (%d MB Ram)", + p_vout->p_sys->mga.ram_size ); + } + else + { + msg_Dbg( p_vout, "detected MGA G400/G450 (%d MB Ram)", + p_vout->p_sys->mga.ram_size ); + } + + p_vout->p_sys->p_video = mmap( 0, p_vout->p_sys->mga.frame_size + * MGA_NUM_FRAMES, + PROT_WRITE, MAP_SHARED, + p_vout->p_sys->i_fd, 0 ); + + /* Try to initialize up to MGA_NUM_FRAMES direct buffers */ + while( I_OUTPUTPICTURES < MGA_NUM_FRAMES ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || NewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + /* Blank the windows */ + for( i_index = 0; i_index < I_OUTPUTPICTURES; i_index++ ) + { + memset( p_vout->p_sys->p_video + + p_vout->p_sys->mga.frame_size * i_index, + 0x00, p_vout->p_sys->mga.frame_size / 2 ); + memset( p_vout->p_sys->p_video + + p_vout->p_sys->mga.frame_size * ( 2*i_index + 1 ) / 2, + 0x80, p_vout->p_sys->mga.frame_size / 2 ); + } + + /* Display the image */ + ioctl( p_vout->p_sys->i_fd, MGA_VID_ON, 0 ); + + return( 0 ); +} + +/***************************************************************************** + * End: terminate dummy video thread output method + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + ioctl( p_vout->p_sys->i_fd, MGA_VID_OFF, 0 ); + + /* Free the output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + } +} + +/***************************************************************************** + * Destroy: destroy dummy video thread output method + ***************************************************************************** + * Terminate an output method created by DummyCreateOutputMethod + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + close( p_vout->p_sys->i_fd ); + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Display: displays previously rendered output + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + ioctl( p_vout->p_sys->i_fd, MGA_VID_FSEL, &p_pic->p_sys->i_frame ); +} + +/* Following functions are local */ + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p_data = p_vout->p_sys->p_video + I_OUTPUTPICTURES + * p_vout->p_sys->mga.frame_size; + + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return -1; + } + + p_pic->Y_PIXELS = p_pic->p_data; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = CEIL32( p_vout->output.i_width ); + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width; + + p_pic->U_PIXELS = p_pic->p_data + p_vout->p_sys->mga.frame_size * 2/4; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = CEIL32( p_vout->output.i_width ) / 2; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_data + p_vout->p_sys->mga.frame_size * 3/4; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = CEIL32( p_vout->output.i_width ) / 2; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->p_sys->i_frame = I_OUTPUTPICTURES; + + p_pic->i_planes = 3; + + return 0; +} + diff --git a/modules/video_output/mga/xmga.c b/modules/video_output/mga/xmga.c new file mode 100644 index 0000000000..adac83222a --- /dev/null +++ b/modules/video_output/mga/xmga.c @@ -0,0 +1,1187 @@ +/***************************************************************************** + * xmga.c : X11 MGA plugin for vlc + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: xmga.c,v 1.1 2002/08/04 17:23:43 sam Exp $ + * + * Authors: Vincent Seguin + * Samuel Hocevar + * Gildas Bazin + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include + +#ifdef HAVE_MACHINE_PARAM_H +/* BSD */ +#include +#include /* typedef ushort */ +#include +#endif + +#ifndef WIN32 +#include /* BSD: struct in_addr */ +#endif + +#include /* shmget(), shmctl() */ +#include +#include +#include +#include +#include + +#include "netutils.h" /* network_ChannelJoin */ + +//#include "mga.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); + +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void MGADisplay( vout_thread_t *, picture_t * ); + +static int CreateWindow ( vout_thread_t * ); +static void DestroyWindow ( vout_thread_t * ); + +static int NewPicture ( vout_thread_t *, picture_t * ); +static void FreePicture ( vout_thread_t *, picture_t * ); + +static void ToggleFullScreen ( vout_thread_t * ); + +static void EnableXScreenSaver ( vout_thread_t * ); +static void DisableXScreenSaver ( vout_thread_t * ); + +static void CreateCursor ( vout_thread_t * ); +static void DestroyCursor ( vout_thread_t * ); +static void ToggleCursor ( vout_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +#define ALT_FS_TEXT N_("alternate fullscreen method") +#define ALT_FS_LONGTEXT N_( \ + "There are two ways to make a fullscreen window, unfortunately each one " \ + "has its drawbacks.\n" \ + "1) Let the window manager handle your fullscreen window (default). But " \ + "things like taskbars will likely show on top of the video.\n" \ + "2) Completly bypass the window manager, but then nothing will be able " \ + "to show on top of the video.") + +#define DISPLAY_TEXT N_("X11 display name") +#define DISPLAY_LONGTEXT N_( \ + "Specify the X11 hardware display you want to use. By default vlc will " \ + "use the value of the DISPLAY environment variable.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "xmga-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT ); + add_bool( "xmga-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT ); + set_description( _("X11 MGA module") ); + set_capability( "video output", 60 ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * vout_sys_t: video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the X11 and XVideo specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + /* Internal settings and properties */ + Display * p_display; /* display pointer */ + + Visual * p_visual; /* visual pointer */ + int i_screen; /* screen number */ + Window window; /* root window */ + GC gc; /* graphic context instance handler */ + + vlc_bool_t b_shm; /* shared memory extension flag */ + +#ifdef MODULE_NAME_IS_xvideo + Window yuv_window; /* sub-window for displaying yuv video + data */ + int i_xvport; +#else + Colormap colormap; /* colormap used (8bpp only) */ + + int i_screen_depth; + int i_bytes_per_pixel; + int i_bytes_per_line; + int i_red_mask; + int i_green_mask; + int i_blue_mask; +#endif + + /* X11 generic properties */ + Atom wm_protocols; + Atom wm_delete_window; + + int i_width; /* width of main window */ + int i_height; /* height of main window */ + vlc_bool_t b_altfullscreen; /* which fullscreen method */ + + /* Backup of window position and size before fullscreen switch */ + int i_width_backup; + int i_height_backup; + int i_xpos_backup; + int i_ypos_backup; + int i_width_backup_2; + int i_height_backup_2; + int i_xpos_backup_2; + int i_ypos_backup_2; + + /* Screen saver properties */ + int i_ss_timeout; /* timeout */ + int i_ss_interval; /* interval between changes */ + int i_ss_blanking; /* blanking mode */ + int i_ss_exposure; /* exposure mode */ + BOOL b_ss_dpms; /* DPMS mode */ + + /* Mouse pointer properties */ + vlc_bool_t b_mouse_pointer_visible; + mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/ + Cursor blank_cursor; /* the hidden cursor */ + mtime_t i_time_button_last_pressed; /* to track dbl-clicks */ + Pixmap cursor_pixmap; +}; + +/***************************************************************************** + * mwmhints_t: window manager hints + ***************************************************************************** + * Fullscreen needs to be able to hide the wm decorations so we provide + * this structure to make it easier. + *****************************************************************************/ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 +typedef struct mwmhints_t +{ + u32 flags; + u32 functions; + u32 decorations; + s32 input_mode; + u32 status; +} mwmhints_t; + +/***************************************************************************** + * Chroma defines + *****************************************************************************/ +#ifdef MODULE_NAME_IS_xvideo +# define MAX_DIRECTBUFFERS 5 +#else +# define MAX_DIRECTBUFFERS 2 +#endif + +/***************************************************************************** + * Create: allocate X11 video thread output method + ***************************************************************************** + * This function allocate and initialize a X11 vout method. It uses some of the + * vout properties to choose the window size, and change them according to the + * actual properties of the display. + *****************************************************************************/ +static int Create( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char *psz_display; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* Open display, unsing the "display" config variable or the DISPLAY + * environment variable */ + psz_display = config_GetPsz( p_vout, "xmga-display" ); + p_vout->p_sys->p_display = XOpenDisplay( psz_display ); + + if( p_vout->p_sys->p_display == NULL ) /* error */ + { + msg_Err( p_vout, "cannot open display %s", + XDisplayName( psz_display ) ); + free( p_vout->p_sys ); + if( psz_display ) free( psz_display ); + return( 1 ); + } + if( psz_display ) free( psz_display ); + + p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display ); + + /* Create blank cursor (for mouse cursor autohiding) */ + p_vout->p_sys->b_mouse_pointer_visible = 1; + CreateCursor( p_vout ); + + /* Spawn base window - this window will include the video output window, + * but also command buttons, subtitles and other indicators */ + if( CreateWindow( p_vout ) ) + { + msg_Err( p_vout, "cannot create X11 window" ); + DestroyCursor( p_vout ); + XCloseDisplay( p_vout->p_sys->p_display ); + free( p_vout->p_sys ); + return( 1 ); + } + + /* Disable screen saver */ + DisableXScreenSaver( p_vout ); + + /* Misc init */ + p_vout->p_sys->b_altfullscreen = 0; + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = MGADisplay; + + return( 0 ); +} + +/***************************************************************************** + * Destroy: destroy X11 video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* Restore cursor if it was blanked */ + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + + DestroyCursor( p_vout ); + EnableXScreenSaver( p_vout ); + DestroyWindow( p_vout ); + + XCloseDisplay( p_vout->p_sys->p_display ); + + /* Destroy structure */ + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Init: initialize X11 video thread output method + ***************************************************************************** + * This function create the XImages needed by the output thread. It is called + * at the beginning of the thread, but also each time the window is resized. + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + +#ifdef MODULE_NAME_IS_xvideo + /* Initialize the output structure; we already found an XVideo port, + * and the corresponding chroma we will be using. Since we can + * arbitrary scale, stick to the coordinates and aspect. */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + +#else + /* Initialize the output structure: RGB with square pixels, whatever + * the input format is, since it's the only format we know */ + switch( p_vout->p_sys->i_screen_depth ) + { + case 8: /* FIXME: set the palette */ + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break; + default: + msg_Err( p_vout, "unknown screen depth %i", + p_vout->p_sys->i_screen_depth ); + return( 0 ); + } + + p_vout->output.i_width = p_vout->p_sys->i_width; + p_vout->output.i_height = p_vout->p_sys->i_height; + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->p_sys->i_width + * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height; +#endif + + /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || NewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * MGADisplay: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to X11 server. + * (The Xv extension takes care of "double-buffering".) + *****************************************************************************/ +static void MGADisplay( vout_thread_t *p_vout, picture_t *p_pic ) +{ + int i_width, i_height, i_x, i_y; + + vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, + &i_x, &i_y, &i_width, &i_height ); +} + +/***************************************************************************** + * Manage: handle X11 events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * X11 events and allows window resizing. It returns a non null value on + * error. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + XEvent xevent; /* X11 event */ + vlc_bool_t b_resized; /* window has been resized */ + char i_key; /* ISO Latin-1 key */ + KeySym x_key_symbol; + + /* Handle X11 events: ConfigureNotify events are parsed to know if the + * output window's size changed, MapNotify and UnmapNotify to know if the + * window is mapped (and if the display is useful), and ClientMessages + * to intercept window destruction requests */ + + b_resized = 0; + while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | Button1MotionMask , &xevent ) + == True ) + { + /* ConfigureNotify event: prepare */ + if( (xevent.type == ConfigureNotify) + && ((xevent.xconfigure.width != p_vout->p_sys->i_width) + || (xevent.xconfigure.height != p_vout->p_sys->i_height)) ) + { + /* Update dimensions */ + b_resized = 1; + p_vout->i_changes |= VOUT_SIZE_CHANGE; + p_vout->p_sys->i_width = xevent.xconfigure.width; + p_vout->p_sys->i_height = xevent.xconfigure.height; + } + /* Keyboard event */ + else if( xevent.type == KeyPress ) + { + /* We may have keys like F1 trough F12, ESC ... */ + x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display, + xevent.xkey.keycode, 0 ); + switch( x_key_symbol ) + { + case XK_Escape: + p_vout->p_vlc->b_die = 1; + break; + case XK_Menu: + p_vout->p_vlc->p_intf->b_menu_change = 1; + break; + case XK_Left: + input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Right: + input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Up: + input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Down: + input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Home: + input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_SET ); + break; + case XK_End: + input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_END ); + break; + case XK_Page_Up: + input_Seek( p_vout, 900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Page_Down: + input_Seek( p_vout, -900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_space: + input_SetStatus( p_input_bank->pp_input[0], + INPUT_STATUS_PAUSE ); + break; + + case XK_F1: network_ChannelJoin( p_vout, 1 ); break; + case XK_F2: network_ChannelJoin( p_vout, 2 ); break; + case XK_F3: network_ChannelJoin( p_vout, 3 ); break; + case XK_F4: network_ChannelJoin( p_vout, 4 ); break; + case XK_F5: network_ChannelJoin( p_vout, 5 ); break; + case XK_F6: network_ChannelJoin( p_vout, 6 ); break; + case XK_F7: network_ChannelJoin( p_vout, 7 ); break; + case XK_F8: network_ChannelJoin( p_vout, 8 ); break; + case XK_F9: network_ChannelJoin( p_vout, 9 ); break; + case XK_F10: network_ChannelJoin( p_vout, 10 ); break; + case XK_F11: network_ChannelJoin( p_vout, 11 ); break; + case XK_F12: network_ChannelJoin( p_vout, 12 ); break; + + default: + /* "Normal Keys" + * The reason why I use this instead of XK_0 is that + * with XLookupString, we don't have to care about + * keymaps. */ + + if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) ) + { + /* FIXME: handle stuff here */ + switch( i_key ) + { + case 'q': + case 'Q': + p_vout->p_vlc->b_die = 1; + break; + case 'f': + case 'F': + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + default: + break; + } + } + break; + } + } + /* Mouse click */ + else if( xevent.type == ButtonPress ) + { + switch( ((XButtonEvent *)&xevent)->button ) + { + case Button1: + /* In this part we will eventually manage + * clicks for DVD navigation for instance. */ + + /* detect double-clicks */ + if( ( ((XButtonEvent *)&xevent)->time - + p_vout->p_sys->i_time_button_last_pressed ) < 300 ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + } + + p_vout->p_sys->i_time_button_last_pressed = + ((XButtonEvent *)&xevent)->time; + break; + + case Button4: + input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case Button5: + input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + } + } + /* Mouse release */ + else if( xevent.type == ButtonRelease ) + { + switch( ((XButtonEvent *)&xevent)->button ) + { + case Button3: + /* FIXME: need locking ! */ + p_vout->p_vlc->p_intf->b_menu_change = 1; + break; + } + } + /* Mouse move */ + else if( xevent.type == MotionNotify ) + { + p_vout->p_sys->i_time_mouse_last_moved = mdate(); + if( ! p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + } + /* Other event */ + else + { + msg_Warn( p_vout, "unhandled event %d received", xevent.type ); + } + } + + /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data + * are handled - according to the man pages, the format is always 32 + * in this case */ + while( XCheckTypedEvent( p_vout->p_sys->p_display, + ClientMessage, &xevent ) ) + { + if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols) + && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) ) + { + p_vout->p_vlc->b_die = 1; + } + } + + /* + * Fullscreen Change + */ + if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + ToggleFullScreen( p_vout ); + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + + } + + /* + * Size change + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + int i_width, i_height, i_x, i_y; + + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + + msg_Dbg( p_vout, "video display resized (%dx%d)", + p_vout->p_sys->i_width, p_vout->p_sys->i_height ); + + vout_PlacePicture( p_vout, p_vout->p_sys->i_width, + p_vout->p_sys->i_height, + &i_x, &i_y, &i_width, &i_height ); + } + + /* Autohide Cursour */ + if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 ) + { + /* Hide the mouse automatically */ + if( p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + } + + return 0; +} + +/***************************************************************************** + * End: terminate X11 video thread output method + ***************************************************************************** + * Destroy the X11 XImages created by Init. It is called at the end of + * the thread, but also each time the window is resized. + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); + } +} + +/* following functions are local */ + +/***************************************************************************** + * CreateWindow: open and set-up X11 main window + *****************************************************************************/ +static int CreateWindow( vout_thread_t *p_vout ) +{ + XSizeHints xsize_hints; + XSetWindowAttributes xwindow_attributes; + XGCValues xgcvalues; + XEvent xevent; + + vlc_bool_t b_expose; + vlc_bool_t b_configure_notify; + vlc_bool_t b_map_notify; + + /* Set main window's size */ + p_vout->p_sys->i_width = p_vout->i_window_width; + p_vout->p_sys->i_height = p_vout->i_window_height; + + /* Prepare window manager hints and properties */ + xsize_hints.base_width = p_vout->p_sys->i_width; + xsize_hints.base_height = p_vout->p_sys->i_height; + xsize_hints.flags = PSize; + p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display, + "WM_PROTOCOLS", True ); + p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display, + "WM_DELETE_WINDOW", True ); + + /* Prepare window attributes */ + xwindow_attributes.backing_store = Always; /* save the hidden part */ + xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display, + p_vout->p_sys->i_screen); + xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask; + + + /* Create the window and set hints - the window must receive + * ConfigureNotify events, and until it is displayed, Expose and + * MapNotify events. */ + + p_vout->p_sys->window = + XCreateWindow( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, 0, + p_vout->p_sys->i_width, + p_vout->p_sys->i_height, + 0, + 0, InputOutput, 0, + CWBackingStore | CWBackPixel | CWEventMask, + &xwindow_attributes ); + + /* Set window manager hints and properties: size hints, command, + * window's name, and accepted protocols */ + XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window, + &xsize_hints ); + XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window, + p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc ); + XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window, + VOUT_TITLE " (XMGA output)" + ); + + if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */ + || (p_vout->p_sys->wm_delete_window == None) + || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window, + &p_vout->p_sys->wm_delete_window, 1 ) ) + { + /* WM_DELETE_WINDOW is not supported by window manager */ + msg_Err( p_vout, "missing or bad window manager" ); + } + + /* Creation of a graphic context that doesn't generate a GraphicsExpose + * event when using functions like XCopyArea */ + xgcvalues.graphics_exposures = False; + p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display, + p_vout->p_sys->window, + GCGraphicsExposures, &xgcvalues); + + /* Send orders to server, and wait until window is displayed - three + * events must be received: a MapNotify event, an Expose event allowing + * drawing in the window, and a ConfigureNotify to get the window + * dimensions. Once those events have been received, only ConfigureNotify + * events need to be received. */ + b_expose = 0; + b_configure_notify = 0; + b_map_notify = 0; + XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window); + do + { + XNextEvent( p_vout->p_sys->p_display, &xevent); + if( (xevent.type == Expose) + && (xevent.xexpose.window == p_vout->p_sys->window) ) + { + b_expose = 1; + } + else if( (xevent.type == MapNotify) + && (xevent.xmap.window == p_vout->p_sys->window) ) + { + b_map_notify = 1; + } + else if( (xevent.type == ConfigureNotify) + && (xevent.xconfigure.window == p_vout->p_sys->window) ) + { + b_configure_notify = 1; + p_vout->p_sys->i_width = xevent.xconfigure.width; + p_vout->p_sys->i_height = xevent.xconfigure.height; + } + } while( !( b_expose && b_configure_notify && b_map_notify ) ); + + XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask ); + + /* If the cursor was formerly blank than blank it again */ + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + ToggleCursor( p_vout ); + } + + XSync( p_vout->p_sys->p_display, False ); + + /* At this stage, the window is open, displayed, and ready to + * receive data */ + + return( 0 ); +} + +/***************************************************************************** + * DestroyWindow: destroy the window + ***************************************************************************** + * + *****************************************************************************/ +static void DestroyWindow( vout_thread_t *p_vout ) +{ + XSync( p_vout->p_sys->p_display, False ); + + XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window ); + XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc ); + XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window ); +} + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + switch( p_vout->output.i_chroma ) + { + /* XXX ?? */ + + default: + /* Unknown chroma, tell the guy to get lost */ + msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)", + p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma ); + p_pic->i_planes = 0; + return -1; + } + + return 0; +} + +/***************************************************************************** + * FreePicture: destroy a picture allocated with NewPicture + ***************************************************************************** + * Destroy XImage AND associated data. If using Shm, detach shared memory + * segment from server and process, then free it. The XDestroyImage manpage + * says that both the image structure _and_ the data pointed to by the + * image structure are freed, so no need to free p_image->data. + *****************************************************************************/ +static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + XSync( p_vout->p_sys->p_display, False ); +} + +/***************************************************************************** + * ToggleFullScreen: Enable or disable full screen mode + ***************************************************************************** + * This function will switch between fullscreen and window mode. + * + *****************************************************************************/ +static void ToggleFullScreen ( vout_thread_t *p_vout ) +{ + Atom prop; + mwmhints_t mwmhints; + int i_xpos, i_ypos, i_width, i_height; + XEvent xevent; + XSetWindowAttributes attributes; + + p_vout->b_fullscreen = !p_vout->b_fullscreen; + + if( p_vout->b_fullscreen ) + { + Window next_parent, parent, *p_dummy, dummy1; + unsigned int dummy2, dummy3; + + msg_Dbg( p_vout, "entering fullscreen mode" ); + + /* Only check the fullscreen method when we actually go fullscreen, + * because to go back to window mode we need to know in which + * fullscreen mode we where */ + p_vout->p_sys->b_altfullscreen = config_GetInt( p_vout, + "xmga-altfullscreen" ); + + /* Save current window coordinates so they can be restored when + * we exit from fullscreen mode. This is the tricky part because + * this heavily depends on the behaviour of the window manager. + * When you use XMoveWindow some window managers will adjust the top + * of the window to the coordinates you gave, but others will instead + * adjust the top of the client area to the coordinates + * (don't forget windows have decorations). */ + + /* First, get the position and size of the client area */ + XGetGeometry( p_vout->p_sys->p_display, + p_vout->p_sys->window, + &dummy1, + &dummy2, + &dummy3, + &p_vout->p_sys->i_width_backup_2, + &p_vout->p_sys->i_height_backup_2, + &dummy2, &dummy3 ); + XTranslateCoordinates( p_vout->p_sys->p_display, + p_vout->p_sys->window, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, + 0, + &p_vout->p_sys->i_xpos_backup_2, + &p_vout->p_sys->i_ypos_backup_2, + &dummy1 ); + + /* Then try to get the position and size of the whole window */ + + /* find the real parent of our window (created by the window manager), + * the one which is a direct child of the root window */ + next_parent = parent = p_vout->p_sys->window; + while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) ) + { + parent = next_parent; + XQueryTree( p_vout->p_sys->p_display, + parent, + &dummy1, + &next_parent, + &p_dummy, + &dummy2 ); + XFree((void *)p_dummy); + } + + XGetGeometry( p_vout->p_sys->p_display, + p_vout->p_sys->window, + &dummy1, + &dummy2, + &dummy3, + &p_vout->p_sys->i_width_backup, + &p_vout->p_sys->i_height_backup, + &dummy2, &dummy3 ); + + XTranslateCoordinates( p_vout->p_sys->p_display, + parent, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, + 0, + &p_vout->p_sys->i_xpos_backup, + &p_vout->p_sys->i_ypos_backup, + &dummy1 ); + + /* fullscreen window size and position */ + i_xpos = 0; + i_ypos = 0; + i_width = DisplayWidth( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ); + i_height = DisplayHeight( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ); + + } + else + { + msg_Dbg( p_vout, "leaving fullscreen mode" ); + + i_xpos = p_vout->p_sys->i_xpos_backup; + i_ypos = p_vout->p_sys->i_ypos_backup; + i_width = p_vout->p_sys->i_width_backup; + i_height = p_vout->p_sys->i_height_backup; + } + + /* To my knowledge there are two ways to create a borderless window. + * There's the generic way which is to tell x to bypass the window manager, + * but this creates problems with the focus of other applications. + * The other way is to use the motif property "_MOTIF_WM_HINTS" which + * luckily seems to be supported by most window managers. + */ + if( !p_vout->p_sys->b_altfullscreen ) + { + mwmhints.flags = MWM_HINTS_DECORATIONS; + mwmhints.decorations = !p_vout->b_fullscreen; + + prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", + False ); + XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window, + prop, prop, 32, PropModeReplace, + (unsigned char *)&mwmhints, + PROP_MWM_HINTS_ELEMENTS ); + } + else + { + /* brute force way to remove decorations */ + attributes.override_redirect = p_vout->b_fullscreen; + XChangeWindowAttributes( p_vout->p_sys->p_display, + p_vout->p_sys->window, + CWOverrideRedirect, + &attributes); + } + + /* We need to unmap and remap the window if we want the window + * manager to take our changes into effect */ + XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window); + + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( xevent.type != UnmapNotify ) + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + + XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window); + + while( xevent.type != MapNotify ) + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + + XMoveResizeWindow( p_vout->p_sys->p_display, + p_vout->p_sys->window, + i_xpos, + i_ypos, + i_width, + i_height ); + + /* Purge all ConfigureNotify events, this is needed to fix a bug where we + * would lose the original size of the window */ + while( xevent.type != ConfigureNotify ) + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ) ); + + + /* We need to check that the window was really restored where we wanted */ + if( !p_vout->b_fullscreen ) + { + Window dummy1; + unsigned int dummy2, dummy3, dummy4, dummy5; + + /* Check the position */ + XTranslateCoordinates( p_vout->p_sys->p_display, + p_vout->p_sys->window, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, + 0, + &dummy2, + &dummy3, + &dummy1 ); + if( dummy2 != p_vout->p_sys->i_xpos_backup_2 || + dummy3 != p_vout->p_sys->i_ypos_backup_2 ) + { + /* Ok it didn't work... second try */ + + XMoveWindow( p_vout->p_sys->p_display, + p_vout->p_sys->window, + p_vout->p_sys->i_xpos_backup_2, + p_vout->p_sys->i_ypos_backup_2 ); + + /* Purge all ConfigureNotify events, this is needed to fix a bug + * where we would lose the original size of the window */ + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( xevent.type != ConfigureNotify ) + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( XCheckWindowEvent( p_vout->p_sys->p_display, + p_vout->p_sys->window, + StructureNotifyMask, &xevent ) ); + } + + /* Check the size */ + XGetGeometry( p_vout->p_sys->p_display, + p_vout->p_sys->window, + &dummy1, + &dummy2, + &dummy3, + &dummy4, + &dummy5, + &dummy2, &dummy3 ); + + if( dummy4 != p_vout->p_sys->i_width_backup_2 || + dummy5 != p_vout->p_sys->i_height_backup_2 ) + { + /* Ok it didn't work... third try */ + + XResizeWindow( p_vout->p_sys->p_display, + p_vout->p_sys->window, + p_vout->p_sys->i_width_backup_2, + p_vout->p_sys->i_height_backup_2 ); + + /* Purge all ConfigureNotify events, this is needed to fix a bug + * where we would lose the original size of the window */ + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( xevent.type != ConfigureNotify ) + XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window, + StructureNotifyMask, &xevent ); + while( XCheckWindowEvent( p_vout->p_sys->p_display, + p_vout->p_sys->window, + StructureNotifyMask, &xevent ) ); + } + } + + if( p_vout->p_sys->b_altfullscreen ) + XSetInputFocus(p_vout->p_sys->p_display, + p_vout->p_sys->window, + RevertToParent, + CurrentTime); + + /* signal that the size needs to be updated */ + p_vout->p_sys->i_width = i_width; + p_vout->p_sys->i_height = i_height; + p_vout->i_changes |= VOUT_SIZE_CHANGE; + +} + +/***************************************************************************** + * EnableXScreenSaver: enable screen saver + ***************************************************************************** + * This function enables the screen saver on a display after it has been + * disabled by XDisableScreenSaver. + * FIXME: what happens if multiple vlc sessions are running at the same + * time ??? + *****************************************************************************/ +static void EnableXScreenSaver( vout_thread_t *p_vout ) +{ + int dummy; + + XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout, + p_vout->p_sys->i_ss_interval, + p_vout->p_sys->i_ss_blanking, + p_vout->p_sys->i_ss_exposure ); + + /* Restore DPMS settings */ + if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) ) + { + if( p_vout->p_sys->b_ss_dpms ) + { + DPMSEnable( p_vout->p_sys->p_display ); + } + } +} + +/***************************************************************************** + * DisableXScreenSaver: disable screen saver + ***************************************************************************** + * See XEnableXScreenSaver + *****************************************************************************/ +static void DisableXScreenSaver( vout_thread_t *p_vout ) +{ + int dummy; + + /* Save screen saver informations */ + XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout, + &p_vout->p_sys->i_ss_interval, + &p_vout->p_sys->i_ss_blanking, + &p_vout->p_sys->i_ss_exposure ); + + /* Disable screen saver */ + XSetScreenSaver( p_vout->p_sys->p_display, 0, + p_vout->p_sys->i_ss_interval, + p_vout->p_sys->i_ss_blanking, + p_vout->p_sys->i_ss_exposure ); + + /* Disable DPMS */ + if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) ) + { + CARD16 dummy; + /* Save DPMS current state */ + DPMSInfo( p_vout->p_sys->p_display, &dummy, + &p_vout->p_sys->b_ss_dpms ); + DPMSDisable( p_vout->p_sys->p_display ); + } +} + +/***************************************************************************** + * CreateCursor: create a blank mouse pointer + *****************************************************************************/ +static void CreateCursor( vout_thread_t *p_vout ) +{ + XColor cursor_color; + + p_vout->p_sys->cursor_pixmap = + XCreatePixmap( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + 1, 1, 1 ); + + XParseColor( p_vout->p_sys->p_display, + XCreateColormap( p_vout->p_sys->p_display, + DefaultRootWindow( + p_vout->p_sys->p_display ), + DefaultVisual( + p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ), + AllocNone ), + "black", &cursor_color ); + + p_vout->p_sys->blank_cursor = + XCreatePixmapCursor( p_vout->p_sys->p_display, + p_vout->p_sys->cursor_pixmap, + p_vout->p_sys->cursor_pixmap, + &cursor_color, &cursor_color, 1, 1 ); +} + +/***************************************************************************** + * DestroyCursor: destroy the blank mouse pointer + *****************************************************************************/ +static void DestroyCursor( vout_thread_t *p_vout ) +{ + XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap ); +} + +/***************************************************************************** + * ToggleCursor: hide or show the mouse pointer + ***************************************************************************** + * This function hides the X pointer if it is visible by setting the pointer + * sprite to a blank one. To show it again, we disable the sprite. + *****************************************************************************/ +static void ToggleCursor( vout_thread_t *p_vout ) +{ + if( p_vout->p_sys->b_mouse_pointer_visible ) + { + XDefineCursor( p_vout->p_sys->p_display, + p_vout->p_sys->window, + p_vout->p_sys->blank_cursor ); + p_vout->p_sys->b_mouse_pointer_visible = 0; + } + else + { + XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window ); + p_vout->p_sys->b_mouse_pointer_visible = 1; + } +} + diff --git a/modules/video_output/sdl/.cvsignore b/modules/video_output/sdl/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/sdl/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/sdl/Makefile b/modules/video_output/sdl/Makefile new file mode 100644 index 0000000000..0a57b49304 --- /dev/null +++ b/modules/video_output/sdl/Makefile @@ -0,0 +1 @@ +sdl_SOURCES = sdl.c vout.c aout.c diff --git a/modules/video_output/sdl/aout.c b/modules/video_output/sdl/aout.c new file mode 100644 index 0000000000..0c6f15286f --- /dev/null +++ b/modules/video_output/sdl/aout.c @@ -0,0 +1,280 @@ +/***************************************************************************** + * aout_sdl.c : audio sdl functions library + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: aout.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Michel Kaempf + * Samuel Hocevar + * Pierre Baillet + * + * 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 /* ENOMEM */ +#include /* open(), O_WRONLY */ +#include /* strerror() */ +#include /* write(), close() */ +#include /* calloc(), malloc(), free() */ + +#include +#include + +#include SDL_INCLUDE_FILE + +/***************************************************************************** + * 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. + *****************************************************************************/ + +/* the overflow limit is used to prevent the fifo from growing too big */ +#define OVERFLOWLIMIT 100000 + +struct aout_sys_t +{ + byte_t * audio_buf; + int i_audio_end; + + vlc_bool_t b_active; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int SetFormat ( aout_thread_t * ); +static int GetBufInfo ( aout_thread_t *, int ); +static void Play ( aout_thread_t *, byte_t *, int ); + +static void SDLCallback ( void *, Uint8 *, int ); + +/***************************************************************************** + * OpenAudio: open the audio device + ***************************************************************************** + * This function opens the dsp as a usual non-blocking write-only file, and + * modifies the p_aout->i_fd with the file's descriptor. + *****************************************************************************/ +int E_(OpenAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + SDL_AudioSpec desired; + + if( SDL_WasInit( SDL_INIT_AUDIO ) != 0 ) + { + return( 1 ); + } + + p_aout->pf_setformat = SetFormat; + p_aout->pf_getbufinfo = GetBufInfo; + p_aout->pf_play = 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 library */ + if( SDL_Init( SDL_INIT_AUDIO +#ifndef WIN32 + /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/ + | SDL_INIT_EVENTTHREAD +#endif +#ifdef DEBUG + /* In debug mode you may want vlc to dump a core instead of staying + * stuck */ + | SDL_INIT_NOPARACHUTE +#endif + ) < 0 ) + { + msg_Err( p_aout, "cannot initialize SDL (%s)", SDL_GetError() ); + free( p_aout->p_sys ); + return( 1 ); + } + + p_aout->p_sys->i_audio_end = 0; + p_aout->p_sys->audio_buf = malloc( OVERFLOWLIMIT ); + + /* Initialize some variables */ + + /* TODO: write conversion beetween AOUT_FORMAT_DEFAULT + * AND AUDIO* from SDL. */ + desired.freq = p_aout->i_rate; +#ifdef WORDS_BIGENDIAN + desired.format = AUDIO_S16MSB; /* stereo 16 bits */ +#else + desired.format = AUDIO_S16LSB; /* stereo 16 bits */ +#endif + desired.channels = p_aout->i_channels; + desired.callback = SDLCallback; + desired.userdata = p_aout->p_sys; + desired.samples = 1024; + + /* Open the sound device + * we just ask the SDL to wrap at the good frequency if the one we + * ask for is unavailable. This is done by setting the second parar + * to NULL + */ + if( SDL_OpenAudio( &desired, NULL ) < 0 ) + { + msg_Err( p_aout, "SDL_OpenAudio failed (%s)", SDL_GetError() ); + SDL_QuitSubSystem( SDL_INIT_AUDIO ); + free( p_aout->p_sys ); + return( -1 ); + } + + p_aout->p_sys->b_active = 1; + SDL_PauseAudio( 0 ); + + return( 0 ); +} + +/***************************************************************************** + * SetFormat: reset the audio device and sets its format + ***************************************************************************** + * This functions resets the audio 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 ) +{ + /* TODO: finish and clean this */ + SDL_AudioSpec desired; + + /*i_format = p_aout->i_format;*/ + desired.freq = p_aout->i_rate; /* Set the output rate */ +#ifdef WORDS_BIGENDIAN + desired.format = AUDIO_S16MSB; /* stereo 16 bits */ +#else + desired.format = AUDIO_S16LSB; /* stereo 16 bits */ +#endif + desired.channels = p_aout->i_channels; + desired.callback = SDLCallback; + desired.userdata = p_aout->p_sys; + desired.samples = 2048; + + /* Open the sound device */ + SDL_PauseAudio( 1 ); + SDL_CloseAudio(); + + if( SDL_OpenAudio( &desired, NULL ) < 0 ) + { + p_aout->p_sys->b_active = 0; + return( -1 ); + } + + p_aout->p_sys->b_active = 1; + SDL_PauseAudio( 0 ); + + return( 0 ); +} + +/***************************************************************************** + * GetBufInfo: buffer status query + ***************************************************************************** + * returns the number of bytes in the audio buffer compared to the size of + * i_buffer_limit... + *****************************************************************************/ +static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +{ + if(i_buffer_limit > p_aout->p_sys->i_audio_end) + { + /* returning 0 here juste gives awful sound in the speakers :/ */ + return( i_buffer_limit ); + } + return( p_aout->p_sys->i_audio_end - i_buffer_limit); +} + +/***************************************************************************** + * Play: play 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 ) +{ + byte_t * audio_buf = p_aout->p_sys->audio_buf; + + SDL_LockAudio(); /* Stop callbacking */ + + p_aout->p_sys->audio_buf = realloc( audio_buf, + p_aout->p_sys->i_audio_end + i_size); + memcpy( p_aout->p_sys->audio_buf + p_aout->p_sys->i_audio_end, + buffer, i_size); + + p_aout->p_sys->i_audio_end += i_size; + + SDL_UnlockAudio(); /* go on callbacking */ +} + +/***************************************************************************** + * CloseAudio: close the audio device + *****************************************************************************/ +void E_(CloseAudio) ( vlc_object_t *p_this ) +{ + aout_thread_t * p_aout = (aout_thread_t *)p_this; + + if( p_aout->p_sys->b_active ) + { + SDL_PauseAudio( 1 ); /* pause audio */ + + if( p_aout->p_sys->audio_buf != NULL ) /* do we have a buffer now ? */ + { + free( p_aout->p_sys->audio_buf ); + } + } + + SDL_CloseAudio(); + + SDL_QuitSubSystem( SDL_INIT_AUDIO ); + + free( p_aout->p_sys ); /* Close the Output. */ +} + +/***************************************************************************** + * SDLCallback: what to do once SDL has played sound samples + *****************************************************************************/ +static void SDLCallback( void *userdata, byte_t *stream, int len ) +{ + aout_sys_t * p_sys = userdata; + + if( p_sys->i_audio_end > OVERFLOWLIMIT ) + { +//X msg_Err( p_aout, "aout_SDLCallback overflowed" ); + + free( p_sys->audio_buf ); + p_sys->audio_buf = NULL; + + p_sys->i_audio_end = 0; + /* we've gone to slow, increase output freq */ + } + + /* if we are not in underrun */ + if( p_sys->i_audio_end > len ) + { + p_sys->i_audio_end -= len; + memcpy( stream, p_sys->audio_buf, len ); + memmove( p_sys->audio_buf, p_sys->audio_buf + len, p_sys->i_audio_end ); + } +} + diff --git a/modules/video_output/sdl/sdl.c b/modules/video_output/sdl/sdl.c new file mode 100644 index 0000000000..fcecfb9d7c --- /dev/null +++ b/modules/video_output/sdl/sdl.c @@ -0,0 +1,55 @@ +/***************************************************************************** + * sdl.c : SDL plugin for vlc + ***************************************************************************** + * Copyright (C) 2000, 2001 VideoLAN + * $Id: sdl.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Samuel Hocevar + * Pierre Baillet + * Arnaud de Bossoreille de Ribou + * + * 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 /* malloc(), free() */ +#include + +#include + +/***************************************************************************** + * External prototypes + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t * ); +void E_(CloseVideo) ( vlc_object_t * ); + +int E_(OpenAudio) ( vlc_object_t * ); +void E_(CloseAudio) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Simple DirectMedia Layer module") ); + add_submodule(); + set_capability( "video output", 40 ); + set_callbacks( E_(OpenVideo), E_(CloseVideo) ); + add_submodule(); + set_capability( "audio output", 40 ); + set_callbacks( E_(OpenAudio), E_(CloseAudio) ); +vlc_module_end(); + diff --git a/modules/video_output/sdl/vout.c b/modules/video_output/sdl/vout.c new file mode 100644 index 0000000000..06d7fb41e4 --- /dev/null +++ b/modules/video_output/sdl/vout.c @@ -0,0 +1,862 @@ +/***************************************************************************** + * vout_sdl.c: SDL video output display method + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: vout.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Samuel Hocevar + * Pierre Baillet + * Arnaud de Bossoreille de Ribou + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include + +#include +#ifndef WIN32 +# include /* BSD: struct in_addr */ +#endif + +#include SDL_INCLUDE_FILE + +#include "netutils.h" + +#define SDL_MAX_DIRECTBUFFERS 10 +#define SDL_DEFAULT_BPP 16 + +/***************************************************************************** + * vout_sys_t: video output SDL method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the SDL specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + SDL_Surface * p_display; /* display device */ + + int i_width; + int i_height; + + /* For YUV output */ + SDL_Overlay * p_overlay; /* An overlay we keep to grab the XVideo port */ + + /* For RGB output */ + int i_surfaces; + + vlc_bool_t b_cursor; + vlc_bool_t b_cursor_autohidden; + mtime_t i_lastmoved; + mtime_t i_lastpressed; /* to track dbl-clicks */ +}; + +/***************************************************************************** + * picture_sys_t: direct buffer method descriptor + ***************************************************************************** + * This structure is part of the picture descriptor, it describes the + * SDL specific properties of a direct buffer. + *****************************************************************************/ +struct picture_sys_t +{ + SDL_Overlay *p_overlay; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Init ( vout_thread_t * ); +static void End ( vout_thread_t * ); +static int Manage ( vout_thread_t * ); +static void Display ( vout_thread_t *, picture_t * ); + +static int OpenDisplay ( vout_thread_t * ); +static void CloseDisplay ( vout_thread_t * ); +static int NewPicture ( vout_thread_t *, picture_t * ); +static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); + +/***************************************************************************** + * OpenVideo: allocate SDL video thread output method + ***************************************************************************** + * This function allocate and initialize a SDL vout method. It uses some of the + * vout properties to choose the correct mode, and change them according to the + * mode actually used. + *****************************************************************************/ +int E_(OpenVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + +#ifdef HAVE_SETENV + char *psz_method; +#endif + + if( SDL_WasInit( SDL_INIT_VIDEO ) != 0 ) + { + return( 1 ); + } + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + p_vout->pf_init = Init; + p_vout->pf_end = End; + p_vout->pf_manage = Manage; + p_vout->pf_render = NULL; + p_vout->pf_display = Display; + +#ifdef HAVE_SETENV + psz_method = config_GetPsz( p_vout, "vout" ); + if( psz_method ) + { + while( *psz_method && *psz_method != ':' ) + { + psz_method++; + } + + if( *psz_method ) + { + setenv( "SDL_VIDEODRIVER", psz_method + 1, 1 ); + } + } +#endif + + /* Initialize library */ + if( SDL_Init( SDL_INIT_VIDEO +#ifndef WIN32 + /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/ + | SDL_INIT_EVENTTHREAD +#endif +#ifdef DEBUG + /* In debug mode you may want vlc to dump a core instead of staying + * stuck */ + | SDL_INIT_NOPARACHUTE +#endif + ) < 0 ) + { + msg_Err( p_vout, "cannot initialize SDL (%s)", SDL_GetError() ); + free( p_vout->p_sys ); + return( 1 ); + } + + p_vout->p_sys->b_cursor = 1; + p_vout->p_sys->b_cursor_autohidden = 0; + p_vout->p_sys->i_lastmoved = mdate(); + + if( OpenDisplay( p_vout ) ) + { + msg_Err( p_vout, "cannot set up SDL (%s)", SDL_GetError() ); + SDL_QuitSubSystem( SDL_INIT_VIDEO ); + free( p_vout->p_sys ); + return( 1 ); + } + + return( 0 ); +} + +/***************************************************************************** + * Init: initialize SDL video thread output method + ***************************************************************************** + * This function initialize the SDL display device. + *****************************************************************************/ +static int Init( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + p_vout->p_sys->i_surfaces = 0; + + I_OUTPUTPICTURES = 0; + + /* Initialize the output structure */ + if( p_vout->p_sys->p_overlay == NULL ) + { + /* All we have is an RGB image with square pixels */ + p_vout->output.i_width = p_vout->p_sys->i_width; + p_vout->output.i_height = p_vout->p_sys->i_height; + p_vout->output.i_aspect = p_vout->output.i_width + * VOUT_ASPECT_FACTOR + / p_vout->output.i_height; + } + else + { + /* We may need to convert the chroma, but at least we keep the + * aspect ratio */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + } + + /* Try to initialize SDL_MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < SDL_MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture if we found one */ + if( p_pic == NULL || NewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + +/***************************************************************************** + * End: terminate Sys video thread output method + ***************************************************************************** + * Terminate an output method created by OpenVideo + *****************************************************************************/ +static void End( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the output buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + if( p_vout->p_sys->p_overlay == NULL ) + { + /* RGB picture */ + } + else + { + SDL_UnlockYUVOverlay( + PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay ); + SDL_FreeYUVOverlay( + PP_OUTPUTPICTURE[ i_index ]->p_sys->p_overlay ); + } + free( PP_OUTPUTPICTURE[ i_index ]->p_sys ); + } +} + +/***************************************************************************** + * CloseVideo: destroy Sys video thread output method + ***************************************************************************** + * Terminate an output method created by vout_SDLCreate + *****************************************************************************/ +void E_(CloseVideo) ( vlc_object_t *p_this ) +{ + vout_thread_t * p_vout = (vout_thread_t *)p_this; + + CloseDisplay( p_vout ); + SDL_QuitSubSystem( SDL_INIT_VIDEO ); + + free( p_vout->p_sys ); +} + +/***************************************************************************** + * Manage: handle Sys events + ***************************************************************************** + * This function should be called regularly by video output thread. It returns + * a non null value if an error occured. + *****************************************************************************/ +static int Manage( vout_thread_t *p_vout ) +{ + SDL_Event event; /* SDL event */ + + /* Process events */ + while( SDL_PollEvent(&event) ) + { + switch( event.type ) + { + case SDL_VIDEORESIZE: /* Resizing of window */ + /* Update dimensions */ + p_vout->i_changes |= VOUT_SIZE_CHANGE; + p_vout->i_window_width = p_vout->p_sys->i_width = event.resize.w; + p_vout->i_window_height = p_vout->p_sys->i_height = event.resize.h; + break; + + case SDL_MOUSEMOTION: + if( p_vout->p_sys->b_cursor && + (abs(event.motion.xrel) > 2 || abs(event.motion.yrel) > 2) ) + { + if( p_vout->p_sys->b_cursor_autohidden ) + { + p_vout->p_sys->b_cursor_autohidden = 0; + SDL_ShowCursor( 1 ); + } + else + { + p_vout->p_sys->i_lastmoved = mdate(); + } + } + break; + + case SDL_MOUSEBUTTONUP: + switch( event.button.button ) + { + case SDL_BUTTON_RIGHT: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + } + break; + + case SDL_MOUSEBUTTONDOWN: + switch( event.button.button ) + { + case SDL_BUTTON_LEFT: + /* In this part we will eventually manage + * clicks for DVD navigation for instance. */ + + /* detect double-clicks */ + if( ( mdate() - p_vout->p_sys->i_lastpressed ) < 300000 ) + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + + p_vout->p_sys->i_lastpressed = mdate(); + break; + + case 4: + input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case 5: + input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + } + break; + + case SDL_QUIT: + p_vout->p_vlc->b_die = 1; + break; + + case SDL_KEYDOWN: /* if a key is pressed */ + + switch( event.key.keysym.sym ) + { + case SDLK_ESCAPE: + if( p_vout->b_fullscreen ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + } + else + { + p_vout->p_vlc->b_die = 1; + } + break; + + case SDLK_q: /* quit */ + p_vout->p_vlc->b_die = 1; + break; + + case SDLK_f: /* switch to fullscreen */ + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + case SDLK_c: /* toggle grayscale */ + p_vout->b_grayscale = ! p_vout->b_grayscale; + p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE; + break; + + case SDLK_i: /* toggle info */ + p_vout->b_info = ! p_vout->b_info; + p_vout->i_changes |= VOUT_INFO_CHANGE; + break; + + case SDLK_s: /* toggle scaling */ + p_vout->b_scale = ! p_vout->b_scale; + p_vout->i_changes |= VOUT_SCALE_CHANGE; + break; + + case SDLK_SPACE: /* toggle interface */ + p_vout->b_interface = ! p_vout->b_interface; + p_vout->i_changes |= VOUT_INTF_CHANGE; + break; + + case SDLK_MENU: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + + case SDLK_LEFT: + input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case SDLK_RIGHT: + input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case SDLK_UP: + input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case SDLK_DOWN: + input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case SDLK_F1: network_ChannelJoin( p_vout, 1 ); break; + case SDLK_F2: network_ChannelJoin( p_vout, 2 ); break; + case SDLK_F3: network_ChannelJoin( p_vout, 3 ); break; + case SDLK_F4: network_ChannelJoin( p_vout, 4 ); break; + case SDLK_F5: network_ChannelJoin( p_vout, 5 ); break; + case SDLK_F6: network_ChannelJoin( p_vout, 6 ); break; + case SDLK_F7: network_ChannelJoin( p_vout, 7 ); break; + case SDLK_F8: network_ChannelJoin( p_vout, 8 ); break; + case SDLK_F9: network_ChannelJoin( p_vout, 9 ); break; + case SDLK_F10: network_ChannelJoin( p_vout, 10 ); break; + case SDLK_F11: network_ChannelJoin( p_vout, 11 ); break; + case SDLK_F12: network_ChannelJoin( p_vout, 12 ); break; + + default: + break; + } + break; + + default: + break; + } + } + + /* Fullscreen change */ + if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + p_vout->b_fullscreen = ! p_vout->b_fullscreen; + + p_vout->p_sys->b_cursor_autohidden = 0; + SDL_ShowCursor( p_vout->p_sys->b_cursor && + ! p_vout->p_sys->b_cursor_autohidden ); + + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + p_vout->i_changes |= VOUT_SIZE_CHANGE; + } + + /* + * Size change + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + msg_Dbg( p_vout, "video display resized (%dx%d)", + p_vout->p_sys->i_width, p_vout->p_sys->i_height ); + + CloseDisplay( p_vout ); + OpenDisplay( p_vout ); + + /* We don't need to signal the vout thread about the size change if + * we can handle rescaling ourselves */ + if( p_vout->p_sys->p_overlay != NULL ) + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + + } + + /* Pointer change */ + if( ! p_vout->p_sys->b_cursor_autohidden && + ( mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) ) + { + /* Hide the mouse automatically */ + p_vout->p_sys->b_cursor_autohidden = 1; + SDL_ShowCursor( 0 ); + } + + return( 0 ); +} + +/***************************************************************************** + * Display: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to the display. + *****************************************************************************/ +static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +{ + int x, y, w, h; + SDL_Rect disp; + + vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, + &x, &y, &w, &h ); + disp.x = x; + disp.y = y; + disp.w = w; + disp.h = h; + + if( p_vout->p_sys->p_overlay == NULL ) + { + /* RGB picture */ + SDL_Flip( p_vout->p_sys->p_display ); + } + else + { + /* Overlay picture */ + SDL_UnlockYUVOverlay( p_pic->p_sys->p_overlay); + SDL_DisplayYUVOverlay( p_pic->p_sys->p_overlay , &disp ); + SDL_LockYUVOverlay( p_pic->p_sys->p_overlay); + } +} + +/* following functions are local */ + +/***************************************************************************** + * OpenDisplay: open and initialize SDL device + ***************************************************************************** + * Open and initialize display according to preferences specified in the vout + * thread fields. + *****************************************************************************/ +static int OpenDisplay( vout_thread_t *p_vout ) +{ + Uint32 i_flags; + int i_bpp; + + /* Set main window's size */ + p_vout->p_sys->i_width = p_vout->b_fullscreen ? p_vout->output.i_width : + p_vout->i_window_width; + p_vout->p_sys->i_height = p_vout->b_fullscreen ? p_vout->output.i_height : + p_vout->i_window_height; + + /* Initialize flags and cursor */ + i_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF; + i_flags |= p_vout->b_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE; + + i_bpp = SDL_VideoModeOK( p_vout->p_sys->i_width, p_vout->p_sys->i_height, + SDL_DEFAULT_BPP, i_flags ); + if( i_bpp == 0 ) + { + msg_Err( p_vout, "no video mode available" ); + return( 1 ); + } + + p_vout->p_sys->p_display = SDL_SetVideoMode( p_vout->p_sys->i_width, + p_vout->p_sys->i_height, + i_bpp, i_flags ); + + if( p_vout->p_sys->p_display == NULL ) + { + msg_Err( p_vout, "cannot set video mode" ); + return( 1 ); + } + + SDL_LockSurface( p_vout->p_sys->p_display ); + + /* Choose the chroma we will try first. */ + switch( p_vout->render.i_chroma ) + { + case VLC_FOURCC('Y','U','Y','2'): + case VLC_FOURCC('Y','U','N','V'): + p_vout->output.i_chroma = SDL_YUY2_OVERLAY; + break; + case VLC_FOURCC('U','Y','V','Y'): + case VLC_FOURCC('U','Y','N','V'): + case VLC_FOURCC('Y','4','2','2'): + p_vout->output.i_chroma = SDL_UYVY_OVERLAY; + break; + case VLC_FOURCC('Y','V','Y','U'): + p_vout->output.i_chroma = SDL_YVYU_OVERLAY; + break; + case VLC_FOURCC('Y','V','1','2'): + case VLC_FOURCC('I','4','2','0'): + case VLC_FOURCC('I','Y','U','V'): + default: + p_vout->output.i_chroma = SDL_YV12_OVERLAY; + break; + } + + p_vout->p_sys->p_overlay = + SDL_CreateYUVOverlay( 32, 32, p_vout->output.i_chroma, + p_vout->p_sys->p_display ); + /* FIXME: if the first overlay we find is software, don't stop, + * because we may find a hardware one later ... */ + + /* If this best choice failed, fall back to other chromas */ + if( p_vout->p_sys->p_overlay == NULL ) + { + p_vout->output.i_chroma = SDL_IYUV_OVERLAY; + p_vout->p_sys->p_overlay = + SDL_CreateYUVOverlay( 32, 32, p_vout->output.i_chroma, + p_vout->p_sys->p_display ); + } + + if( p_vout->p_sys->p_overlay == NULL ) + { + p_vout->output.i_chroma = SDL_YV12_OVERLAY; + p_vout->p_sys->p_overlay = + SDL_CreateYUVOverlay( 32, 32, p_vout->output.i_chroma, + p_vout->p_sys->p_display ); + } + + if( p_vout->p_sys->p_overlay == NULL ) + { + p_vout->output.i_chroma = SDL_YUY2_OVERLAY; + p_vout->p_sys->p_overlay = + SDL_CreateYUVOverlay( 32, 32, p_vout->output.i_chroma, + p_vout->p_sys->p_display ); + } + + if( p_vout->p_sys->p_overlay == NULL ) + { + msg_Warn( p_vout, "no SDL overlay for 0x%.8x (%4.4s)", + p_vout->render.i_chroma, (char*)&p_vout->render.i_chroma ); + + switch( p_vout->p_sys->p_display->format->BitsPerPixel ) + { + case 8: + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); + p_vout->output.pf_setpalette = SetPalette; + break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); + break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); + break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); + break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); + break; + default: + msg_Err( p_vout, "unknown screen depth %i", + p_vout->p_sys->p_display->format->BitsPerPixel ); + SDL_UnlockSurface( p_vout->p_sys->p_display ); + SDL_FreeSurface( p_vout->p_sys->p_display ); + return( -1 ); + } + + p_vout->output.i_rmask = p_vout->p_sys->p_display->format->Rmask; + p_vout->output.i_gmask = p_vout->p_sys->p_display->format->Gmask; + p_vout->output.i_bmask = p_vout->p_sys->p_display->format->Bmask; + + SDL_WM_SetCaption( VOUT_TITLE " (software RGB SDL output)", + VOUT_TITLE " (software RGB SDL output)" ); + } + else + { + if( p_vout->p_sys->p_overlay->hw_overlay ) + { + SDL_WM_SetCaption( VOUT_TITLE " (hardware YUV SDL output)", + VOUT_TITLE " (hardware YUV SDL output)" ); + } + else + { + SDL_WM_SetCaption( VOUT_TITLE " (software YUV SDL output)", + VOUT_TITLE " (software YUV SDL output)" ); + } + } + + SDL_EventState( SDL_KEYUP, SDL_IGNORE ); /* ignore keys up */ + + return( 0 ); +} + +/***************************************************************************** + * CloseDisplay: close and reset SDL device + ***************************************************************************** + * This function returns all resources allocated by OpenDisplay and restore + * the original state of the device. + *****************************************************************************/ +static void CloseDisplay( vout_thread_t *p_vout ) +{ + SDL_FreeYUVOverlay( p_vout->p_sys->p_overlay ); + SDL_UnlockSurface ( p_vout->p_sys->p_display ); + SDL_FreeSurface( p_vout->p_sys->p_display ); +} + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + int i_width = p_vout->output.i_width; + int i_height = p_vout->output.i_height; + + if( p_vout->p_sys->p_overlay == NULL ) + { + /* RGB picture */ + if( p_vout->p_sys->i_surfaces ) + { + /* We already allocated this surface, return */ + return -1; + } + + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return -1; + } + + switch( p_vout->p_sys->p_display->format->BitsPerPixel ) + { + case 8: + p_pic->p->i_pixel_pitch = 1; + break; + case 15: + case 16: + p_pic->p->i_pixel_pitch = 2; + break; + case 24: + case 32: + p_pic->p->i_pixel_pitch = 4; + break; + default: + return( -1 ); + } + + p_pic->p->p_pixels = p_vout->p_sys->p_display->pixels; + p_pic->p->i_lines = p_vout->p_sys->p_display->h; + p_pic->p->i_pitch = p_vout->p_sys->p_display->pitch; + p_pic->p->i_visible_pitch = + p_pic->p->i_pixel_pitch * p_vout->p_sys->p_display->w; + + p_vout->p_sys->i_surfaces++; + + p_pic->i_planes = 1; + } + else + { + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return -1; + } + + p_pic->p_sys->p_overlay = + SDL_CreateYUVOverlay( i_width, i_height, + p_vout->output.i_chroma, + p_vout->p_sys->p_display ); + + if( p_pic->p_sys->p_overlay == NULL ) + { + free( p_pic->p_sys ); + return -1; + } + + SDL_LockYUVOverlay( p_pic->p_sys->p_overlay ); + + p_pic->Y_PIXELS = p_pic->p_sys->p_overlay->pixels[0]; + p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_overlay->h; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[0]; + + switch( p_vout->output.i_chroma ) + { + case SDL_YV12_OVERLAY: + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[2]; + p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2]; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[1]; + p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1]; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + case SDL_IYUV_OVERLAY: + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_overlay->pixels[1]; + p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[1]; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_overlay->pixels[2]; + p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_overlay->h / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_overlay->pitches[2]; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + default: + p_pic->p[Y_PLANE].i_pixel_pitch = 2; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->i_planes = 1; + break; + } + } + + return 0; +} + +/***************************************************************************** + * SetPalette: sets an 8 bpp palette + *****************************************************************************/ +static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) +{ + SDL_Color colors[256]; + int i; + + /* Fill colors with color information */ + for( i = 0; i < 256; i++ ) + { + colors[ i ].r = red[ i ] >> 8; + colors[ i ].g = green[ i ] >> 8; + colors[ i ].b = blue[ i ] >> 8; + } + + /* Set palette */ + if( SDL_SetColors( p_vout->p_sys->p_display, colors, 0, 256 ) == 0 ) + { + msg_Err( p_vout, "failed setting palette" ); + } +} + diff --git a/modules/video_output/x11/.cvsignore b/modules/video_output/x11/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/video_output/x11/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/video_output/x11/Makefile b/modules/video_output/x11/Makefile new file mode 100644 index 0000000000..a2e53c05f8 --- /dev/null +++ b/modules/video_output/x11/Makefile @@ -0,0 +1,2 @@ +x11_SOURCES = x11.c xcommon.c +xvideo_SOURCES = xvideo.c xcommon.c diff --git a/modules/video_output/x11/x11.c b/modules/video_output/x11/x11.c new file mode 100644 index 0000000000..044a3123ec --- /dev/null +++ b/modules/video_output/x11/x11.c @@ -0,0 +1,78 @@ +/***************************************************************************** + * x11.c : X11 plugin for vlc + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: x11.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Vincent Seguin + * Samuel Hocevar + * David Kennedy + * + * 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 /* malloc(), free() */ +#include /* strerror() */ + +#include + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +extern int E_(Activate) ( vlc_object_t * ); +extern void E_(Deactivate) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define ALT_FS_TEXT N_("alternate fullscreen method") +#define ALT_FS_LONGTEXT N_( \ + "There are two ways to make a fullscreen window, unfortunately each one " \ + "has its drawbacks.\n" \ + "1) Let the window manager handle your fullscreen window (default). But " \ + "things like taskbars will likely show on top of the video.\n" \ + "2) Completly bypass the window manager, but then nothing will be able " \ + "to show on top of the video.") + +#define DISPLAY_TEXT N_("X11 display name") +#define DISPLAY_LONGTEXT N_( \ + "Specify the X11 hardware display you want to use. By default vlc will " \ + "use the value of the DISPLAY environment variable.") + +#define DRAWABLE_TEXT N_("X11 drawable") +#define DRAWABLE_LONGTEXT N_( \ + "Specify a X11 drawable to use instead of opening a new window. This " \ + "option is DANGEROUS, use with care.") + +#define SHM_TEXT N_("use shared memory") +#define SHM_LONGTEXT N_( \ + "Use shared memory to communicate between vlc and the X server.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "x11-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT ); + add_bool( "x11-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT ); + add_integer( "x11-drawable", -1, NULL, DRAWABLE_TEXT, DRAWABLE_LONGTEXT ); +#ifdef HAVE_SYS_SHM_H + add_bool( "x11-shm", 1, NULL, SHM_TEXT, SHM_LONGTEXT ); +#endif + set_description( _("X11 module") ); + set_capability( "video output", 50 ); + set_callbacks( E_(Activate), E_(Deactivate) ); +vlc_module_end(); + diff --git a/modules/video_output/x11/xcommon.c b/modules/video_output/x11/xcommon.c new file mode 100644 index 0000000000..5bcee547e3 --- /dev/null +++ b/modules/video_output/x11/xcommon.c @@ -0,0 +1,2014 @@ +/***************************************************************************** + * xcommon.c: Functions common to the X11 and XVideo plugins + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: xcommon.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Vincent Seguin + * Samuel Hocevar + * David Kennedy + * Gildas Bazin + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include +#include +#include + +#ifdef HAVE_MACHINE_PARAM_H + /* BSD */ +# include +# include /* typedef ushort */ +# include +#endif + +#ifndef WIN32 +# include /* BSD: struct in_addr */ +#endif + +#ifdef HAVE_SYS_SHM_H +# include /* shmget(), shmctl() */ +#endif + +#include +#include +#include +#ifdef HAVE_SYS_SHM_H +# include +#endif +#ifdef DPMSINFO_IN_DPMS_H +# include +#endif + +#ifdef MODULE_NAME_IS_xvideo +# include +# include +#endif + +#include "netutils.h" /* network_ChannelJoin */ + +#include "xcommon.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +int E_(Activate) ( vlc_object_t * ); +void E_(Deactivate) ( vlc_object_t * ); + +static int InitVideo ( vout_thread_t * ); +static void EndVideo ( vout_thread_t * ); +static void DisplayVideo ( vout_thread_t *, picture_t * ); +static int ManageVideo ( vout_thread_t * ); + +static int InitDisplay ( vout_thread_t * ); + +static int CreateWindow ( vout_thread_t *, x11_window_t * ); +static void DestroyWindow ( vout_thread_t *, x11_window_t * ); + +static int NewPicture ( vout_thread_t *, picture_t * ); +static void FreePicture ( vout_thread_t *, picture_t * ); + +static IMAGE_TYPE *CreateImage ( vout_thread_t *, + Display *, EXTRA_ARGS, int, int ); +#ifdef HAVE_SYS_SHM_H +static IMAGE_TYPE *CreateShmImage ( vout_thread_t *, + Display *, EXTRA_ARGS_SHM, int, int ); +#endif + +static void ToggleFullScreen ( vout_thread_t * ); + +static void EnableXScreenSaver ( vout_thread_t * ); +static void DisableXScreenSaver ( vout_thread_t * ); + +static void CreateCursor ( vout_thread_t * ); +static void DestroyCursor ( vout_thread_t * ); +static void ToggleCursor ( vout_thread_t * ); + +#ifdef MODULE_NAME_IS_xvideo +static int XVideoGetPort ( vout_thread_t *, vlc_fourcc_t, vlc_fourcc_t * ); +static void XVideoReleasePort( vout_thread_t *, int ); +#endif + +#ifdef MODULE_NAME_IS_x11 +static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * ); +#endif + +/***************************************************************************** + * Activate: allocate X11 video thread output method + ***************************************************************************** + * This function allocate and initialize a X11 vout method. It uses some of the + * vout properties to choose the window size, and change them according to the + * actual properties of the display. + *****************************************************************************/ +int E_(Activate) ( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + char * psz_display; +#ifdef MODULE_NAME_IS_xvideo + char * psz_chroma; + vlc_fourcc_t i_chroma = 0; + vlc_bool_t b_chroma = 0; +#endif + + p_vout->pf_init = InitVideo; + p_vout->pf_end = EndVideo; + p_vout->pf_manage = ManageVideo; + p_vout->pf_render = NULL; + p_vout->pf_display = DisplayVideo; + + /* Allocate structure */ + p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + if( p_vout->p_sys == NULL ) + { + msg_Err( p_vout, "out of memory" ); + return( 1 ); + } + + /* Open display, unsing the "display" config variable or the DISPLAY + * environment variable */ + psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" ); + + p_vout->p_sys->p_display = XOpenDisplay( psz_display ); + + if( p_vout->p_sys->p_display == NULL ) /* error */ + { + msg_Err( p_vout, "cannot open display %s", + XDisplayName( psz_display ) ); + free( p_vout->p_sys ); + if( psz_display ) free( psz_display ); + return( 1 ); + } + if( psz_display ) free( psz_display ); + + /* Get a screen ID matching the XOpenDisplay return value */ + p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display ); + +#ifdef MODULE_NAME_IS_xvideo + psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" ); + if( psz_chroma ) + { + if( strlen( psz_chroma ) >= 4 ) + { + i_chroma = (unsigned char)psz_chroma[0] << 0; + i_chroma |= (unsigned char)psz_chroma[1] << 8; + i_chroma |= (unsigned char)psz_chroma[2] << 16; + i_chroma |= (unsigned char)psz_chroma[3] << 24; + + b_chroma = 1; + } + + free( psz_chroma ); + } + + if( b_chroma ) + { + msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)", + i_chroma, (char*)&i_chroma ); + } + else + { + i_chroma = p_vout->render.i_chroma; + } + + /* Check that we have access to an XVideo port providing this chroma */ + p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, i_chroma, + &p_vout->output.i_chroma ); + if( p_vout->p_sys->i_xvport < 0 ) + { + /* If a specific chroma format was requested, then we don't try to + * be cleverer than the user. He knows pretty well what he wants. */ + if( b_chroma ) + { + XCloseDisplay( p_vout->p_sys->p_display ); + free( p_vout->p_sys ); + return 1; + } + + /* It failed, but it's not completely lost ! We try to open an + * XVideo port for an YUY2 picture. We'll need to do an YUV + * conversion, but at least it has got scaling. */ + p_vout->p_sys->i_xvport = + XVideoGetPort( p_vout, VLC_FOURCC('Y','U','Y','2'), + &p_vout->output.i_chroma ); + if( p_vout->p_sys->i_xvport < 0 ) + { + /* It failed, but it's not completely lost ! We try to open an + * XVideo port for a simple 16bpp RGB picture. We'll need to do + * an YUV conversion, but at least it has got scaling. */ + p_vout->p_sys->i_xvport = + XVideoGetPort( p_vout, VLC_FOURCC('R','V','1','6'), + &p_vout->output.i_chroma ); + if( p_vout->p_sys->i_xvport < 0 ) + { + XCloseDisplay( p_vout->p_sys->p_display ); + free( p_vout->p_sys ); + return 1; + } + } + } +#endif + + /* Create blank cursor (for mouse cursor autohiding) */ + p_vout->p_sys->i_time_mouse_last_moved = mdate(); + p_vout->p_sys->b_mouse_pointer_visible = 1; + CreateCursor( p_vout ); + + /* Set main window's size */ + p_vout->p_sys->original_window.i_width = p_vout->i_window_width; + p_vout->p_sys->original_window.i_height = p_vout->i_window_height; + + /* Spawn base window - this window will include the video output window, + * but also command buttons, subtitles and other indicators */ + if( CreateWindow( p_vout, &p_vout->p_sys->original_window ) ) + { + msg_Err( p_vout, "cannot create X11 window" ); + DestroyCursor( p_vout ); + XCloseDisplay( p_vout->p_sys->p_display ); + free( p_vout->p_sys ); + return( 1 ); + } + + /* Open and initialize device. */ + if( InitDisplay( p_vout ) ) + { + msg_Err( p_vout, "cannot initialize X11 display" ); + DestroyCursor( p_vout ); + DestroyWindow( p_vout, &p_vout->p_sys->original_window ); + XCloseDisplay( p_vout->p_sys->p_display ); + free( p_vout->p_sys ); + return( 1 ); + } + + /* Disable screen saver */ + DisableXScreenSaver( p_vout ); + + /* Misc init */ + p_vout->p_sys->b_altfullscreen = 0; + p_vout->p_sys->i_time_button_last_pressed = 0; + + return( 0 ); +} + +/***************************************************************************** + * Deactivate: destroy X11 video thread output method + ***************************************************************************** + * Terminate an output method created by Open + *****************************************************************************/ +void E_(Deactivate) ( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + /* If the fullscreen window is still open, close it */ + if( p_vout->b_fullscreen ) + { + ToggleFullScreen( p_vout ); + } + + /* Restore cursor if it was blanked */ + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + +#ifdef MODULE_NAME_IS_x11 + /* Destroy colormap */ + if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 ) + { + XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap ); + } +#else + XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport ); +#endif + + DestroyCursor( p_vout ); + EnableXScreenSaver( p_vout ); + DestroyWindow( p_vout, &p_vout->p_sys->original_window ); + + XCloseDisplay( p_vout->p_sys->p_display ); + + /* Destroy structure */ + free( p_vout->p_sys ); +} + +/***************************************************************************** + * InitVideo: initialize X11 video thread output method + ***************************************************************************** + * This function create the XImages needed by the output thread. It is called + * at the beginning of the thread, but also each time the window is resized. + *****************************************************************************/ +static int InitVideo( vout_thread_t *p_vout ) +{ + int i_index; + picture_t *p_pic; + + I_OUTPUTPICTURES = 0; + +#ifdef MODULE_NAME_IS_xvideo + /* Initialize the output structure; we already found an XVideo port, + * and the corresponding chroma we will be using. Since we can + * arbitrary scale, stick to the coordinates and aspect. */ + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + switch( p_vout->output.i_chroma ) + { + case VLC_FOURCC('R','V','1','5'): + p_vout->output.i_rmask = 0x001f; + p_vout->output.i_gmask = 0x07e0; + p_vout->output.i_bmask = 0xf800; + break; + case VLC_FOURCC('R','V','1','6'): + p_vout->output.i_rmask = 0x001f; + p_vout->output.i_gmask = 0x03e0; + p_vout->output.i_bmask = 0x7c00; + break; + } + +#else + /* Initialize the output structure: RGB with square pixels, whatever + * the input format is, since it's the only format we know */ + switch( p_vout->p_sys->i_screen_depth ) + { + case 8: /* FIXME: set the palette */ + p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break; + case 15: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break; + case 16: + p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break; + case 24: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + case 32: + p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + default: + msg_Err( p_vout, "unknown screen depth %i", + p_vout->p_sys->i_screen_depth ); + return( 0 ); + } + + vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height, + &i_index, &i_index, + &p_vout->output.i_width, &p_vout->output.i_height ); + + /* Assume we have square pixels */ + p_vout->output.i_aspect = p_vout->output.i_width + * VOUT_ASPECT_FACTOR / p_vout->output.i_height; +#endif + + /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS ) + { + p_pic = NULL; + + /* Find an empty picture slot */ + for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + { + if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + { + p_pic = p_vout->p_picture + i_index; + break; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || NewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; + } + + return( 0 ); +} + + /***************************************************************************** + * DisplayVideo: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to X11 server. + * (The Xv extension takes care of "double-buffering".) + *****************************************************************************/ +static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic ) +{ + int i_width, i_height, i_x, i_y; + + vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height, + &i_x, &i_y, &i_width, &i_height ); + +#ifdef HAVE_SYS_SHM_H + if( p_vout->p_sys->b_shm ) + { + /* Display rendered image using shared memory extension */ +# ifdef MODULE_NAME_IS_xvideo + XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport, + p_vout->p_sys->p_win->video_window, + p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image, + 0 /*src_x*/, 0 /*src_y*/, + p_vout->output.i_width, p_vout->output.i_height, + 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height, + False /* Don't put True here or you'll waste your CPU */ ); +# else + XShmPutImage( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->video_window, + p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image, + 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/, + p_vout->output.i_width, p_vout->output.i_height, + False /* Don't put True here ! */ ); +# endif + } + else +#endif /* HAVE_SYS_SHM_H */ + { + /* Use standard XPutImage -- this is gonna be slow ! */ +#ifdef MODULE_NAME_IS_xvideo + XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport, + p_vout->p_sys->p_win->video_window, + p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image, + 0 /*src_x*/, 0 /*src_y*/, + p_vout->output.i_width, p_vout->output.i_height, + 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height ); +#else + XPutImage( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->video_window, + p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image, + 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/, + p_vout->output.i_width, p_vout->output.i_height ); +#endif + } + + /* Make sure the command is sent now - do NOT use XFlush !*/ + XSync( p_vout->p_sys->p_display, False ); +} + +/***************************************************************************** + * ManageVideo: handle X11 events + ***************************************************************************** + * This function should be called regularly by video output thread. It manages + * X11 events and allows window resizing. It returns a non null value on + * error. + *****************************************************************************/ +static int ManageVideo( vout_thread_t *p_vout ) +{ + XEvent xevent; /* X11 event */ + char i_key; /* ISO Latin-1 key */ + KeySym x_key_symbol; + + /* Handle X11 events: ConfigureNotify events are parsed to know if the + * output window's size changed, MapNotify and UnmapNotify to know if the + * window is mapped (and if the display is useful), and ClientMessages + * to intercept window destruction requests */ + + while( XCheckWindowEvent( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + StructureNotifyMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | Button1MotionMask , &xevent ) + == True ) + { + /* ConfigureNotify event: prepare */ + if( xevent.type == ConfigureNotify ) + { + if( (xevent.xconfigure.width != p_vout->p_sys->p_win->i_width) + || (xevent.xconfigure.height != p_vout->p_sys->p_win->i_height) ) + { + /* Update dimensions */ + p_vout->i_changes |= VOUT_SIZE_CHANGE; + p_vout->p_sys->p_win->i_width = xevent.xconfigure.width; + p_vout->p_sys->p_win->i_height = xevent.xconfigure.height; + } + } + /* Keyboard event */ + else if( xevent.type == KeyPress ) + { + /* We may have keys like F1 trough F12, ESC ... */ + x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display, + xevent.xkey.keycode, 0 ); + switch( x_key_symbol ) + { + case XK_Escape: + if( p_vout->b_fullscreen ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + } + else + { + p_vout->p_vlc->b_die = 1; + } + break; + case XK_Menu: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + case XK_Left: + input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Right: + input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Up: + input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Down: + input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Home: + input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_SET ); + break; + case XK_End: + input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_END ); + break; + case XK_Page_Up: + input_Seek( p_vout, 900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_Page_Down: + input_Seek( p_vout, -900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + case XK_space: + input_SetStatus( p_vout, INPUT_STATUS_PAUSE ); + break; + + case XK_F1: network_ChannelJoin( p_vout, 1 ); break; + case XK_F2: network_ChannelJoin( p_vout, 2 ); break; + case XK_F3: network_ChannelJoin( p_vout, 3 ); break; + case XK_F4: network_ChannelJoin( p_vout, 4 ); break; + case XK_F5: network_ChannelJoin( p_vout, 5 ); break; + case XK_F6: network_ChannelJoin( p_vout, 6 ); break; + case XK_F7: network_ChannelJoin( p_vout, 7 ); break; + case XK_F8: network_ChannelJoin( p_vout, 8 ); break; + case XK_F9: network_ChannelJoin( p_vout, 9 ); break; + case XK_F10: network_ChannelJoin( p_vout, 10 ); break; + case XK_F11: network_ChannelJoin( p_vout, 11 ); break; + case XK_F12: network_ChannelJoin( p_vout, 12 ); break; + + default: + /* "Normal Keys" + * The reason why I use this instead of XK_0 is that + * with XLookupString, we don't have to care about + * keymaps. */ + + if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) ) + { + /* FIXME: handle stuff here */ + switch( i_key ) + { + case 'q': + case 'Q': + p_vout->p_vlc->b_die = 1; + break; + case 'f': + case 'F': + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + break; + + default: + break; + } + } + break; + } + } + /* Mouse click */ + else if( xevent.type == ButtonPress ) + { + int i_width, i_height, i_x, i_y; + + vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height, + &i_x, &i_y, &i_width, &i_height ); + + p_vout->i_mouse_x = ( xevent.xmotion.x - i_x ) + * p_vout->render.i_width / i_width; + p_vout->i_mouse_y = ( xevent.xmotion.y - i_y ) + * p_vout->render.i_height / i_height; + p_vout->i_mouse_button = 1; + + switch( ((XButtonEvent *)&xevent)->button ) + { + case Button1: + /* In this part we will eventually manage + * clicks for DVD navigation for instance. */ + + /* detect double-clicks */ + if( ( ((XButtonEvent *)&xevent)->time - + p_vout->p_sys->i_time_button_last_pressed ) < 300 ) + { + p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + } + + p_vout->p_sys->i_time_button_last_pressed = + ((XButtonEvent *)&xevent)->time; + break; + + case Button4: + input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + + case Button5: + input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); + break; + } + } + /* Mouse release */ + else if( xevent.type == ButtonRelease ) + { + switch( ((XButtonEvent *)&xevent)->button ) + { + case Button3: + { + intf_thread_t *p_intf; + p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, + FIND_ANYWHERE ); + if( p_intf ) + { + p_intf->b_menu_change = 1; + vlc_object_release( p_intf ); + } + } + break; + } + } + /* Mouse move */ + else if( xevent.type == MotionNotify ) + { + int i_width, i_height, i_x, i_y; + + /* somewhat different use for vout_PlacePicture: + * here the values are needed to give to mouse coordinates + * in the original picture space */ + vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height, + &i_x, &i_y, &i_width, &i_height ); + + p_vout->i_mouse_x = ( xevent.xmotion.x - i_x ) + * p_vout->render.i_width / i_width; + p_vout->i_mouse_y = ( xevent.xmotion.y - i_y ) + * p_vout->render.i_height / i_height; + + p_vout->p_sys->i_time_mouse_last_moved = mdate(); + if( ! p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + } + /* Reparent move -- XXX: why are we getting this ? */ + else if( xevent.type == ReparentNotify ) + { + ; + } + /* Other event */ + else + { + msg_Warn( p_vout, "unhandled event %d received", xevent.type ); + } + } + + /* Handle events for video output sub-window */ + while( XCheckWindowEvent( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->video_window, + ExposureMask, &xevent ) == True ) + { + /* Window exposed (only handled if stream playback is paused) */ + if( xevent.type == Expose ) + { + if( ((XExposeEvent *)&xevent)->count == 0 ) + { + /* (if this is the last a collection of expose events...) */ +#if 0 + if( p_vout->p_vlc->p_input_bank->pp_input[0] != NULL ) + { + if( PAUSE_S == p_vout->p_vlc->p_input_bank->pp_input[0] + ->stream.control.i_status ) + { + /* XVideoDisplay( p_vout )*/; + } + } +#endif + } + } + } + + /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data + * are handled - according to the man pages, the format is always 32 + * in this case */ + while( XCheckTypedEvent( p_vout->p_sys->p_display, + ClientMessage, &xevent ) ) + { + if( (xevent.xclient.message_type == p_vout->p_sys->p_win->wm_protocols) + && (xevent.xclient.data.l[0] + == p_vout->p_sys->p_win->wm_delete_window ) ) + { + p_vout->p_vlc->b_die = 1; + } + } + + /* + * Fullscreen Change + */ + if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + ToggleFullScreen( p_vout ); + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + } + + /* + * Size change + * + * (Needs to be placed after VOUT_FULLSREEN_CHANGE because we can activate + * the size flag inside the fullscreen routine) + */ + if( p_vout->i_changes & VOUT_SIZE_CHANGE ) + { + int i_width, i_height, i_x, i_y; + + p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + + msg_Dbg( p_vout, "video display resized (%dx%d)", + p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height ); + +#ifdef MODULE_NAME_IS_x11 + /* We need to signal the vout thread about the size change because it + * is doing the rescaling */ + p_vout->i_changes |= VOUT_SIZE_CHANGE; +#endif + + vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height, + &i_x, &i_y, &i_width, &i_height ); + + XResizeWindow( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->video_window, i_width, i_height ); + + XMoveWindow( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->video_window, i_x, i_y ); + } + + /* Autohide Cursour */ + if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 ) + { + /* Hide the mouse automatically */ + if( p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + } + } + + return 0; +} + +/***************************************************************************** + * EndVideo: terminate X11 video thread output method + ***************************************************************************** + * Destroy the X11 XImages created by Init. It is called at the end of + * the thread, but also each time the window is resized. + *****************************************************************************/ +static void EndVideo( vout_thread_t *p_vout ) +{ + int i_index; + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); + } +} + +/* following functions are local */ + +/***************************************************************************** + * CreateWindow: open and set-up X11 main window + *****************************************************************************/ +static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win ) +{ + XSizeHints xsize_hints; + XSetWindowAttributes xwindow_attributes; + XGCValues xgcvalues; + XEvent xevent; + + vlc_bool_t b_expose; + vlc_bool_t b_configure_notify; + vlc_bool_t b_map_notify; + + long long int i_drawable; + + /* Prepare window manager hints and properties */ + xsize_hints.base_width = p_win->i_width; + xsize_hints.base_height = p_win->i_height; + xsize_hints.flags = PSize; + p_win->wm_protocols = + XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True ); + p_win->wm_delete_window = + XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True ); + + /* Prepare window attributes */ + xwindow_attributes.backing_store = Always; /* save the hidden part */ + xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display, + p_vout->p_sys->i_screen); + xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask; + + /* Check whether someone provided us with a window ID */ + i_drawable = p_vout->b_fullscreen ? + -1 : config_GetInt( p_vout, MODULE_STRING "-drawable"); + + if( i_drawable == -1 ) + { + p_vout->p_sys->b_createwindow = 1; + + /* Create the window and set hints - the window must receive + * ConfigureNotify events, and until it is displayed, Expose and + * MapNotify events. */ + + p_win->base_window = + XCreateWindow( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, 0, + p_win->i_width, p_win->i_height, + 0, + 0, InputOutput, 0, + CWBackingStore | CWBackPixel | CWEventMask, + &xwindow_attributes ); + + if( !p_vout->b_fullscreen ) + { + /* Set window manager hints and properties: size hints, command, + * window's name, and accepted protocols */ + XSetWMNormalHints( p_vout->p_sys->p_display, + p_win->base_window, &xsize_hints ); + XSetCommand( p_vout->p_sys->p_display, p_win->base_window, + p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc ); + + XStoreName( p_vout->p_sys->p_display, p_win->base_window, +#ifdef MODULE_NAME_IS_x11 + VOUT_TITLE " (X11 output)" +#else + VOUT_TITLE " (XVideo output)" +#endif + ); + } + } + else + { + p_vout->p_sys->b_createwindow = 0; + p_win->base_window = i_drawable; + + XChangeWindowAttributes( p_vout->p_sys->p_display, + p_win->base_window, + CWBackingStore | CWBackPixel | CWEventMask, + &xwindow_attributes ); + } + + if( (p_win->wm_protocols == None) /* use WM_DELETE_WINDOW */ + || (p_win->wm_delete_window == None) + || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window, + &p_win->wm_delete_window, 1 ) ) + { + /* WM_DELETE_WINDOW is not supported by window manager */ + msg_Warn( p_vout, "missing or bad window manager" ); + } + + /* Creation of a graphic context that doesn't generate a GraphicsExpose + * event when using functions like XCopyArea */ + xgcvalues.graphics_exposures = False; + p_win->gc = XCreateGC( p_vout->p_sys->p_display, + p_win->base_window, + GCGraphicsExposures, &xgcvalues ); + + if( p_vout->p_sys->b_createwindow ) + { + /* Send orders to server, and wait until window is displayed - three + * events must be received: a MapNotify event, an Expose event allowing + * drawing in the window, and a ConfigureNotify to get the window + * dimensions. Once those events have been received, only + * ConfigureNotify events need to be received. */ + b_expose = 0; + b_configure_notify = 0; + b_map_notify = 0; + XMapWindow( p_vout->p_sys->p_display, p_win->base_window ); + do + { + XNextEvent( p_vout->p_sys->p_display, &xevent); + if( (xevent.type == Expose) + && (xevent.xexpose.window == p_win->base_window) ) + { + b_expose = 1; + } + else if( (xevent.type == MapNotify) + && (xevent.xmap.window == p_win->base_window) ) + { + b_map_notify = 1; + } + else if( (xevent.type == ConfigureNotify) + && (xevent.xconfigure.window == p_win->base_window) ) + { + b_configure_notify = 1; + p_win->i_width = xevent.xconfigure.width; + p_win->i_height = xevent.xconfigure.height; + } + } while( !( b_expose && b_configure_notify && b_map_notify ) ); + } + else + { + /* Get the window's geometry information */ + Window dummy1; + unsigned int dummy2, dummy3; + XGetGeometry( p_vout->p_sys->p_display, p_win->base_window, + &dummy1, &dummy2, &dummy3, + &p_win->i_width, + &p_win->i_height, + &dummy2, &dummy3 ); + } + + XSelectInput( p_vout->p_sys->p_display, p_win->base_window, + StructureNotifyMask | KeyPressMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask ); + +#ifdef MODULE_NAME_IS_x11 + if( p_vout->p_sys->b_createwindow && + XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 ) + { + /* Allocate a new palette */ + p_vout->p_sys->colormap = + XCreateColormap( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + DefaultVisual( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ), + AllocAll ); + + xwindow_attributes.colormap = p_vout->p_sys->colormap; + XChangeWindowAttributes( p_vout->p_sys->p_display, p_win->base_window, + CWColormap, &xwindow_attributes ); + } +#endif + + /* Create video output sub-window. */ + p_win->video_window = XCreateSimpleWindow( + p_vout->p_sys->p_display, + p_win->base_window, 0, 0, + p_win->i_width, p_win->i_height, + 0, + BlackPixel( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ), + WhitePixel( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ) ); + + XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window, + BlackPixel( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ) ); + + XMapWindow( p_vout->p_sys->p_display, p_win->video_window ); + XSelectInput( p_vout->p_sys->p_display, p_win->video_window, + ExposureMask ); + + /* make sure the video window will be centered in the next ManageVideo() */ + p_vout->i_changes |= VOUT_SIZE_CHANGE; + + /* If the cursor was formerly blank than blank it again */ + if( !p_vout->p_sys->b_mouse_pointer_visible ) + { + ToggleCursor( p_vout ); + ToggleCursor( p_vout ); + } + + /* Do NOT use XFlush here ! */ + XSync( p_vout->p_sys->p_display, False ); + + /* At this stage, the window is open, displayed, and ready to + * receive data */ + p_vout->p_sys->p_win = p_win; + + return( 0 ); +} + +/***************************************************************************** + * DestroyWindow: destroy the window + ***************************************************************************** + * + *****************************************************************************/ +static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win ) +{ + /* Do NOT use XFlush here ! */ + XSync( p_vout->p_sys->p_display, False ); + + XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window ); + XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window ); + XFreeGC( p_vout->p_sys->p_display, p_win->gc ); + XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window ); +} + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + + if( p_pic->p_sys == NULL ) + { + return -1; + } + +#ifdef HAVE_SYS_SHM_H + if( p_vout->p_sys->b_shm ) + { + /* Create image using XShm extension */ + p_pic->p_sys->p_image = + CreateShmImage( p_vout, p_vout->p_sys->p_display, +# ifdef MODULE_NAME_IS_xvideo + p_vout->p_sys->i_xvport, p_vout->output.i_chroma, +# else + p_vout->p_sys->p_visual, + p_vout->p_sys->i_screen_depth, +# endif + &p_pic->p_sys->shminfo, + p_vout->output.i_width, p_vout->output.i_height ); + } + else +#endif /* HAVE_SYS_SHM_H */ + { + /* Create image without XShm extension */ + p_pic->p_sys->p_image = + CreateImage( p_vout, p_vout->p_sys->p_display, +#ifdef MODULE_NAME_IS_xvideo + p_vout->p_sys->i_xvport, p_vout->output.i_chroma, +#else + p_vout->p_sys->p_visual, + p_vout->p_sys->i_screen_depth, + p_vout->p_sys->i_bytes_per_pixel, +#endif + p_vout->output.i_width, p_vout->output.i_height ); + } + + if( p_pic->p_sys->p_image == NULL ) + { + free( p_pic->p_sys ); + return -1; + } + + switch( p_vout->output.i_chroma ) + { +#ifdef MODULE_NAME_IS_xvideo + case VLC_FOURCC('I','4','2','0'): + + p_pic->Y_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[1]; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[1]; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[2]; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[2]; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + case VLC_FOURCC('Y','V','1','2'): + + p_pic->Y_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height; + p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p[Y_PLANE].i_pixel_pitch = 1; + p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; + + p_pic->U_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[2]; + p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[2]; + p_pic->p[U_PLANE].i_pixel_pitch = 1; + p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; + + p_pic->V_PIXELS = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[1]; + p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2; + p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[1]; + p_pic->p[V_PLANE].i_pixel_pitch = 1; + p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; + + p_pic->i_planes = 3; + break; + + case VLC_FOURCC('Y','2','1','1'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + /* XXX: this just looks so plain wrong... check it out ! */ + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; + + case VLC_FOURCC('Y','U','Y','2'): + case VLC_FOURCC('U','Y','V','Y'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p->i_pixel_pitch = 4; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; + + case VLC_FOURCC('R','V','1','5'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p->i_pixel_pitch = 2; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; + + case VLC_FOURCC('R','V','1','6'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->offsets[0]; + p_pic->p->i_lines = p_vout->output.i_height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0]; + p_pic->p->i_pixel_pitch = 2; + p_pic->p->i_visible_pitch = p_pic->p->i_pitch; + + p_pic->i_planes = 1; + break; + +#else + case VLC_FOURCC('R','G','B','2'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->xoffset; + p_pic->p->i_lines = p_pic->p_sys->p_image->height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line; + p_pic->p->i_pixel_pitch = p_pic->p_sys->p_image->depth; + p_pic->p->i_visible_pitch = p_pic->p_sys->p_image->width; + + p_pic->i_planes = 1; + + break; + + case VLC_FOURCC('R','V','1','6'): + case VLC_FOURCC('R','V','1','5'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->xoffset; + p_pic->p->i_lines = p_pic->p_sys->p_image->height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line; + p_pic->p->i_pixel_pitch = p_pic->p_sys->p_image->depth; + p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_image->width; + + p_pic->i_planes = 1; + + break; + + case VLC_FOURCC('R','V','3','2'): + case VLC_FOURCC('R','V','2','4'): + + p_pic->p->p_pixels = p_pic->p_sys->p_image->data + + p_pic->p_sys->p_image->xoffset; + p_pic->p->i_lines = p_pic->p_sys->p_image->height; + p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line; + p_pic->p->i_pixel_pitch = p_pic->p_sys->p_image->depth; + p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_image->width; + + p_pic->i_planes = 1; + + break; +#endif + + default: + /* Unknown chroma, tell the guy to get lost */ + IMAGE_FREE( p_pic->p_sys->p_image ); + free( p_pic->p_sys ); + msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)", + p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma ); + p_pic->i_planes = 0; + return -1; + } + + return 0; +} + +/***************************************************************************** + * FreePicture: destroy a picture allocated with NewPicture + ***************************************************************************** + * Destroy XImage AND associated data. If using Shm, detach shared memory + * segment from server and process, then free it. The XDestroyImage manpage + * says that both the image structure _and_ the data pointed to by the + * image structure are freed, so no need to free p_image->data. + *****************************************************************************/ +static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* The order of operations is correct */ +#ifdef HAVE_SYS_SHM_H + if( p_vout->p_sys->b_shm ) + { + XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo ); + IMAGE_FREE( p_pic->p_sys->p_image ); + + shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 ); + if( shmdt( p_pic->p_sys->shminfo.shmaddr ) ) + { + msg_Err( p_vout, "cannot detach shared memory (%s)", + strerror(errno) ); + } + } + else +#endif + { + IMAGE_FREE( p_pic->p_sys->p_image ); + } + + /* Do NOT use XFlush here ! */ + XSync( p_vout->p_sys->p_display, False ); + + free( p_pic->p_sys ); +} + +/***************************************************************************** + * ToggleFullScreen: Enable or disable full screen mode + ***************************************************************************** + * This function will switch between fullscreen and window mode. + *****************************************************************************/ +static void ToggleFullScreen ( vout_thread_t *p_vout ) +{ + Atom prop; + mwmhints_t mwmhints; + XSetWindowAttributes attributes; + + p_vout->b_fullscreen = !p_vout->b_fullscreen; + + if( p_vout->b_fullscreen ) + { + msg_Dbg( p_vout, "entering fullscreen mode" ); + p_vout->p_sys->p_win = &p_vout->p_sys->fullscreen_window; + + /* Only check the fullscreen method when we actually go fullscreen, + * because to go back to window mode we need to know in which + * fullscreen mode we were */ + p_vout->p_sys->b_altfullscreen = + config_GetInt( p_vout, MODULE_STRING "-altfullscreen" ); + + /* fullscreen window size and position */ + p_vout->p_sys->p_win->i_width = + DisplayWidth( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ); + p_vout->p_sys->p_win->i_height = + DisplayHeight( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ); + + CreateWindow( p_vout, p_vout->p_sys->p_win ); + + /* To my knowledge there are two ways to create a borderless window. + * There's the generic way which is to tell x to bypass the window + * manager, but this creates problems with the focus of other + * applications. + * The other way is to use the motif property "_MOTIF_WM_HINTS" which + * luckily seems to be supported by most window managers. */ + if( !p_vout->p_sys->b_altfullscreen ) + { + mwmhints.flags = MWM_HINTS_DECORATIONS; + mwmhints.decorations = !p_vout->b_fullscreen; + + prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", + False ); + XChangeProperty( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + prop, prop, 32, PropModeReplace, + (unsigned char *)&mwmhints, + PROP_MWM_HINTS_ELEMENTS ); + } + else + { + /* brute force way to remove decorations */ + attributes.override_redirect = p_vout->b_fullscreen; + XChangeWindowAttributes( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + CWOverrideRedirect, + &attributes); + } + + XReparentWindow( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + DefaultRootWindow( p_vout->p_sys->p_display ), + 0, 0 ); + XMoveResizeWindow( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + 0, 0, + p_vout->p_sys->p_win->i_width, + p_vout->p_sys->p_win->i_height ); + } + else + { + msg_Dbg( p_vout, "leaving fullscreen mode" ); + DestroyWindow( p_vout, &p_vout->p_sys->fullscreen_window ); + p_vout->p_sys->p_win = &p_vout->p_sys->original_window; + } + + XSync( p_vout->p_sys->p_display, True ); + + if( !p_vout->b_fullscreen || p_vout->p_sys->b_altfullscreen ) + { + XSetInputFocus(p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + RevertToParent, + CurrentTime); + } + + /* signal that the size needs to be updated */ + p_vout->i_changes |= VOUT_SIZE_CHANGE; +} + +/***************************************************************************** + * EnableXScreenSaver: enable screen saver + ***************************************************************************** + * This function enables the screen saver on a display after it has been + * disabled by XDisableScreenSaver. + * FIXME: what happens if multiple vlc sessions are running at the same + * time ??? + *****************************************************************************/ +static void EnableXScreenSaver( vout_thread_t *p_vout ) +{ +#ifdef DPMSINFO_IN_DPMS_H + int dummy; +#endif + + XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout, + p_vout->p_sys->i_ss_interval, + p_vout->p_sys->i_ss_blanking, + p_vout->p_sys->i_ss_exposure ); + + /* Restore DPMS settings */ +#ifdef DPMSINFO_IN_DPMS_H + if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) ) + { + if( p_vout->p_sys->b_ss_dpms ) + { + DPMSEnable( p_vout->p_sys->p_display ); + } + } +#endif +} + +/***************************************************************************** + * DisableXScreenSaver: disable screen saver + ***************************************************************************** + * See XEnableXScreenSaver + *****************************************************************************/ +static void DisableXScreenSaver( vout_thread_t *p_vout ) +{ +#ifdef DPMSINFO_IN_DPMS_H + int dummy; +#endif + + /* Save screen saver informations */ + XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout, + &p_vout->p_sys->i_ss_interval, + &p_vout->p_sys->i_ss_blanking, + &p_vout->p_sys->i_ss_exposure ); + + /* Disable screen saver */ + XSetScreenSaver( p_vout->p_sys->p_display, 0, + p_vout->p_sys->i_ss_interval, + p_vout->p_sys->i_ss_blanking, + p_vout->p_sys->i_ss_exposure ); + + /* Disable DPMS */ +#ifdef DPMSINFO_IN_DPMS_H + if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) ) + { + CARD16 unused; + /* Save DPMS current state */ + DPMSInfo( p_vout->p_sys->p_display, &unused, + &p_vout->p_sys->b_ss_dpms ); + DPMSDisable( p_vout->p_sys->p_display ); + } +#endif +} + +/***************************************************************************** + * CreateCursor: create a blank mouse pointer + *****************************************************************************/ +static void CreateCursor( vout_thread_t *p_vout ) +{ + XColor cursor_color; + + p_vout->p_sys->cursor_pixmap = + XCreatePixmap( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + 1, 1, 1 ); + + XParseColor( p_vout->p_sys->p_display, + XCreateColormap( p_vout->p_sys->p_display, + DefaultRootWindow( + p_vout->p_sys->p_display ), + DefaultVisual( + p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ), + AllocNone ), + "black", &cursor_color ); + + p_vout->p_sys->blank_cursor = + XCreatePixmapCursor( p_vout->p_sys->p_display, + p_vout->p_sys->cursor_pixmap, + p_vout->p_sys->cursor_pixmap, + &cursor_color, &cursor_color, 1, 1 ); +} + +/***************************************************************************** + * DestroyCursor: destroy the blank mouse pointer + *****************************************************************************/ +static void DestroyCursor( vout_thread_t *p_vout ) +{ + XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap ); +} + +/***************************************************************************** + * ToggleCursor: hide or show the mouse pointer + ***************************************************************************** + * This function hides the X pointer if it is visible by setting the pointer + * sprite to a blank one. To show it again, we disable the sprite. + *****************************************************************************/ +static void ToggleCursor( vout_thread_t *p_vout ) +{ + if( p_vout->p_sys->b_mouse_pointer_visible ) + { + XDefineCursor( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window, + p_vout->p_sys->blank_cursor ); + p_vout->p_sys->b_mouse_pointer_visible = 0; + } + else + { + XUndefineCursor( p_vout->p_sys->p_display, + p_vout->p_sys->p_win->base_window ); + p_vout->p_sys->b_mouse_pointer_visible = 1; + } +} + +#ifdef MODULE_NAME_IS_xvideo +/***************************************************************************** + * XVideoGetPort: get YUV12 port + *****************************************************************************/ +static int XVideoGetPort( vout_thread_t *p_vout, + vlc_fourcc_t i_chroma, vlc_fourcc_t *pi_newchroma ) +{ + XvAdaptorInfo *p_adaptor; + unsigned int i; + int i_adaptor, i_num_adaptors, i_requested_adaptor; + int i_selected_port; + + switch( XvQueryExtension( p_vout->p_sys->p_display, &i, &i, &i, &i, &i ) ) + { + case Success: + break; + + case XvBadExtension: + msg_Warn( p_vout, "XvBadExtension" ); + return( -1 ); + + case XvBadAlloc: + msg_Warn( p_vout, "XvBadAlloc" ); + return( -1 ); + + default: + msg_Warn( p_vout, "XvQueryExtension failed" ); + return( -1 ); + } + + switch( XvQueryAdaptors( p_vout->p_sys->p_display, + DefaultRootWindow( p_vout->p_sys->p_display ), + &i_num_adaptors, &p_adaptor ) ) + { + case Success: + break; + + case XvBadExtension: + msg_Warn( p_vout, "XvBadExtension for XvQueryAdaptors" ); + return( -1 ); + + case XvBadAlloc: + msg_Warn( p_vout, "XvBadAlloc for XvQueryAdaptors" ); + return( -1 ); + + default: + msg_Warn( p_vout, "XvQueryAdaptors failed" ); + return( -1 ); + } + + i_selected_port = -1; + i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" ); + + for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor ) + { + XvImageFormatValues *p_formats; + int i_format, i_num_formats; + int i_port; + + /* If we requested an adaptor and it's not this one, we aren't + * interested */ + if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor ) + { + continue; + } + + /* If the adaptor doesn't have the required properties, skip it */ + if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) || + !( p_adaptor[ i_adaptor ].type & XvImageMask ) ) + { + continue; + } + + /* Check that adaptor supports our requested format... */ + p_formats = XvListImageFormats( p_vout->p_sys->p_display, + p_adaptor[i_adaptor].base_id, + &i_num_formats ); + + for( i_format = 0; + i_format < i_num_formats && ( i_selected_port == -1 ); + i_format++ ) + { + /* Code removed, we can get this through xvinfo anyway */ +#if 0 + XvEncodingInfo *p_enc; + int i_enc, i_num_encodings; + XvAttribute *p_attr; + int i_attr, i_num_attributes; +#endif + + /* If this is not the format we want, or at least a + * similar one, forget it */ + if( !vout_ChromaCmp( p_formats[ i_format ].id, i_chroma ) ) + { + continue; + } + + /* Look for the first available port supporting this format */ + for( i_port = p_adaptor[i_adaptor].base_id; + ( i_port < p_adaptor[i_adaptor].base_id + + p_adaptor[i_adaptor].num_ports ) + && ( i_selected_port == -1 ); + i_port++ ) + { + if( XvGrabPort( p_vout->p_sys->p_display, i_port, CurrentTime ) + == Success ) + { + i_selected_port = i_port; + *pi_newchroma = p_formats[ i_format ].id; + } + } + + /* If no free port was found, forget it */ + if( i_selected_port == -1 ) + { + continue; + } + + /* If we found a port, print information about it */ + msg_Dbg( p_vout, "adaptor %i, port %i, format 0x%x (%4.4s) %s", + i_adaptor, i_selected_port, p_formats[ i_format ].id, + (char *)&p_formats[ i_format ].id, + ( p_formats[ i_format ].format == XvPacked ) ? + "packed" : "planar" ); + +#if 0 + msg_Dbg( p_vout, " encoding list:" ); + + if( XvQueryEncodings( p_vout->p_sys->p_display, i_selected_port, + &i_num_encodings, &p_enc ) + != Success ) + { + msg_Dbg( p_vout, " XvQueryEncodings failed" ); + continue; + } + + for( i_enc = 0; i_enc < i_num_encodings; i_enc++ ) + { + msg_Dbg( p_vout, " id=%ld, name=%s, size=%ldx%ld," + " numerator=%d, denominator=%d", + p_enc[i_enc].encoding_id, p_enc[i_enc].name, + p_enc[i_enc].width, p_enc[i_enc].height, + p_enc[i_enc].rate.numerator, + p_enc[i_enc].rate.denominator ); + } + + if( p_enc != NULL ) + { + XvFreeEncodingInfo( p_enc ); + } + + msg_Dbg( p_vout, " attribute list:" ); + p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display, + i_selected_port, + &i_num_attributes ); + for( i_attr = 0; i_attr < i_num_attributes; i_attr++ ) + { + msg_Dbg( p_vout, " name=%s, flags=[%s%s ], min=%i, max=%i", + p_attr[i_attr].name, + (p_attr[i_attr].flags & XvGettable) ? " get" : "", + (p_attr[i_attr].flags & XvSettable) ? " set" : "", + p_attr[i_attr].min_value, p_attr[i_attr].max_value ); + } + + if( p_attr != NULL ) + { + XFree( p_attr ); + } +#endif + } + + if( p_formats != NULL ) + { + XFree( p_formats ); + } + + } + + if( i_num_adaptors > 0 ) + { + XvFreeAdaptorInfo( p_adaptor ); + } + + if( i_selected_port == -1 ) + { + if( i_requested_adaptor == -1 ) + { + msg_Warn( p_vout, "no free XVideo port found for format " + "0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma ); + } + else + { + msg_Warn( p_vout, "XVideo adaptor %i does not have a free " + "XVideo port for format 0x%.8x (%4.4s)", + i_requested_adaptor, i_chroma, (char*)&i_chroma ); + } + } + + return( i_selected_port ); +} + +/***************************************************************************** + * XVideoReleasePort: release YUV12 port + *****************************************************************************/ +static void XVideoReleasePort( vout_thread_t *p_vout, int i_port ) +{ + XvUngrabPort( p_vout->p_sys->p_display, i_port, CurrentTime ); +} +#endif + +/***************************************************************************** + * InitDisplay: open and initialize X11 device + ***************************************************************************** + * Create a window according to video output given size, and set other + * properties according to the display properties. + *****************************************************************************/ +static int InitDisplay( vout_thread_t *p_vout ) +{ +#ifdef MODULE_NAME_IS_x11 + XPixmapFormatValues * p_formats; /* pixmap formats */ + XVisualInfo * p_xvisual; /* visuals informations */ + XVisualInfo xvisual_template; /* visual template */ + int i_count; /* array size */ +#endif + +#ifdef HAVE_SYS_SHM_H + p_vout->p_sys->b_shm = 0; + + if( config_GetInt( p_vout, MODULE_STRING "-shm" ) ) + { +# ifdef SYS_DARWIN + /* FIXME: As of 2001-03-16, XFree4 for MacOS X does not support Xshm */ +# else + p_vout->p_sys->b_shm = + ( XShmQueryExtension( p_vout->p_sys->p_display ) == True ); +# endif + + if( !p_vout->p_sys->b_shm ) + { + msg_Warn( p_vout, "XShm video extension is unavailable" ); + } + } + else + { + msg_Dbg( p_vout, "disabling XShm video extension" ); + } + +#else + msg_Warn( p_vout, "XShm video extension is unavailable" ); + +#endif + +#ifdef MODULE_NAME_IS_xvideo + /* XXX The brightness and contrast values should be read from environment + * XXX variables... */ +#if 0 + XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 ); + XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 ); +#endif +#endif + +#ifdef MODULE_NAME_IS_x11 + /* Initialize structure */ + p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display ); + + /* Get screen depth */ + p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display, + p_vout->p_sys->i_screen ); + switch( p_vout->p_sys->i_screen_depth ) + { + case 8: + /* + * Screen depth is 8bpp. Use PseudoColor visual with private colormap. + */ + xvisual_template.screen = p_vout->p_sys->i_screen; + xvisual_template.class = DirectColor; + p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display, + VisualScreenMask | VisualClassMask, + &xvisual_template, &i_count ); + if( p_xvisual == NULL ) + { + msg_Err( p_vout, "no PseudoColor visual available" ); + return( 1 ); + } + p_vout->p_sys->i_bytes_per_pixel = 1; + p_vout->output.pf_setpalette = SetPalette; + break; + case 15: + case 16: + case 24: + default: + /* + * Screen depth is higher than 8bpp. TrueColor visual is used. + */ + xvisual_template.screen = p_vout->p_sys->i_screen; + xvisual_template.class = TrueColor; + p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display, + VisualScreenMask | VisualClassMask, + &xvisual_template, &i_count ); + if( p_xvisual == NULL ) + { + msg_Err( p_vout, "no TrueColor visual available" ); + return( 1 ); + } + + p_vout->output.i_rmask = p_xvisual->red_mask; + p_vout->output.i_gmask = p_xvisual->green_mask; + p_vout->output.i_bmask = p_xvisual->blue_mask; + + /* There is no difference yet between 3 and 4 Bpp. The only way + * to find the actual number of bytes per pixel is to list supported + * pixmap formats. */ + p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count ); + p_vout->p_sys->i_bytes_per_pixel = 0; + + for( ; i_count-- ; p_formats++ ) + { + /* Under XFree4.0, the list contains pixmap formats available + * through all video depths ; so we have to check against current + * depth. */ + if( p_formats->depth == p_vout->p_sys->i_screen_depth ) + { + if( p_formats->bits_per_pixel / 8 + > p_vout->p_sys->i_bytes_per_pixel ) + { + p_vout->p_sys->i_bytes_per_pixel = p_formats->bits_per_pixel / 8; + } + } + } + break; + } + p_vout->p_sys->p_visual = p_xvisual->visual; + XFree( p_xvisual ); +#endif + + return( 0 ); +} + +#ifdef HAVE_SYS_SHM_H +/***************************************************************************** + * CreateShmImage: create an XImage or XvImage using shared memory extension + ***************************************************************************** + * Prepare an XImage or XvImage for display function. + * The order of the operations respects the recommandations of the mit-shm + * document by J.Corbet and K.Packard. Most of the parameters were copied from + * there. See http://ftp.xfree86.org/pub/XFree86/4.0/doc/mit-shm.TXT + *****************************************************************************/ +static IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout, + Display* p_display, EXTRA_ARGS_SHM, + int i_width, int i_height ) +{ + IMAGE_TYPE *p_image; + + /* Create XImage / XvImage */ +#ifdef MODULE_NAME_IS_xvideo + p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0, + i_width, i_height, p_shm ); +#else + p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0, + p_shm, i_width, i_height ); +#endif + if( p_image == NULL ) + { + msg_Err( p_vout, "image creation failed" ); + return( NULL ); + } + + /* Allocate shared memory segment - 0776 set the access permission + * rights (like umask), they are not yet supported by all X servers */ + p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0776 ); + if( p_shm->shmid < 0 ) + { + msg_Err( p_vout, "cannot allocate shared image data (%s)", + strerror( errno ) ); + IMAGE_FREE( p_image ); + return( NULL ); + } + + /* Attach shared memory segment to process (read/write) */ + p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 ); + if(! p_shm->shmaddr ) + { + msg_Err( p_vout, "cannot attach shared memory (%s)", + strerror(errno)); + IMAGE_FREE( p_image ); + shmctl( p_shm->shmid, IPC_RMID, 0 ); + return( NULL ); + } + + /* Read-only data. We won't be using XShmGetImage */ + p_shm->readOnly = True; + + /* Attach shared memory segment to X server */ + if( XShmAttach( p_display, p_shm ) == False ) + { + msg_Err( p_vout, "cannot attach shared memory to X server" ); + IMAGE_FREE( p_image ); + shmctl( p_shm->shmid, IPC_RMID, 0 ); + shmdt( p_shm->shmaddr ); + return( NULL ); + } + + /* Send image to X server. This instruction is required, since having + * built a Shm XImage and not using it causes an error on XCloseDisplay, + * and remember NOT to use XFlush ! */ + XSync( p_display, False ); + +#if 0 + /* Mark the shm segment to be removed when there are no more + * attachements, so it is automatic on process exit or after shmdt */ + shmctl( p_shm->shmid, IPC_RMID, 0 ); +#endif + + return( p_image ); +} +#endif + +/***************************************************************************** + * CreateImage: create an XImage or XvImage + ***************************************************************************** + * Create a simple image used as a buffer. + *****************************************************************************/ +static IMAGE_TYPE * CreateImage( vout_thread_t *p_vout, + Display *p_display, EXTRA_ARGS, + int i_width, int i_height ) +{ + byte_t * p_data; /* image data storage zone */ + IMAGE_TYPE *p_image; +#ifdef MODULE_NAME_IS_x11 + int i_quantum; /* XImage quantum (see below) */ + int i_bytes_per_line; +#endif + + /* Allocate memory for image */ +#ifdef MODULE_NAME_IS_xvideo + p_data = (byte_t *) malloc( i_width * i_height * 2 ); /* XXX */ +#else + i_bytes_per_line = i_width * i_bytes_per_pixel; + p_data = (byte_t *) malloc( i_bytes_per_line * i_height ); +#endif + if( !p_data ) + { + msg_Err( p_vout, "out of memory" ); + return( NULL ); + } + +#ifdef MODULE_NAME_IS_x11 + /* Optimize the quantum of a scanline regarding its size - the quantum is + a diviser of the number of bits between the start of two scanlines. */ + if( i_bytes_per_line & 0xf ) + { + i_quantum = 0x8; + } + else if( i_bytes_per_line & 0x10 ) + { + i_quantum = 0x10; + } + else + { + i_quantum = 0x20; + } +#endif + + /* Create XImage. p_data will be automatically freed */ +#ifdef MODULE_NAME_IS_xvideo + p_image = XvCreateImage( p_display, i_xvport, i_chroma, + p_data, i_width, i_height ); +#else + p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0, + p_data, i_width, i_height, i_quantum, 0 ); +#endif + if( p_image == NULL ) + { + msg_Err( p_vout, "XCreateImage() failed" ); + free( p_data ); + return( NULL ); + } + + return p_image; +} + +#ifdef MODULE_NAME_IS_x11 +/***************************************************************************** + * SetPalette: sets an 8 bpp palette + ***************************************************************************** + * This function sets the palette given as an argument. It does not return + * anything, but could later send information on which colors it was unable + * to set. + *****************************************************************************/ +static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) +{ + int i; + XColor p_colors[255]; + + /* allocate palette */ + for( i = 0; i < 255; i++ ) + { + /* kludge: colors are indexed reversely because color 255 seems + * to be reserved for black even if we try to set it to white */ + p_colors[ i ].pixel = 255 - i; + p_colors[ i ].pad = 0; + p_colors[ i ].flags = DoRed | DoGreen | DoBlue; + p_colors[ i ].red = red[ 255 - i ]; + p_colors[ i ].blue = blue[ 255 - i ]; + p_colors[ i ].green = green[ 255 - i ]; + } + + XStoreColors( p_vout->p_sys->p_display, + p_vout->p_sys->colormap, p_colors, 255 ); +} +#endif diff --git a/modules/video_output/x11/xcommon.h b/modules/video_output/x11/xcommon.h new file mode 100644 index 0000000000..179958d3ea --- /dev/null +++ b/modules/video_output/x11/xcommon.h @@ -0,0 +1,157 @@ +/***************************************************************************** + * xcommon.h: Defines common to the X11 and XVideo plugins + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: xcommon.h,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Vincent Seguin + * Samuel Hocevar + * David Kennedy + * Gildas Bazin + * + * 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. + *****************************************************************************/ + +/***************************************************************************** + * Defines + *****************************************************************************/ +#ifdef MODULE_NAME_IS_xvideo +# define IMAGE_TYPE XvImage +# define EXTRA_ARGS int i_xvport, int i_chroma +# define EXTRA_ARGS_SHM int i_xvport, int i_chroma, XShmSegmentInfo *p_shm +# define DATA_SIZE(p) (p)->data_size +# define IMAGE_FREE XFree /* There is nothing like XvDestroyImage */ +#else +# define IMAGE_TYPE XImage +# define EXTRA_ARGS Visual *p_visual, int i_depth, int i_bytes_per_pixel +# define EXTRA_ARGS_SHM Visual *p_visual, int i_depth, XShmSegmentInfo *p_shm +# define DATA_SIZE(p) ((p)->bytes_per_line * (p)->height) +# define IMAGE_FREE XDestroyImage +#endif + +VLC_DECLARE_STRUCT(x11_window_t) + +/***************************************************************************** + * x11_window_t: X11 window descriptor + ***************************************************************************** + * This structure contains all the data necessary to describe an X11 window. + *****************************************************************************/ +struct x11_window_t +{ + Window base_window; /* base window */ + Window video_window; /* sub-window for displaying video */ + GC gc; /* graphic context instance handler */ + int i_width; /* width of main window */ + int i_height; /* height of main window */ + Atom wm_protocols; + Atom wm_delete_window; +}; + +/***************************************************************************** + * vout_sys_t: video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the X11 and XVideo specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + /* Internal settings and properties */ + Display * p_display; /* display pointer */ + + Visual * p_visual; /* visual pointer */ + int i_screen; /* screen number */ + + /* Our current window */ + x11_window_t * p_win; + + /* Our two windows */ + x11_window_t original_window; + x11_window_t fullscreen_window; + + /* X11 generic properties */ + vlc_bool_t b_altfullscreen; /* which fullscreen method */ + vlc_bool_t b_createwindow; /* are we the base window's owner ? */ +#ifdef HAVE_SYS_SHM_H + vlc_bool_t b_shm; /* shared memory extension flag */ +#endif + +#ifdef MODULE_NAME_IS_xvideo + int i_xvport; +#else + Colormap colormap; /* colormap used (8bpp only) */ + + int i_screen_depth; + int i_bytes_per_pixel; + int i_bytes_per_line; +#endif + + /* Screen saver properties */ + int i_ss_timeout; /* timeout */ + int i_ss_interval; /* interval between changes */ + int i_ss_blanking; /* blanking mode */ + int i_ss_exposure; /* exposure mode */ +#ifdef DPMSINFO_IN_DPMS_H + BOOL b_ss_dpms; /* DPMS mode */ +#endif + + /* Mouse pointer properties */ + vlc_bool_t b_mouse_pointer_visible; + mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/ + Cursor blank_cursor; /* the hidden cursor */ + mtime_t i_time_button_last_pressed; /* to track dbl-clicks */ + Pixmap cursor_pixmap; +}; + +/***************************************************************************** + * picture_sys_t: direct buffer method descriptor + ***************************************************************************** + * This structure is part of the picture descriptor, it describes the + * XVideo specific properties of a direct buffer. + *****************************************************************************/ +struct picture_sys_t +{ + IMAGE_TYPE * p_image; + +#ifdef HAVE_SYS_SHM_H + XShmSegmentInfo shminfo; /* shared memory zone information */ +#endif +}; + +/***************************************************************************** + * mwmhints_t: window manager hints + ***************************************************************************** + * Fullscreen needs to be able to hide the wm decorations so we provide + * this structure to make it easier. + *****************************************************************************/ +#define MWM_HINTS_DECORATIONS (1L << 1) +#define PROP_MWM_HINTS_ELEMENTS 5 +typedef struct mwmhints_t +{ + u32 flags; + u32 functions; + u32 decorations; + s32 input_mode; + u32 status; +} mwmhints_t; + +/***************************************************************************** + * Chroma defines + *****************************************************************************/ +#ifdef MODULE_NAME_IS_xvideo +# define MAX_DIRECTBUFFERS 10 +#else +# define MAX_DIRECTBUFFERS 2 +#endif + diff --git a/modules/video_output/x11/xvideo.c b/modules/video_output/x11/xvideo.c new file mode 100644 index 0000000000..0e6807a19c --- /dev/null +++ b/modules/video_output/x11/xvideo.c @@ -0,0 +1,132 @@ +/***************************************************************************** + * xvideo.c : Xvideo plugin for vlc + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: xvideo.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Shane Harper + * Vincent Seguin + * Samuel Hocevar + * David Kennedy + * + * 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 /* malloc(), free() */ +#include /* strerror() */ + +#include + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +extern int E_(Activate) ( vlc_object_t * ); +extern void E_(Deactivate) ( vlc_object_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define ADAPTOR_TEXT N_("XVideo adaptor number") +#define ADAPTOR_LONGTEXT N_( \ + "If you graphics card provides several adaptors, this option allows you " \ + "to choose which one will be used (you shouldn't have to change this).") + +#define ALT_FS_TEXT N_("alternate fullscreen method") +#define ALT_FS_LONGTEXT N_( \ + "There are two ways to make a fullscreen window, unfortunately each one " \ + "has its drawbacks.\n" \ + "1) Let the window manager handle your fullscreen window (default). But " \ + "things like taskbars will likely show on top of the video.\n" \ + "2) Completly bypass the window manager, but then nothing will be able " \ + "to show on top of the video.") + +#define DISPLAY_TEXT N_("X11 display name") +#define DISPLAY_LONGTEXT N_( \ + "Specify the X11 hardware display you want to use. By default vlc will " \ + "use the value of the DISPLAY environment variable.") + +#define CHROMA_TEXT N_("XVimage chroma format") +#define CHROMA_LONGTEXT N_( \ + "Force the XVideo renderer to use a specific chroma format instead of " \ + "trying to improve performances by using the most efficient one.") + +#define DRAWABLE_TEXT N_("X11 drawable") +#define DRAWABLE_LONGTEXT N_( \ + "Specify a X11 drawable to use instead of opening a new window. This " \ + "option is DANGEROUS, use with care.") + +#define SHM_TEXT N_("use shared memory") +#define SHM_LONGTEXT N_( \ + "Use shared memory to communicate between vlc and the X server.") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_string( "xvideo-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT ); + add_integer( "xvideo-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT ); + add_bool( "xvideo-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT ); + add_string( "xvideo-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT ); + add_integer( "xvideo-drawable", -1, NULL, DRAWABLE_TEXT, DRAWABLE_LONGTEXT ); +#ifdef HAVE_SYS_SHM_H + add_bool( "xvideo-shm", 1, NULL, SHM_TEXT, SHM_LONGTEXT ); +#endif + set_description( _("XVideo extension module") ); + set_capability( "video output", 150 ); + set_callbacks( E_(Activate), E_(Deactivate) ); +vlc_module_end(); + +/* following functions are local */ + +#if 0 +/***************************************************************************** + * XVideoSetAttribute + ***************************************************************************** + * This function can be used to set attributes, e.g. XV_BRIGHTNESS and + * XV_CONTRAST. "f_value" should be in the range of 0 to 1. + *****************************************************************************/ +static void XVideoSetAttribute( vout_thread_t *p_vout, + char *attr_name, float f_value ) +{ + int i_attrib; + XvAttribute *p_attrib; + Display *p_display = p_vout->p_sys->p_display; + int i_xvport = p_vout->p_sys->i_xvport; + + p_attrib = XvQueryPortAttributes( p_display, i_xvport, &i_attrib ); + + do + { + i_attrib--; + + if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) ) + { + int i_sv = f_value * ( p_attrib[ i_attrib ].max_value + - p_attrib[ i_attrib ].min_value + 1 ) + + p_attrib[ i_attrib ].min_value; + + XvSetPortAttribute( p_display, i_xvport, + XInternAtom( p_display, attr_name, False ), i_sv ); + break; + } + + } while( i_attrib > 0 ); + + if( p_attrib ) + XFree( p_attrib ); +} +#endif + diff --git a/modules/visualization/scope/.cvsignore b/modules/visualization/scope/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/visualization/scope/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/visualization/scope/Makefile b/modules/visualization/scope/Makefile new file mode 100644 index 0000000000..12eedae677 --- /dev/null +++ b/modules/visualization/scope/Makefile @@ -0,0 +1 @@ +scope_SOURCES = scope.c diff --git a/modules/visualization/scope/scope.c b/modules/visualization/scope/scope.c new file mode 100644 index 0000000000..9a79c3b1bd --- /dev/null +++ b/modules/visualization/scope/scope.c @@ -0,0 +1,299 @@ +/***************************************************************************** + * scope.c : Scope effect module + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: scope.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Samuel Hocevar + * + * 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 /* malloc(), free() */ +#include /* strdup() */ +#include + +#include +#include +#include + +#define SCOPE_WIDTH 320 +#define SCOPE_HEIGHT 240 +#define SCOPE_ASPECT (VOUT_ASPECT_FACTOR*SCOPE_WIDTH/SCOPE_HEIGHT) + +/***************************************************************************** + * aout_sys_t: scope audio output method descriptor + ***************************************************************************** + * This structure is part of the audio output thread descriptor. + * It describes some scope specific variables. + *****************************************************************************/ +struct aout_sys_t +{ + aout_fifo_t *p_aout_fifo; + + aout_thread_t *p_aout; + vout_thread_t *p_vout; +}; + +/***************************************************************************** + * 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( _("scope effect") ); + set_capability( "audio output", 0 ); + set_callbacks( Open, Close ); + add_shortcut( "scope" ); +vlc_module_end(); + +/***************************************************************************** + * Open: open a scope effect plugin + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + aout_thread_t *p_aout = (aout_thread_t *)p_this; + char *psz_method; + + /* 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; + } + + psz_method = config_GetPsz( p_aout, "aout" ); + if( psz_method ) + { + if( !*psz_method ) + { + free( psz_method ); + return -1; + } + } + else + { + return -1; + } + + /* Open video output */ + p_aout->p_sys->p_vout = + vout_CreateThread( p_aout, SCOPE_WIDTH, SCOPE_HEIGHT, + VLC_FOURCC('I','4','2','0'), SCOPE_ASPECT ); + + if( p_aout->p_sys->p_vout == NULL ) + { + msg_Err( p_aout, "no suitable vout module" ); + free( p_aout->p_sys ); + return -1; + } + + /* Open audio output */ + p_aout->p_sys->p_aout = vlc_object_create( p_aout, VLC_OBJECT_AOUT ); + + p_aout->p_sys->p_aout->i_format = p_aout->i_format; + p_aout->p_sys->p_aout->i_rate = p_aout->i_rate; + p_aout->p_sys->p_aout->i_channels = p_aout->i_channels; + + p_aout->p_sys->p_aout->p_module = + module_Need( p_aout->p_sys->p_aout, "audio output", "" ); + if( p_aout->p_sys->p_aout->p_module == NULL ) + { + msg_Err( p_aout, "no suitable aout module" ); + vlc_object_destroy( p_aout->p_sys->p_aout ); + vout_DestroyThread( p_aout->p_sys->p_vout ); + free( p_aout->p_sys ); + return -1; + } + + vlc_object_attach( p_aout->p_sys->p_aout, p_aout ); + + 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_ret; + + /* Force the output method */ + p_aout->p_sys->p_aout->i_format = p_aout->i_format; + p_aout->p_sys->p_aout->i_channels = p_aout->i_channels; + p_aout->p_sys->p_aout->i_rate = p_aout->i_rate; + + /* + * Initialize audio device + */ + i_ret = p_aout->p_sys->p_aout->pf_setformat( p_aout->p_sys->p_aout ); + + if( i_ret ) + { + return i_ret; + } + + if( p_aout->p_sys->p_aout->i_format != p_aout->i_format + || p_aout->p_sys->p_aout->i_channels != p_aout->i_channels ) + { + msg_Err( p_aout, "plugin is not very cooperative" ); + return 0; + } + + p_aout->i_channels = p_aout->p_sys->p_aout->i_channels; + p_aout->i_format = p_aout->p_sys->p_aout->i_format; + p_aout->i_rate = p_aout->p_sys->p_aout->i_rate; + + return 0; +} + +/***************************************************************************** + * GetBufInfo: buffer status query + *****************************************************************************/ +static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) +{ + return p_aout->p_sys->p_aout->pf_getbufinfo( p_aout->p_sys->p_aout, + 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 *p_buffer, int i_size ) +{ + picture_t *p_outpic; + int i_index, i_image; + u8 *ppp_area[2][3]; + u16 *p_sample; + + /* Play the real sound */ + p_aout->p_sys->p_aout->pf_play( p_aout->p_sys->p_aout, p_buffer, i_size ); + + for( i_image = 0; (i_image + 1) * SCOPE_WIDTH * 8 < i_size ; i_image++ ) + { + /* Don't stay here forever */ + if( mdate() >= p_aout->date - 10000 ) + { + break; + } + + /* This is a new frame. Get a structure from the video_output. */ + while( ( p_outpic = vout_CreatePicture( p_aout->p_sys->p_vout, 0, 0, 0 ) ) + == NULL ) + { + if( p_aout->b_die ) + { + return; + } + msleep( VOUT_OUTMEM_SLEEP ); + } + + /* Blank the picture */ + for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ ) + { + memset( p_outpic->p[i_index].p_pixels, i_index ? 0x80 : 0x00, + p_outpic->p[i_index].i_lines * p_outpic->p[i_index].i_pitch ); + } + + /* We only support 2 channels for now */ + for( i_index = 0 ; i_index < 2 ; i_index++ ) + { + int j; + for( j = 0 ; j < 3 ; j++ ) + { + ppp_area[i_index][j] = + p_outpic->p[j].p_pixels + i_index * p_outpic->p[j].i_lines + / p_aout->i_channels * p_outpic->p[j].i_pitch; + } + } + + for( i_index = 0, p_sample = (u16*)p_buffer; + i_index < SCOPE_WIDTH; + i_index++ ) + { + int i; + u8 i_value; + + for( i = 0 ; i < 2 ; i++ ) + { + /* Left channel */ + i_value = *p_sample++ / 256 + 128; + *(ppp_area[0][0] + + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH + + p_outpic->p[0].i_lines * i_value / 512 + * p_outpic->p[0].i_pitch) = 0xbf; + *(ppp_area[0][1] + + p_outpic->p[1].i_pitch * i_index / SCOPE_WIDTH + + p_outpic->p[1].i_lines * i_value / 512 + * p_outpic->p[1].i_pitch) = 0xff; + + /* Right channel */ + i_value = *p_sample++ / 256 + 128; + *(ppp_area[1][0] + + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH + + p_outpic->p[0].i_lines * i_value / 512 + * p_outpic->p[0].i_pitch) = 0x9f; + *(ppp_area[1][2] + + p_outpic->p[2].i_pitch * i_index / SCOPE_WIDTH + + p_outpic->p[2].i_lines * i_value / 512 + * p_outpic->p[2].i_pitch) = 0xdd; + } + } + + /* Display the picture - FIXME: find a better date :-) */ + vout_DatePicture( p_aout->p_sys->p_vout, p_outpic, + p_aout->date + i_image * 20000 ); + vout_DisplayPicture( p_aout->p_sys->p_vout, p_outpic ); + + p_buffer += SCOPE_WIDTH * 4; + } +} + +/***************************************************************************** + * Close: close the plugin + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + aout_thread_t *p_aout = (aout_thread_t *)p_this; + + /* Kill audio output */ + module_Unneed( p_aout->p_sys->p_aout, p_aout->p_sys->p_aout->p_module ); + vlc_object_detach_all( p_aout->p_sys->p_aout ); + vlc_object_destroy( p_aout->p_sys->p_aout ); + + /* Kill video output */ + vout_DestroyThread( p_aout->p_sys->p_vout ); + + free( p_aout->p_sys ); +} + diff --git a/modules/visualization/xosd/.cvsignore b/modules/visualization/xosd/.cvsignore new file mode 100644 index 0000000000..435f39ed89 --- /dev/null +++ b/modules/visualization/xosd/.cvsignore @@ -0,0 +1,4 @@ +.dep +*.lo +*.o.* +*.lo.* diff --git a/modules/visualization/xosd/Makefile b/modules/visualization/xosd/Makefile new file mode 100644 index 0000000000..07c05422a5 --- /dev/null +++ b/modules/visualization/xosd/Makefile @@ -0,0 +1 @@ +xosd_SOURCES = xosd.c diff --git a/modules/visualization/xosd/xosd.c b/modules/visualization/xosd/xosd.c new file mode 100644 index 0000000000..572b03bb61 --- /dev/null +++ b/modules/visualization/xosd/xosd.c @@ -0,0 +1,200 @@ +/***************************************************************************** + * xosd.c : X On Screen Display interface + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: xosd.c,v 1.1 2002/08/04 17:23:44 sam Exp $ + * + * Authors: Loïc Minier + * + * 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 /* malloc(), free() */ +#include + +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +/***************************************************************************** + * intf_sys_t: description and status of rc interface + *****************************************************************************/ +struct intf_sys_t +{ + input_thread_t * p_input; /* associated input thread */ + xosd * p_osd; /* libxosd handle */ + char * psz_source; /* current file || NULL */ +}; + +#define MAX_LINE_LENGTH 256 + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static void Run ( intf_thread_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define POSITION_TEXT N_("flip vertical position") +#define POSITION_LONGTEXT N_("Display xosd output on the bottom of the " \ + "screen instead of the top") + +#define TXT_OFS_TEXT N_("vertical offset") +#define TXT_OFS_LONGTEXT N_("Vertical offset in pixels of the displayed text") + +#define SHD_OFS_TEXT N_("shadow offset") +#define SHD_OFS_LONGTEXT N_("Offset in pixels of the shadow") + +#define FONT_TEXT N_("font") +#define FONT_LONGTEXT N_("Font used to display text in the xosd output") + +vlc_module_begin(); + add_category_hint( N_("Miscellaneous"), NULL ); + add_bool( "xosd-position", 1, NULL, POSITION_TEXT, POSITION_LONGTEXT ); + add_integer( "xosd-text-offset", 0, NULL, TXT_OFS_TEXT, TXT_OFS_LONGTEXT ); + add_integer( "xosd-shadow-offset", 1, NULL, + SHD_OFS_TEXT, SHD_OFS_LONGTEXT ); + add_string( "xosd-font", "-misc-fixed-medium-r-*-*-*-300-*-*-*-*-*-*", + NULL, FONT_TEXT, FONT_LONGTEXT ); + set_description( _("xosd interface module") ); + set_capability( "interface", 40 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Open: initialize and create stuff + *****************************************************************************/ +static int Open( 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 = (intf_sys_t *)malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + msg_Err( p_intf, "out of memory" ); + return( 1 ); + } + + /* Initialize library */ + p_intf->p_sys->p_osd = + xosd_init( "fixed", "LawnGreen", 3, XOSD_top, 0, 1 ); + + /* Initialize to NULL */ + p_intf->p_sys->psz_source = NULL; + + xosd_display( p_intf->p_sys->p_osd, + 0, + XOSD_string, + "xosd interface initialized" ); + + p_intf->pf_run = Run; + + return( 0 ); +} + +/***************************************************************************** + * Close: destroy interface stuff + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->psz_source ) free( p_intf->p_sys->psz_source ); + + /* Uninitialize library */ + xosd_uninit( p_intf->p_sys->p_osd ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: xosd thread + ***************************************************************************** + * This part of the interface runs in a separate thread + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + p_intf->p_sys->p_input = NULL; + + while( !p_intf->b_die ) + { + /* Manage the input part */ + if( p_intf->p_sys->p_input == NULL ) + { + p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + } + else if( p_intf->p_sys->p_input->b_dead ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + else /* We have a valid input */ + { + /* Did source change? */ + if ( (p_intf->p_sys->psz_source == NULL) + || (strcmp( p_intf->p_sys->psz_source, + p_intf->p_sys->p_input->psz_source ) != 0) + ) + { + if( p_intf->p_sys->psz_source ) + free( p_intf->p_sys->psz_source ); + + p_intf->p_sys->psz_source = + strdup( p_intf->p_sys->p_input->psz_source ); + + /* Set user preferences */ + xosd_set_font( p_intf->p_sys->p_osd, + config_GetPsz( p_intf, "xosd-font" ) ); + xosd_set_offset( p_intf->p_sys->p_osd, + config_GetInt( p_intf, "xosd-text-offset" ) ); + xosd_set_shadow_offset( p_intf->p_sys->p_osd, + config_GetInt( p_intf, "xosd-shadow-offset" )); + xosd_set_pos( p_intf->p_sys->p_osd, + config_GetInt( p_intf, "xosd-position" ) ? XOSD_bottom + : XOSD_top ); + + /* Display */ + xosd_display( p_intf->p_sys->p_osd, + 0, /* first line */ + XOSD_string, + p_intf->p_sys->psz_source ); + } + } + + msleep( INTF_IDLE_SLEEP ); + } + + if( p_intf->p_sys->p_input ) + { + vlc_object_release( p_intf->p_sys->p_input ); + p_intf->p_sys->p_input = NULL; + } + +} + diff --git a/src/audio_output/aout_spdif.c b/src/audio_output/aout_spdif.c index 79c69a694f..686d8d56d8 100644 --- a/src/audio_output/aout_spdif.c +++ b/src/audio_output/aout_spdif.c @@ -1,8 +1,8 @@ /***************************************************************************** - * aout_spdif.c: AC3 passthrough output + * aout_spdif.c: A52 passthrough output ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: aout_spdif.c,v 1.29 2002/06/01 12:32:01 sam Exp $ + * $Id: aout_spdif.c,v 1.30 2002/08/04 17:23:44 sam Exp $ * * Authors: Michel Kaempf * Stéphane Borel @@ -83,8 +83,8 @@ void iec958_build_burst( u8 * p_buf, aout_fifo_t * p_fifo ) ***************************************************************************** * This output thread is quite specific as it can only handle one fifo now. * - * Note: spdif can demux up to 8 ac3 streams, and can even take - * care of time stamps (cf ac3 spec) but I'm not sure all decoders + * Note: spdif can demux up to 8 A52 streams, and can even take + * care of time stamps (cf A52 spec) but I'm not sure all decoders * implement it. *****************************************************************************/ void aout_SpdifThread( aout_thread_t * p_aout ) @@ -124,8 +124,8 @@ void aout_SpdifThread( aout_thread_t * p_aout ) (p_aout->fifo[i_fifo].i_start_frame + 1 ) & AOUT_FIFO_SIZE; - /* Compute the theorical duration of an ac3 frame */ - m_frame_time = 1000000 * AC3_FRAME_SIZE + /* Compute the theorical duration of an A52 frame */ + m_frame_time = 1000000 * A52_FRAME_SIZE / p_aout->fifo[i_fifo].i_rate; vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock ); diff --git a/src/audio_output/aout_spdif.h b/src/audio_output/aout_spdif.h index 3cb4ac96b9..ca123a841b 100644 --- a/src/audio_output/aout_spdif.h +++ b/src/audio_output/aout_spdif.h @@ -1,8 +1,8 @@ /***************************************************************************** - * aout_spdif.h: AC3 passthrough output + * aout_spdif.h: A52 passthrough output ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: aout_spdif.h,v 1.1 2002/02/24 22:12:45 sam Exp $ + * $Id: aout_spdif.h,v 1.2 2002/08/04 17:23:44 sam Exp $ * * Authors: Michel Kaempf * Stéphane Borel diff --git a/src/audio_output/audio_output.c b/src/audio_output/audio_output.c index f7ddbabd5e..4312e27c69 100644 --- a/src/audio_output/audio_output.c +++ b/src/audio_output/audio_output.c @@ -2,7 +2,7 @@ * audio_output.c : audio output thread ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN - * $Id: audio_output.c,v 1.87 2002/07/31 20:56:52 sam Exp $ + * $Id: audio_output.c,v 1.88 2002/08/04 17:23:44 sam Exp $ * * Authors: Michel Kaempf * Cyril Deguet @@ -181,9 +181,9 @@ static int aout_SpawnThread( aout_thread_t * p_aout ) i_bytes = 2 * p_aout->i_units * p_aout->i_channels; break; - case AOUT_FMT_AC3: + case AOUT_FMT_A52: pf_aout_thread = aout_SpdifThread; - psz_format = "ac3 pass-through"; + psz_format = "A52 pass-through"; i_bytes = SPDIF_FRAME_SIZE; break; diff --git a/src/input/mpeg_system.c b/src/input/mpeg_system.c index 329b84e9fd..2ac3401b37 100644 --- a/src/input/mpeg_system.c +++ b/src/input/mpeg_system.c @@ -2,7 +2,7 @@ * mpeg_system.c: TS, PS and PES management ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN - * $Id: mpeg_system.c,v 1.100 2002/07/23 00:39:17 sam Exp $ + * $Id: mpeg_system.c,v 1.101 2002/08/04 17:23:44 sam Exp $ * * Authors: Christophe Massiot * Michel Lespinasse @@ -339,7 +339,7 @@ void input_ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ) if( p_es->i_fourcc == VLC_FOURCC('a','5','2',' ') ) { - /* With ac3 audio, we need to skip first 3 bytes */ + /* With A52 audio, we need to skip first 3 bytes */ i_pes_header_size += 3; } @@ -617,7 +617,7 @@ static void DecodePSM( input_thread_t * p_input, data_packet_t * p_data ) p_es->i_fourcc = VLC_FOURCC('m','p','g','a'); p_es->i_cat = AUDIO_ES; break; - case AC3_AUDIO_ES: + case A52_AUDIO_ES: p_es->i_fourcc = VLC_FOURCC('a','5','2',' '); p_es->i_cat = AUDIO_ES; break; @@ -842,7 +842,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, } else if( (i_id & 0xF0FF) == 0x80BD ) { - /* AC3 audio (0x80->0x8F) */ + /* A52 audio (0x80->0x8F) */ p_es->i_fourcc = VLC_FOURCC('a','5','2',' '); p_es->i_cat = AUDIO_ES; #ifdef AUTO_SPAWN @@ -854,7 +854,7 @@ es_descriptor_t * input_ParsePS( input_thread_t * p_input, switch( config_GetInt( p_input, "audio-type" ) ) { case -1: - case REQUESTED_AC3: + case REQUESTED_A52: input_SelectES( p_input, p_es ); } #endif diff --git a/src/libvlc.h b/src/libvlc.h index 4b7ba85d50..bae56bc089 100644 --- a/src/libvlc.h +++ b/src/libvlc.h @@ -2,7 +2,7 @@ * libvlc.h: main libvlc header ***************************************************************************** * Copyright (C) 1998-2002 VideoLAN - * $Id: libvlc.h,v 1.9 2002/07/31 20:56:52 sam Exp $ + * $Id: libvlc.h,v 1.10 2002/08/04 17:23:44 sam Exp $ * * Authors: Vincent Seguin * Samuel Hocevar @@ -89,8 +89,8 @@ "4 -> 8 bits signed\n" \ "5 -> 16 bits unsigned little endian\n" \ "6 -> 16 bits unsigned big endian\n" \ - "7 -> mpeg2 audio (unsupported)\n" \ - "8 -> ac3 pass-through") + "7 -> MPEG2 audio (unsupported)\n" \ + "8 -> A52 pass-through") #define RATE_TEXT N_("audio output frequency (Hz)") #define RATE_LONGTEXT N_( \ @@ -223,10 +223,11 @@ #define CODEC_TEXT N_("choose preferred codec list") #define CODEC_LONGTEXT N_( \ "This allows you to select the order in which vlc will choose its " \ - "codecs. For instance, 'a52,ac3,any' will try the a52 codec before " \ - "the ac3 one. Please be aware that vlc does not make any difference " \ - "between audio or video codecs, so you should always specify 'any' at " \ - "the end of the list to make sure there is a fallback for all types.") + "codecs. For instance, 'a52old,a52,any' will try the old a52 codec " \ + "before the new one. Please be aware that vlc does not make any " \ + "difference between audio or video codecs, so you should always specify " \ + "'any' at the end of the list to make sure there is a fallback for the " \ + "types you didn't specify.") #define MMX_TEXT N_("enable CPU MMX support") #define MMX_LONGTEXT N_( \ diff --git a/src/misc/modules.c b/src/misc/modules.c index 41a6f29bc2..fd08b1056d 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -2,7 +2,7 @@ * modules.c : Builtin and plugin modules management functions ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: modules.c,v 1.76 2002/08/04 12:18:41 sam Exp $ + * $Id: modules.c,v 1.77 2002/08/04 17:23:44 sam Exp $ * * Authors: Samuel Hocevar * Ethan C. Baldridge @@ -569,7 +569,7 @@ void __module_Unneed( vlc_object_t * p_this, module_t * p_module ) static void AllocateAllPlugins( vlc_object_t *p_this ) { /* Yes, there are two NULLs because we replace one with "plugin-path". */ - char * path[] = { "plugins", PLUGIN_PATH, NULL, NULL }; + char * path[] = { "modules", PLUGIN_PATH, NULL, NULL }; char ** ppsz_path = path; char * psz_fullpath;