Mercurial > mplayer.hg
changeset 19271:64d82a45a05d
introduce new 'stream' directory for all stream layer related components and split them from libmpdemux
author | ben |
---|---|
date | Mon, 31 Jul 2006 17:39:17 +0000 |
parents | 7d39b911f0bd |
children | e53b30cd047f |
files | Copyright Gui/mplayer/common.c Gui/mplayer/gtk/fs.c Gui/mplayer/gtk/menu.c Gui/mplayer/mw.c Gui/mplayer/pb.c Gui/mplayer/play.c Gui/win32/dialogs.c Gui/win32/gui.c Gui/win32/interface.c Makefile TOOLS/Makefile TOOLS/netstream/Makefile TOOLS/netstream/netstream.c asxparser.c cfg-common.h libmenu/menu.c libmenu/menu_dvbin.c libmpcodecs/Makefile libmpdemux/Makefile libmpdemux/ai_alsa.c libmpdemux/ai_alsa1x.c libmpdemux/ai_oss.c libmpdemux/asf_mmst_streaming.c libmpdemux/asf_streaming.c libmpdemux/audio_in.c libmpdemux/audio_in.h libmpdemux/cache2.c libmpdemux/cdd.h libmpdemux/cdda.c libmpdemux/cddb.c libmpdemux/cdinfo.c libmpdemux/cookies.c libmpdemux/cookies.h libmpdemux/cue_read.c libmpdemux/cue_read.h libmpdemux/dvb_tune.c libmpdemux/dvbin.c libmpdemux/dvbin.h libmpdemux/dvdnav_stream.c libmpdemux/dvdnav_stream.h libmpdemux/freesdp/common.c libmpdemux/freesdp/common.h libmpdemux/freesdp/errorlist.c libmpdemux/freesdp/parser.c libmpdemux/freesdp/parser.h libmpdemux/freesdp/parserpriv.h libmpdemux/freesdp/priv.h libmpdemux/frequencies.c libmpdemux/frequencies.h libmpdemux/http.c libmpdemux/http.h libmpdemux/librtsp/rtsp.c libmpdemux/librtsp/rtsp.h libmpdemux/librtsp/rtsp_rtp.c libmpdemux/librtsp/rtsp_rtp.h libmpdemux/librtsp/rtsp_session.c libmpdemux/librtsp/rtsp_session.h libmpdemux/mf.c libmpdemux/mf.h libmpdemux/netstream.h libmpdemux/network.c libmpdemux/network.h libmpdemux/open.c libmpdemux/pnm.c libmpdemux/realrtsp/asmrp.c libmpdemux/realrtsp/asmrp.h libmpdemux/realrtsp/real.c libmpdemux/realrtsp/real.h libmpdemux/realrtsp/rmff.c libmpdemux/realrtsp/rmff.h libmpdemux/realrtsp/sdpplin.c libmpdemux/realrtsp/sdpplin.h libmpdemux/realrtsp/xbuffer.c libmpdemux/realrtsp/xbuffer.h libmpdemux/rtp.c libmpdemux/rtp.h libmpdemux/stream.c libmpdemux/stream.h libmpdemux/stream_dvd.c libmpdemux/stream_dvd.h libmpdemux/stream_file.c libmpdemux/stream_ftp.c libmpdemux/stream_livedotcom.c libmpdemux/stream_netstream.c libmpdemux/stream_null.c libmpdemux/stream_pvr.c libmpdemux/stream_rtsp.c libmpdemux/stream_smb.c libmpdemux/stream_vcd.c libmpdemux/stream_vstream.c libmpdemux/tv.c libmpdemux/tv.h libmpdemux/tvi_bsdbt848.c libmpdemux/tvi_def.h libmpdemux/tvi_dummy.c libmpdemux/tvi_v4l.c libmpdemux/tvi_v4l2.c libmpdemux/url.c libmpdemux/url.h libmpdemux/vcd_read.h libmpdemux/vcd_read_darwin.h libmpdemux/vcd_read_fbsd.h libmpdemux/vcd_read_nbsd.h m_option.c mencoder.c mplayer.c osdep/macosx_finder_args.c playtreeparser.c stream/Makefile stream/ai_alsa.c stream/ai_alsa1x.c stream/ai_oss.c stream/asf_mmst_streaming.c stream/asf_streaming.c stream/audio_in.c stream/audio_in.h stream/cache2.c stream/cdd.h stream/cdda.c stream/cddb.c stream/cdinfo.c stream/cookies.c stream/cookies.h stream/cue_read.c stream/cue_read.h stream/dvb_tune.c stream/dvbin.c stream/dvbin.h stream/dvdnav_stream.c stream/dvdnav_stream.h stream/freesdp/common.c stream/freesdp/common.h stream/freesdp/errorlist.c stream/freesdp/parser.c stream/freesdp/parser.h stream/freesdp/parserpriv.h stream/freesdp/priv.h stream/frequencies.c stream/frequencies.h stream/http.c stream/http.h stream/librtsp/rtsp.c stream/librtsp/rtsp.h stream/librtsp/rtsp_rtp.c stream/librtsp/rtsp_rtp.h stream/librtsp/rtsp_session.c stream/librtsp/rtsp_session.h stream/mf.c stream/mf.h stream/netstream.h stream/network.c stream/network.h stream/open.c stream/pnm.c stream/realrtsp/asmrp.c stream/realrtsp/asmrp.h stream/realrtsp/real.c stream/realrtsp/real.h stream/realrtsp/rmff.c stream/realrtsp/rmff.h stream/realrtsp/sdpplin.c stream/realrtsp/sdpplin.h stream/realrtsp/xbuffer.c stream/realrtsp/xbuffer.h stream/rtp.c stream/rtp.h stream/stream.c stream/stream.h stream/stream_dvd.c stream/stream_dvd.h stream/stream_file.c stream/stream_ftp.c stream/stream_livedotcom.c stream/stream_netstream.c stream/stream_null.c stream/stream_pvr.c stream/stream_rtsp.c stream/stream_smb.c stream/stream_vcd.c stream/stream_vstream.c stream/tv.c stream/tv.h stream/tvi_bsdbt848.c stream/tvi_def.h stream/tvi_dummy.c stream/tvi_v4l.c stream/tvi_v4l2.c stream/url.c stream/url.h stream/vcd_read.h stream/vcd_read_darwin.h stream/vcd_read_fbsd.h stream/vcd_read_nbsd.h subreader.c |
diffstat | 195 files changed, 32369 insertions(+), 32315 deletions(-) [+] |
line wrap: on
line diff
--- a/Copyright Mon Jul 31 12:35:04 2006 +0000 +++ b/Copyright Mon Jul 31 17:39:17 2006 +0000 @@ -71,13 +71,13 @@ Name: dvbstream Version: 0.4.3-pre3 (cvs checkout) Homepage: http://www.linuxstb.org/dvbstream/ -Directory: libmpdemux +Directory: stream License: GNU General Public License Name: realrtsp Version: xine CVS 2003/04/17 + patches Homepage: http://www.xinehq.de -Directory: libmpdemux/realrtsp/ +Directory: stream/realrtsp/ License: GNU General Public License Name: id3edit @@ -107,5 +107,5 @@ Name: FreeSDP Version: 0.4.1 Homepage: https://savannah.nongnu.org/projects/freesdp/ -Directory: libmpdemux/freesdp/ +Directory: stream/freesdp/ License: GNU General Public License
--- a/Gui/mplayer/common.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/common.c Mon Jul 31 17:39:17 2006 +0000 @@ -17,7 +17,7 @@ #include "../libvo/x11_common.h" #include "../libvo/fastmemcpy.h" -#include "../libmpdemux/stream.h" +#include "../stream/stream.h" #include "../mixer.h" #include "../libvo/sub.h" #include "../mplayer.h"
--- a/Gui/mplayer/gtk/fs.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/gtk/fs.c Mon Jul 31 17:39:17 2006 +0000 @@ -16,7 +16,7 @@ #include "../interface.h" #include "../../config.h" #include "../../help_mp.h" -#include "../../libmpdemux/stream.h" +#include "../../stream/stream.h" #include "../widgets.h" #include "fs.h"
--- a/Gui/mplayer/gtk/menu.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/gtk/menu.c Mon Jul 31 17:39:17 2006 +0000 @@ -14,7 +14,7 @@ #include "../widgets.h" #include "app.h" -#include "../../libmpdemux/stream.h" +#include "../../stream/stream.h" #include "../../libmpdemux/demuxer.h" #include "../pixmaps/ab.xpm"
--- a/Gui/mplayer/mw.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/mw.c Mon Jul 31 17:39:17 2006 +0000 @@ -17,7 +17,7 @@ #include "../libvo/x11_common.h" #include "../libvo/fastmemcpy.h" -#include "../libmpdemux/stream.h" +#include "../stream/stream.h" #include "../mixer.h" #include "../libvo/sub.h" #include "../mplayer.h"
--- a/Gui/mplayer/pb.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/pb.c Mon Jul 31 17:39:17 2006 +0000 @@ -17,7 +17,7 @@ #include "../libvo/x11_common.h" #include "../libvo/fastmemcpy.h" -#include "../libmpdemux/stream.h" +#include "../stream/stream.h" #include "../mixer.h" #include "../libvo/sub.h" #include "../mplayer.h"
--- a/Gui/mplayer/play.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/mplayer/play.c Mon Jul 31 17:39:17 2006 +0000 @@ -28,7 +28,7 @@ #include "skin/skin.h" #include "skin/font.h" -#include "libmpdemux/stream.h" +#include "stream/stream.h" extern float rel_seek_secs; extern int abs_seek_pos;
--- a/Gui/win32/dialogs.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/win32/dialogs.c Mon Jul 31 17:39:17 2006 +0000 @@ -24,7 +24,7 @@ #include <interface.h> #include <mp_msg.h> #include <help_mp.h> -#include <libmpdemux/stream.h> +#include <stream/stream.h> #include <libmpdemux/demuxer.h> #include <libmpdemux/stheader.h> #include "gui.h"
--- a/Gui/win32/gui.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/win32/gui.c Mon Jul 31 17:39:17 2006 +0000 @@ -34,7 +34,7 @@ #include <input/input.h> #include <input/mouse.h> #include <osdep/keycodes.h> -#include <libmpdemux/stream.h> +#include <stream/stream.h> #include <libvo/video_out.h> #include <interface.h> #include "gui.h"
--- a/Gui/win32/interface.c Mon Jul 31 12:35:04 2006 +0000 +++ b/Gui/win32/interface.c Mon Jul 31 17:39:17 2006 +0000 @@ -26,11 +26,11 @@ #include <mp_msg.h> #include <help_mp.h> #include <codec-cfg.h> -#include <libmpdemux/stream.h> +#include <stream/stream.h> #include <libmpdemux/demuxer.h> #include <libmpdemux/stheader.h> #ifdef USE_DVDREAD -#include <libmpdemux/stream_dvd.h> +#include <stream/stream_dvd.h> #endif #include <input/input.h> #include <libvo/video_out.h>
--- a/Makefile Mon Jul 31 12:35:04 2006 +0000 +++ b/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -105,6 +105,7 @@ $(W32_LIB) \ libaf/libaf.a \ libmpdemux/libmpdemux.a \ + stream/stream.a \ libswscale/libswscale.a \ osdep/libosdep.a \ $(DVDREAD_LIB) \ @@ -139,6 +140,7 @@ endif PARTS = libmpdemux \ + stream \ libmpcodecs \ libavutil \ libavcodec \ @@ -195,6 +197,7 @@ COMMON_DEPS = $(W32_DEP) \ $(AV_DEP) \ libmpdemux/libmpdemux.a \ + stream/stream.a \ libmpcodecs/libmpcodecs.a \ libao2/libao2.a \ osdep/libosdep.a \ @@ -274,6 +277,9 @@ libmpdemux/libmpdemux.a: $(MAKE) -C libmpdemux +stream/stream.a: + $(MAKE) -C stream + libmpcodecs/libmpcodecs.a: $(MAKE) -C libmpcodecs @@ -546,6 +552,7 @@ libmpdvdkit2/libmpdvdkit.a: $(wildcard libmpdvdkit2/*.[ch]) libmpdemux/libmpdemux.a: $(wildcard libmpdemux/*.[ch] libmpdemux/*/*.[ch]) +stream/stream.a: $(wildcard stream/*.[ch] stream/*/*.[ch]) libmpcodecs/libmpcodecs.a: $(wildcard libmpcodecs/*.[ch]) $(wildcard libmpcodecs/native/*.[ch]) libmpcodecs/libmpencoders.a: $(wildcard libmpcodecs/*.[ch])
--- a/TOOLS/Makefile Mon Jul 31 12:35:04 2006 +0000 +++ b/TOOLS/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -31,7 +31,7 @@ ../libswscale/yuv2rgb.o ../libmpcodecs/img_format.o -lm vivodump: vivodump.c - $(CC) $(CFLAGS) -o $@ $< ../mp_msg.o ../libmpdemux/libmpdemux.a + $(CC) $(CFLAGS) -o $@ $< ../mp_msg.o ../libmpdemux/libmpdemux.a ../stream/stream.a fastmemcpybench: fastmemcpybench.c $(CC) $(CFLAGS) -g $< -o fastmem-mmx ../libvo/aclib.o -DNAME=\"mmx\" -DHAVE_MMX
--- a/TOOLS/netstream/Makefile Mon Jul 31 12:35:04 2006 +0000 +++ b/TOOLS/netstream/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -19,6 +19,7 @@ # FIXME: linking is a mess that should be fixed properly some day # it does not work with either GUI, live.com or libavformat enabled DEPS = $(MPROOT)/libmpdemux/libmpdemux.a \ + $(MPROOT)/stream/stream.a \ $(MPROOT)/libmpdvdkit2/libmpdvdkit.a \ $(MPROOT)/libmpcodecs/native/minilzo.o \ $(MPROOT)/libvo/aclib.o \ @@ -45,7 +46,7 @@ DEPS += $(MPROOT)/osdep/glob-win.o $(WIN32_LIB) -lwsock32 endif -netstream: $(MPROOT)/libmpdemux/libmpdemux.a netstream.o +netstream: $(MPROOT)/libmpdemux/libmpdemux.a $(MPROOT)/libmpdemux/stream.a netstream.o $(CC) $(CFLAGS) netstream.o -o netstream $(DEPS)
--- a/TOOLS/netstream/netstream.c Mon Jul 31 12:35:04 2006 +0000 +++ b/TOOLS/netstream/netstream.c Mon Jul 31 17:39:17 2006 +0000 @@ -41,13 +41,13 @@ #include <ws2tcpip.h> #endif -#include <libmpdemux/stream.h> +#include <stream/stream.h> #include <libmpdemux/demuxer.h> #include <mp_msg.h> #include <bswap.h> /// Netstream packets def and some helpers -#include <libmpdemux/netstream.h> +#include <stream/netstream.h> //Set some standard variables
--- a/asxparser.c Mon Jul 31 12:35:04 2006 +0000 +++ b/asxparser.c Mon Jul 31 17:39:17 2006 +0000 @@ -8,7 +8,7 @@ #include "playtree.h" #include "playtreeparser.h" -#include "libmpdemux/stream.h" +#include "stream/stream.h" #include "libmpdemux/demuxer.h" #include "asxparser.h" #include "mp_msg.h"
--- a/cfg-common.h Mon Jul 31 12:35:04 2006 +0000 +++ b/cfg-common.h Mon Jul 31 17:39:17 2006 +0000 @@ -366,7 +366,7 @@ extern int ts_keep_broken; extern off_t ts_probe; -#include "libmpdemux/tv.h" +#include "stream/tv.h" extern char* edl_filename; extern char* edl_output_filename; @@ -444,7 +444,7 @@ #endif #ifdef HAS_DVBIN_SUPPORT -#include "libmpdemux/dvbin.h" +#include "stream/dvbin.h" extern m_config_t dvbin_opts_conf[]; #endif
--- a/libmenu/menu.c Mon Jul 31 12:35:04 2006 +0000 +++ b/libmenu/menu.c Mon Jul 31 17:39:17 2006 +0000 @@ -13,7 +13,7 @@ #include "libvo/font_load.h" #include "osdep/keycodes.h" #include "asxparser.h" -#include "libmpdemux/stream.h" +#include "stream/stream.h" #include "img_format.h" #include "mp_image.h"
--- a/libmenu/menu_dvbin.c Mon Jul 31 12:35:04 2006 +0000 +++ b/libmenu/menu_dvbin.c Mon Jul 31 17:39:17 2006 +0000 @@ -24,7 +24,7 @@ #include "input/input.h" #include "osdep/keycodes.h" -#include "libmpdemux/dvbin.h" +#include "stream/dvbin.h"
--- a/libmpcodecs/Makefile Mon Jul 31 12:35:04 2006 +0000 +++ b/libmpcodecs/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -321,6 +321,7 @@ -I. -I.. \ -Inative \ -I../libmpdemux \ + -I../stream \ -I../loader \ $(LIBAV_INC) \ -D_GNU_SOURCE \
--- a/libmpdemux/Makefile Mon Jul 31 12:35:04 2006 +0000 +++ b/libmpdemux/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -12,89 +12,15 @@ # Core SRCS += extension.c \ - mf.c \ - open.c \ - url.c \ video.c \ -ifeq ($(STREAM_CACHE),yes) -SRCS += cache2.c -endif - # Miscellaneous -SRCS += cdinfo.c \ - cue_read.c \ - parse_es.c \ +SRCS += parse_es.c \ parse_mp4.c \ mpeg_packetizer.c \ yuv4mpeg.c \ yuv4mpeg_ratio.c \ -ifeq ($(CDDA),yes) -SRCS += cdda.c - ifeq ($(MPLAYER_NETWORK),yes) - SRCS += cddb.c - endif -endif - -# Stream readers/writers -SRCS += stream.c \ - stream_file.c \ - stream_null.c \ - -ifeq ($(HAVE_DVD),yes) -SRCS += stream_dvd.c -endif -ifeq ($(DVDNAV),yes) -SRCS += dvdnav_stream.c -endif -ifeq ($(VCD),yes) -SRCS += stream_vcd.c -endif -ifeq ($(FTP),yes) -SRCS += stream_ftp.c -endif -ifeq ($(LIBSMBCLIENT),yes) -SRCS += stream_smb.c -endif -ifeq ($(MPLAYER_NETWORK),yes) - SRCS += stream_netstream.c - ifeq ($(STREAMING_LIVE555),yes) - SRCS += stream_livedotcom.c - endif -endif -ifeq ($(VSTREAM),yes) -SRCS += stream_vstream.c -endif - -# TV in -ifeq ($(TV),yes) -SRCS += tv.c frequencies.c tvi_dummy.c - ifeq ($(TV_BSDBT848),yes) - SRCS += tvi_bsdbt848.c - endif - ifeq ($(TV_V4L2),yes) - SRCS += tvi_v4l2.c audio_in.c - ifeq ($(PVR),yes) - SRCS += stream_pvr.c - endif - endif - ifeq ($(TV_V4L1),yes) - SRCS += tvi_v4l.c audio_in.c - endif - ifeq ($(TV_V4L),yes) - ifeq ($(ALSA1X),yes) - SRCS += ai_alsa1x.c - endif - ifeq ($(ALSA9),yes) - SRCS += ai_alsa.c - endif - ifeq ($(OSS),yes) - SRCS += ai_oss.c - endif - endif -endif - # Demuxers SRCS += demuxer.c \ demux_aac.c \ @@ -166,48 +92,18 @@ MUXERS += muxer_lavf.c endif -ifeq ($(MPLAYER_NETWORK),yes) -SRCS += asf_streaming.c \ - http.c \ - network.c \ - cookies.c \ - asf_mmst_streaming.c \ - pnm.c \ - rtp.c \ - stream_rtsp.c \ - -SRCS += realrtsp/asmrp.c \ - realrtsp/real.c \ - realrtsp/rmff.c \ - realrtsp/sdpplin.c \ - realrtsp/xbuffer.c \ - -SRCS += librtsp/rtsp.c \ - librtsp/rtsp_rtp.c \ - librtsp/rtsp_session.c \ - -SRCS += freesdp/common.c \ - freesdp/errorlist.c \ - freesdp/parser.c \ +ifeq ($(MENCODER),yes) +SRCS += $(MUXERS) +endif ifeq ($(STREAMING_LIVE555),yes) CPLUSPLUSSRCS = demux_rtp.cpp demux_rtp_codec.cpp CPLUSPLUSINCLUDE = $(LIVE_INCLUDES) endif -endif - -ifeq ($(DVBIN),yes) -SRCS += dvbin.c -SRCS += dvb_tune.c -endif - -ifeq ($(MENCODER),yes) -SRCS += $(MUXERS) -endif OBJS = $(SRCS:.c=.o) OBJS += $(CPLUSPLUSSRCS:.cpp=.o) -INCLUDE = -I.. -I../loader $(LIBAV_INC) +INCLUDE = -I.. -I../stream -I../loader $(LIBAV_INC) CFLAGS = $(OPTFLAGS) $(INCLUDE) $(XMMS_CFLAGS) CPLUSPLUSFLAGS = $(CFLAGS) $(CPLUSPLUSINCLUDE) -D__STDC_LIMIT_MACROS CPLUSPLUS = $(CC) @@ -229,16 +125,14 @@ test: $(LIBNAME) test.c $(CC) $(CFLAGS) test.c ../mp_msg.c ../osdep/shmem.c -o test \ - ./libmpdemux.a ../libmpdvdkit2/libmpdvdkit.a ../libvo/aclib.o \ + ./libmpdemux.a ../stream/stream.a \ + ../libmpdvdkit2/libmpdvdkit.a ../libvo/aclib.o \ ../libmpcodecs/img_format.o ../libao2/afmt.o ../sub_cc.o \ ../m_option.o ../subreader.o \ $(ALSA_LIB) $(VORBIS_LIB) $(CDPARANOIA_LIB) -lz -lpthread clean: - rm -f *.o *.a *~ \ - realrtsp/*.o realrtsp/*.a realrtsp/*~ \ - librtsp/*.o librtsp/*.a librtsp/*~ \ - freesdp/*.o freesdp/*.a freesdp/*~ + rm -f *.o *.a *~ distclean: clean rm -f .depend test
--- a/libmpdemux/ai_alsa.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <sys/time.h> - -#include "config.h" - -#include <alsa/asoundlib.h> -#include "audio_in.h" -#include "mp_msg.h" -#include "help_mp.h" - -int ai_alsa_setup(audio_in_t *ai) -{ - snd_pcm_hw_params_t *params; - snd_pcm_sw_params_t *swparams; - int buffer_size; - int err; - unsigned int rate; - - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_sw_params_alloca(&swparams); - - err = snd_pcm_hw_params_any(ai->alsa.handle, params); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); - return -1; - } - err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); - return -1; - } - err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); - return -1; - } - err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); - if (err < 0) { - ai->channels = snd_pcm_hw_params_get_channels(params); - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, - ai->channels); - } else { - ai->channels = ai->req_channels; - } - - err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0); - assert(err >= 0); - rate = err; - ai->samplerate = rate; - - ai->alsa.buffer_time = 1000000; - ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, - ai->alsa.buffer_time, 0); - assert(ai->alsa.buffer_time >= 0); - ai->alsa.period_time = ai->alsa.buffer_time / 4; - ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, - ai->alsa.period_time, 0); - assert(ai->alsa.period_time >= 0); - err = snd_pcm_hw_params(ai->alsa.handle, params); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams); - snd_pcm_hw_params_dump(params, ai->alsa.log); - return -1; - } - ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0); - buffer_size = snd_pcm_hw_params_get_buffer_size(params); - if (ai->alsa.chunk_size == buffer_size) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); - return -1; - } - snd_pcm_sw_params_current(ai->alsa.handle, swparams); - err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); - assert(err >= 0); - err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); - assert(err >= 0); - - err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); - assert(err >= 0); - err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); - assert(err >= 0); - - assert(err >= 0); - if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); - snd_pcm_sw_params_dump(swparams, ai->alsa.log); - return -1; - } - - if (mp_msg_test(MSGT_TV, MSGL_V)) { - snd_pcm_dump(ai->alsa.handle, ai->alsa.log); - } - - ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); - ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; - ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; - ai->samplesize = ai->alsa.bits_per_sample; - ai->bytes_per_sample = ai->alsa.bits_per_sample/8; - - return 0; -} - -int ai_alsa_init(audio_in_t *ai) -{ - int err; - - err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err)); - return -1; - } - - err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0); - - if (err < 0) { - return -1; - } - - err = ai_alsa_setup(ai); - - return err; -} - -#ifndef timersub -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif - -int ai_alsa_xrun(audio_in_t *ai) -{ - snd_pcm_status_t *status; - int res; - - snd_pcm_status_alloca(&status); - if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res)); - return -1; - } - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { - struct timeval now, diff, tstamp; - gettimeofday(&now, 0); - snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN, - diff.tv_sec * 1000 + diff.tv_usec / 1000.0); - if (mp_msg_test(MSGT_TV, MSGL_V)) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus); - snd_pcm_status_dump(status, ai->alsa.log); - } - if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res)); - return -1; - } - return 0; /* ok, data should be accepted again */ - } - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError); - return -1; -}
--- a/libmpdemux/ai_alsa1x.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <sys/time.h> - -#include "config.h" - -#include <alsa/asoundlib.h> -#include "audio_in.h" -#include "mp_msg.h" -#include "help_mp.h" - -int ai_alsa_setup(audio_in_t *ai) -{ - snd_pcm_hw_params_t *params; - snd_pcm_sw_params_t *swparams; - snd_pcm_uframes_t buffer_size, period_size; - int err; - int dir; - unsigned int rate; - - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_sw_params_alloca(&swparams); - - err = snd_pcm_hw_params_any(ai->alsa.handle, params); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); - return -1; - } - - err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, - SND_PCM_ACCESS_RW_INTERLEAVED); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); - return -1; - } - - err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); - return -1; - } - - err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); - if (err < 0) { - snd_pcm_hw_params_get_channels(params, &ai->channels); - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, - ai->channels); - } else { - ai->channels = ai->req_channels; - } - - dir = 0; - rate = ai->req_samplerate; - err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetSamplerate); - } - ai->samplerate = rate; - - dir = 0; - ai->alsa.buffer_time = 1000000; - err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, - &ai->alsa.buffer_time, &dir); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetBufferTime); - } - - dir = 0; - ai->alsa.period_time = ai->alsa.buffer_time / 4; - err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, - &ai->alsa.period_time, &dir); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetPeriodTime); - } - - err = snd_pcm_hw_params(ai->alsa.handle, params); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams, snd_strerror(err)); - snd_pcm_hw_params_dump(params, ai->alsa.log); - return -1; - } - - dir = -1; - snd_pcm_hw_params_get_period_size(params, &period_size, &dir); - snd_pcm_hw_params_get_buffer_size(params, &buffer_size); - ai->alsa.chunk_size = period_size; - if (period_size == buffer_size) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); - return -1; - } - - snd_pcm_sw_params_current(ai->alsa.handle, swparams); - err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); - assert(err >= 0); - err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); - assert(err >= 0); - - err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); - assert(err >= 0); - err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); - assert(err >= 0); - - assert(err >= 0); - if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); - snd_pcm_sw_params_dump(swparams, ai->alsa.log); - return -1; - } - - if (mp_msg_test(MSGT_TV, MSGL_V)) { - snd_pcm_dump(ai->alsa.handle, ai->alsa.log); - } - - ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); - ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; - ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; - ai->samplesize = ai->alsa.bits_per_sample; - ai->bytes_per_sample = ai->alsa.bits_per_sample/8; - - return 0; -} - -int ai_alsa_init(audio_in_t *ai) -{ - int err; - - err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err)); - return -1; - } - - err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0); - - if (err < 0) { - return -1; - } - - err = ai_alsa_setup(ai); - - return err; -} - -#ifndef timersub -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif - -int ai_alsa_xrun(audio_in_t *ai) -{ - snd_pcm_status_t *status; - int res; - - snd_pcm_status_alloca(&status); - if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res)); - return -1; - } - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { - struct timeval now, diff, tstamp; - gettimeofday(&now, 0); - snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN, - diff.tv_sec * 1000 + diff.tv_usec / 1000.0); - if (mp_msg_test(MSGT_TV, MSGL_V)) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus); - snd_pcm_status_dump(status, ai->alsa.log); - } - if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res)); - return -1; - } - return 0; /* ok, data should be accepted again */ - } - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError); - return -1; -}
--- a/libmpdemux/ai_oss.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> - -#include "config.h" - -#include <string.h> /* strerror */ -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> - -#ifdef HAVE_SYS_SOUNDCARD_H -#include <sys/soundcard.h> -#else -#ifdef HAVE_SOUNDCARD_H -#include <soundcard.h> -#else -#include <linux/soundcard.h> -#endif -#endif - -#include "audio_in.h" -#include "mp_msg.h" -#include "help_mp.h" - -int ai_oss_set_samplerate(audio_in_t *ai) -{ - int tmp = ai->req_samplerate; - if (ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &tmp) == -1) return -1; - ai->samplerate = tmp; - return 0; -} - -int ai_oss_set_channels(audio_in_t *ai) -{ - int err; - int ioctl_param; - - if (ai->req_channels > 2) - { - ioctl_param = ai->req_channels; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp channels: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_CHANNELS, &ioctl_param)); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetChanCount, - ai->req_channels); - return -1; - } - ai->channels = ioctl_param; - } - else - { - ioctl_param = (ai->req_channels == 2); - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp stereo: %d (req: %d)\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_STEREO, &ioctl_param), - ioctl_param); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetStereo, - ai->req_channels == 2); - return -1; - } - ai->channels = ioctl_param ? 2 : 1; - } - return 0; -} - -int ai_oss_init(audio_in_t *ai) -{ - int err; - int ioctl_param; - - ai->oss.audio_fd = open(ai->oss.device, O_RDONLY); - if (ai->oss.audio_fd < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2Open, - ai->oss.device, strerror(errno)); - return -1; - } - - ioctl_param = 0 ; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp getfmt: %d\n", - ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETFMTS, &ioctl_param)); - - mp_msg(MSGT_TV, MSGL_V, "Supported formats: %x\n", ioctl_param); - if (!(ioctl_param & AFMT_S16_LE)) - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_UnsupportedFmt); - - ioctl_param = AFMT_S16_LE; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp setfmt: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETFMT, &ioctl_param)); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetAudioFmt); - return -1; - } - - if (ai_oss_set_channels(ai) < 0) return -1; - - ioctl_param = ai->req_samplerate; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp speed: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &ioctl_param)); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetSamplerate, - ai->req_samplerate); - return -1; - } - ai->samplerate = ioctl_param; - - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp trigger: %d\n", - ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETTRIGGER, &ioctl_param)); - mp_msg(MSGT_TV, MSGL_V, "trigger: %x\n", ioctl_param); - ioctl_param = PCM_ENABLE_INPUT; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp trigger: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETTRIGGER, &ioctl_param)); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetTrigger, - PCM_ENABLE_INPUT); - } - - ai->blocksize = 0; - mp_msg(MSGT_TV, MSGL_V, "ioctl dsp getblocksize: %d\n", - err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETBLKSIZE, &ai->blocksize)); - if (err < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2GetBlockSize); - } - mp_msg(MSGT_TV, MSGL_V, "blocksize: %d\n", ai->blocksize); - - // correct the blocksize to a reasonable value - if (ai->blocksize <= 0) { - ai->blocksize = 4096*ai->channels*2; - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_AudioBlockSizeZero, ai->blocksize); - } else if (ai->blocksize < 4096*ai->channels*2) { - ai->blocksize *= 4096*ai->channels*2/ai->blocksize; - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_AudioBlockSize2Low, ai->blocksize); - } - - ai->samplesize = 16; - ai->bytes_per_sample = 2; - - return 0; -}
--- a/libmpdemux/asf_mmst_streaming.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,665 +0,0 @@ -// mmst implementation taken from the xine-mms plugin made by majormms (http://geocities.com/majormms/) -// -// ported to mplayer by Abhijeet Phatak <abhijeetphatak@yahoo.com> -// date : 16 April 2002 -// -// information about the mms protocol can be find at http://get.to/sdp -// - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <inttypes.h> - -#include "config.h" - -#include "mp_msg.h" -#include "help_mp.h" - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#else -#include <winsock2.h> -#endif - -#ifndef USE_SETLOCALE -#undef USE_ICONV -#endif - -#ifdef USE_ICONV -#include <iconv.h> -#ifdef USE_LANGINFO -#include <langinfo.h> -#endif -#endif - -#include "url.h" -#include "asf.h" - -#include "stream.h" - -#include "network.h" - -#define BUF_SIZE 102400 -#define HDR_BUF_SIZE 8192 -#define MAX_STREAMS 20 - -typedef struct -{ - uint8_t buf[BUF_SIZE]; - int num_bytes; - -} command_t; - -static int seq_num; -static int num_stream_ids; -static int stream_ids[MAX_STREAMS]; - -static int get_data (int s, char *buf, size_t count); - -static void put_32 (command_t *cmd, uint32_t value) -{ - cmd->buf[cmd->num_bytes ] = value % 256; - value = value >> 8; - cmd->buf[cmd->num_bytes+1] = value % 256 ; - value = value >> 8; - cmd->buf[cmd->num_bytes+2] = value % 256 ; - value = value >> 8; - cmd->buf[cmd->num_bytes+3] = value % 256 ; - - cmd->num_bytes += 4; -} - -static uint32_t get_32 (unsigned char *cmd, int offset) -{ - uint32_t ret; - - ret = cmd[offset] ; - ret |= cmd[offset+1]<<8 ; - ret |= cmd[offset+2]<<16 ; - ret |= cmd[offset+3]<<24 ; - - return ret; -} - -static void send_command (int s, int command, uint32_t switches, - uint32_t extra, int length, - char *data) -{ - command_t cmd; - int len8; - - len8 = (length + 7) / 8; - - cmd.num_bytes = 0; - - put_32 (&cmd, 0x00000001); /* start sequence */ - put_32 (&cmd, 0xB00BFACE); /* #-)) */ - put_32 (&cmd, len8*8 + 32); - put_32 (&cmd, 0x20534d4d); /* protocol type "MMS " */ - put_32 (&cmd, len8 + 4); - put_32 (&cmd, seq_num); - seq_num++; - put_32 (&cmd, 0x0); /* unknown */ - put_32 (&cmd, 0x0); - put_32 (&cmd, len8+2); - put_32 (&cmd, 0x00030000 | command); /* dir | command */ - put_32 (&cmd, switches); - put_32 (&cmd, extra); - - memcpy (&cmd.buf[48], data, length); - if (length & 7) - memset(&cmd.buf[48 + length], 0, 8 - (length & 7)); - - if (send (s, cmd.buf, len8*8+48, 0) != (len8*8+48)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_WriteError); - } -} - -#ifdef USE_ICONV -static iconv_t url_conv; -#endif - -static void string_utf16(char *dest, char *src, int len) { - int i; -#ifdef USE_ICONV - size_t len1, len2; - char *ip, *op; - - if (url_conv != (iconv_t)(-1)) - { - memset(dest, 0, 1000); - len1 = len; len2 = 1000; - ip = src; op = dest; - - iconv(url_conv, &ip, &len1, &op, &len2); - } - else - { -#endif - if (len > 499) len = 499; - for (i=0; i<len; i++) { - dest[i*2] = src[i]; - dest[i*2+1] = 0; - } - /* trailing zeroes */ - dest[i*2] = 0; - dest[i*2+1] = 0; -#ifdef USE_ICONV - } -#endif -} - -static void get_answer (int s) -{ - char data[BUF_SIZE]; - int command = 0x1b; - - while (command == 0x1b) { - int len; - - len = recv (s, data, BUF_SIZE, 0) ; - if (!len) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_EOFAlert); - return; - } - - command = get_32 (data, 36) & 0xFFFF; - - if (command == 0x1b) - send_command (s, 0x1b, 0, 0, 0, data); - } -} - -static int get_data (int s, char *buf, size_t count) -{ - ssize_t len; - size_t total = 0; - - while (total < count) { - - len = recv (s, &buf[total], count-total, 0); - - if (len<=0) { - perror ("read error:"); - return 0; - } - - total += len; - - if (len != 0) { -// mp_msg(MSGT_NETWORK,MSGL_INFO,"[%d/%d]", total, count); - fflush (stdout); - } - - } - - return 1; - -} - -static int get_header (int s, uint8_t *header, streaming_ctrl_t *streaming_ctrl) -{ - unsigned char pre_header[8]; - int header_len; - - header_len = 0; - - while (1) { - if (!get_data (s, pre_header, 8)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed); - return 0; - } - if (pre_header[4] == 0x02) { - - int packet_len; - - packet_len = (pre_header[7] << 8 | pre_header[6]) - 8; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf header packet detected, len=%d\n", packet_len); - - if (packet_len < 0 || packet_len > HDR_BUF_SIZE - header_len) { - mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidHeaderSize); - return 0; - } - - if (!get_data (s, &header[header_len], packet_len)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_HeaderDataReadFailed); - return 0; - } - - header_len += packet_len; - - if ( (header[header_len-1] == 1) && (header[header_len-2]==1)) { - - - if( streaming_bufferize( streaming_ctrl, header, header_len )<0 ) { - return -1; - } - - // mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet finished\n"); - - return (header_len); - - } - - } else { - - int32_t packet_len; - int command; - char data[BUF_SIZE]; - - if (!get_data (s, (char*)&packet_len, 4)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed); - return 0; - } - - packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"command packet detected, len=%d\n", packet_len); - - if (packet_len < 0 || packet_len > BUF_SIZE) { - mp_msg(MSGT_NETWORK, MSGL_FATAL, - MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); - return 0; - } - - if (!get_data (s, data, packet_len)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed); - return 0; - } - - command = get_32 (data, 24) & 0xFFFF; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"command: %02x\n", command); - - if (command == 0x1b) - send_command (s, 0x1b, 0, 0, 0, data); - - } - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet succ\n"); - } -} - -static int interp_header (uint8_t *header, int header_len) -{ - int i; - int packet_length=-1; - - /* - * parse header - */ - - i = 30; - while (i<header_len) { - - uint64_t guid_1, guid_2, length; - - guid_2 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) - | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) - | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) - | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); - i += 8; - - guid_1 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) - | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) - | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) - | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); - i += 8; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"guid found: %016llx%016llx\n", guid_1, guid_2); - - length = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) - | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) - | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) - | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); - - i += 8; - - if ( (guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22630ULL) ) { - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_HeaderObject); - } else if ((guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22636ULL)) { - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_DataObject); - } else if ((guid_1 == 0x6553200cc000e48eULL) && (guid_2 == 0x11cfa9478cabdca1ULL)) { - - packet_length = get_32(header, i+92-24); - - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_FileObjectPacketLen, - packet_length, get_32(header, i+96-24)); - - - } else if ((guid_1 == 0x6553200cc000e68eULL) && (guid_2 == 0x11cfa9b7b7dc0791ULL)) { - - int stream_id = header[i+48] | header[i+49] << 8; - - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_StreamObjectStreamID, stream_id); - - if (num_stream_ids < MAX_STREAMS) { - stream_ids[num_stream_ids] = stream_id; - num_stream_ids++; - } else { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_2ManyStreamID); - } - - } else { -#if 0 - int b = i; - printf ("unknown object (guid: %016llx, %016llx, len: %lld)\n", guid_1, guid_2, length); - for (; b < length; b++) - { - if (isascii(header[b]) || isalpha(header[b])) - printf("%c ", header[b]); - else - printf("%x ", header[b]); - } - printf("\n"); -#else - mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_MMST_UnknownObject); -#endif - } - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"length : %lld\n", length); - - i += length-24; - - } - - return packet_length; - -} - - -static int get_media_packet (int s, int padding, streaming_ctrl_t *stream_ctrl) { - unsigned char pre_header[8]; - char data[BUF_SIZE]; - - if (!get_data (s, pre_header, 8)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed); - return 0; - } - -// for (i=0; i<8; i++) -// mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n", -// i, pre_header[i], pre_header[i]); - - if (pre_header[4] == 0x04) { - - int packet_len; - - packet_len = (pre_header[7] << 8 | pre_header[6]) - 8; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len); - - if (packet_len < 0 || packet_len > BUF_SIZE) { - mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); - return 0; - } - - if (!get_data (s, data, packet_len)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MediaDataReadFailed); - return 0; - } - - streaming_bufferize(stream_ctrl, data, padding); - - } else { - - int32_t packet_len; - int command; - - if (!get_data (s, (char*)&packet_len, 4)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed); - return 0; - } - - packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4; - - if (packet_len < 0 || packet_len > BUF_SIZE) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); - return 0; - } - - if (!get_data (s, data, packet_len)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed); - return 0; - } - - if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b) - || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) { - - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MissingSignature); - return -1; - } - - command = get_32 (data, 24) & 0xFFFF; - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"\ncommand packet detected, len=%d cmd=0x%X\n", packet_len, command); - - if (command == 0x1b) - send_command (s, 0x1b, 0, 0, 0, data); - else if (command == 0x1e) { - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_PatentedTechnologyJoke); - return 0; - } - else if (command == 0x21 ) { - // Looks like it's new in WMS9 - // Unknown command, but ignoring it seems to work. - return 0; - } - else if (command != 0x05) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_UnknownCmd,command); - return -1; - } - } - -// mp_msg(MSGT_NETWORK,MSGL_INFO,"get media packet succ\n"); - - return 1; -} - - -static int packet_length1; - -static int asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) -{ - int len; - - while( stream_ctrl->buffer_size==0 ) { - // buffer is empty - fill it! - int ret = get_media_packet( fd, packet_length1, stream_ctrl); - if( ret<0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_GetMediaPacketErr,strerror(errno)); - return -1; - } else if (ret==0) //EOF? - return ret; - } - - len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos; - if(len>size) len=size; - memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len ); - stream_ctrl->buffer_pos += len; - if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) { - free( stream_ctrl->buffer ); - stream_ctrl->buffer = NULL; - stream_ctrl->buffer_size = 0; - stream_ctrl->buffer_pos = 0; - } - return len; - -} - -static int asf_mmst_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl ) -{ - return -1; - // Shut up gcc warning - fd++; - pos++; - streaming_ctrl=NULL; -} - -int asf_mmst_streaming_start(stream_t *stream) -{ - char str[1024]; - char data[BUF_SIZE]; - uint8_t asf_header[HDR_BUF_SIZE]; - int asf_header_len; - int len, i, packet_length; - char *path, *unescpath; - URL_t *url1 = stream->streaming_ctrl->url; - int s = stream->fd; - - if( s>0 ) { - closesocket( stream->fd ); - stream->fd = -1; - } - - /* parse url */ - path = strchr(url1->file,'/') + 1; - - /* mmst filename are not url_escaped by MS MediaPlayer and are expected as - * "plain text" by the server, so need to decode it here - */ - unescpath=malloc(strlen(path)+1); - if (!unescpath) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return -1; - } - url_unescape_string(unescpath,path); - path=unescpath; - - - if( url1->port==0 ) { - url1->port=1755; - } - s = connect2Server( url1->hostname, url1->port, 1); - if( s<0 ) { - free(path); - return s; - } - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_Connected); - - seq_num=0; - - /* - * Send the initial connect info including player version no. Client GUID (random) and the host address being connected to. - * This command is sent at the very start of protocol initiation. It sends local information to the serve - * cmd 1 0x01 - * */ - - /* prepare for the url encoding conversion */ -#ifdef USE_ICONV -#ifdef USE_LANGINFO - url_conv = iconv_open("UTF-16LE",nl_langinfo(CODESET)); -#else - url_conv = iconv_open("UTF-16LE", NULL); -#endif -#endif - - snprintf (str, 1023, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", url1->hostname); - string_utf16 (data, str, strlen(str)); -// send_command(s, commandno ....) - send_command (s, 1, 0, 0x0004000b, strlen(str)*2+2, data); - - len = recv (s, data, BUF_SIZE, 0) ; - - /*This sends details of the local machine IP address to a Funnel system at the server. - * Also, the TCP or UDP transport selection is sent. - * - * here 192.168.0.1 is local ip address TCP/UDP states the tronsport we r using - * and 1037 is the local TCP or UDP socket number - * cmd 2 0x02 - * */ - - string_utf16 (&data[8], "\002\000\\\\192.168.0.1\\TCP\\1037", 24); - memset (data, 0, 8); - send_command (s, 2, 0, 0, 24*2+10, data); - - len = recv (s, data, BUF_SIZE, 0) ; - - /* This command sends file path (at server) and file name request to the server. - * 0x5 */ - - string_utf16 (&data[8], path, strlen(path)); - memset (data, 0, 8); - send_command (s, 5, 0, 0, strlen(path)*2+10, data); - free(path); - - get_answer (s); - - /* The ASF header chunk request. Includes ?session' variable for pre header value. - * After this command is sent, - * the server replies with 0x11 command and then the header chunk with header data follows. - * 0x15 */ - - memset (data, 0, 40); - data[32] = 2; - - send_command (s, 0x15, 1, 0, 40, data); - - num_stream_ids = 0; - /* get_headers(s, asf_header); */ - - asf_header_len = get_header (s, asf_header, stream->streaming_ctrl); -// mp_msg(MSGT_NETWORK,MSGL_INFO,"---------------------------------- asf_header %d\n",asf_header); - if (asf_header_len==0) return -1; //error reading header - packet_length = interp_header (asf_header, asf_header_len); - - - /* - * This command is the media stream MBR selector. Switches are always 6 bytes in length. - * After all switch elements, data ends with bytes [00 00] 00 20 ac 40 [02]. - * Where: - * [00 00] shows 0x61 0x00 (on the first 33 sent) or 0xff 0xff for ASF files, and with no ending data for WMV files. - * It is not yet understood what all this means. - * And the last [02] byte is probably the header ?session' value. - * - * 0x33 */ - - memset (data, 0, 40); - - for (i=1; i<num_stream_ids; i++) { - data [ (i-1) * 6 + 2 ] = 0xFF; - data [ (i-1) * 6 + 3 ] = 0xFF; - data [ (i-1) * 6 + 4 ] = stream_ids[i]; - data [ (i-1) * 6 + 5 ] = 0x00; - } - - send_command (s, 0x33, num_stream_ids, 0xFFFF | stream_ids[0] << 16, (num_stream_ids-1)*6+2 , data); - - get_answer (s); - - /* Start sending file from packet xx. - * This command is also used for resume downloads or requesting a lost packet. - * Also used for seeking by sending a play point value which seeks to the media time point. - * Includes ?session' value in pre header and the maximum media stream time. - * 0x07 */ - - memset (data, 0, 40); - - for (i=8; i<16; i++) - data[i] = 0xFF; - - data[20] = 0x04; - - send_command (s, 0x07, 1, 0xFFFF | stream_ids[0] << 16, 24, data); - - stream->fd = s; - stream->streaming_ctrl->streaming_read = asf_mmst_streaming_read; - stream->streaming_ctrl->streaming_seek = asf_mmst_streaming_seek; - stream->streaming_ctrl->buffering = 1; - stream->streaming_ctrl->status = streaming_playing_e; - - packet_length1 = packet_length; - mp_msg(MSGT_NETWORK,MSGL_INFO,"mmst packet_length = %d\n", packet_length); - -#ifdef USE_ICONV - if (url_conv != (iconv_t)(-1)) - iconv_close(url_conv); -#endif - - return 0; -}
--- a/libmpdemux/asf_streaming.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,882 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> - -#include "config.h" -#include "mp_msg.h" -#include "help_mp.h" - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#else -#include <winsock2.h> -#endif - -#include "url.h" -#include "http.h" -#include "asf.h" - -#include "stream.h" -#include "demuxer.h" - -#include "network.h" - -#ifdef ARCH_X86 -#define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid)) -#else -#define ASF_LOAD_GUID_PREFIX(guid) \ - ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0]) -#endif - -extern int network_bandwidth; - -int asf_mmst_streaming_start( stream_t *stream ); -static int asf_http_streaming_start(stream_t *stream, int *demuxer_type); - -// We can try several protocol for asf streaming -// * first the UDP protcol, if there is a firewall, UDP -// packets will not come back, so the mmsu will fail. -// * Then we can try TCP, but if there is a proxy for -// internet connection, the TCP connection will not get -// through -// * Then we can try HTTP. -// -// Note: Using WMP sequence MMSU then MMST and then HTTP. - -static int asf_streaming_start( stream_t *stream, int *demuxer_type) { - char *proto = stream->streaming_ctrl->url->protocol; - int fd = -1; - int port = stream->streaming_ctrl->url->port; - - // Is protocol mms or mmsu? - if (!strcasecmp(proto, "mmsu") || !strcasecmp(proto, "mms")) - { - mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/UDP...\n"); - //fd = asf_mmsu_streaming_start( stream ); - if( fd>-1 ) return fd; //mmsu support is not implemented yet - using this code - mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/UDP failed\n"); - if( fd==-2 ) return -1; - } - - //Is protocol mms or mmst? - if (!strcasecmp(proto, "mmst") || !strcasecmp(proto, "mms")) - { - mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/TCP...\n"); - fd = asf_mmst_streaming_start( stream ); - stream->streaming_ctrl->url->port = port; - if( fd>-1 ) return fd; - mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/TCP failed\n"); - if( fd==-2 ) return -1; - } - - //Is protocol http, http_proxy, or mms? - if (!strcasecmp(proto, "http_proxy") || !strcasecmp(proto, "http") || - !strcasecmp(proto, "mms") || !strcasecmp(proto, "mmshttp")) - { - mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/HTTP...\n"); - fd = asf_http_streaming_start( stream, demuxer_type ); - stream->streaming_ctrl->url->port = port; - if( fd>-1 ) return fd; - mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/HTTP failed\n"); - if( fd==-2 ) return -1; - } - - //everything failed - return -1; -} - -static int asf_streaming(ASF_stream_chunck_t *stream_chunck, int *drop_packet ) { -/* -printf("ASF stream chunck size=%d\n", stream_chunck->size); -printf("length: %d\n", length ); -printf("0x%02X\n", stream_chunck->type ); -*/ - if( drop_packet!=NULL ) *drop_packet = 0; - - if( stream_chunck->size<8 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_StreamChunkSize2Small, stream_chunck->size); - return -1; - } - if( stream_chunck->size!=stream_chunck->size_confirm ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SizeConfirmMismatch, stream_chunck->size, stream_chunck->size_confirm); - return -1; - } -/* - printf(" type: 0x%02X\n", stream_chunck->type ); - printf(" size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size ); - printf(" sequence_number: 0x%04X\n", stream_chunck->sequence_number ); - printf(" unknown: 0x%02X\n", stream_chunck->unknown ); - printf(" size_confirm: 0x%02X\n", stream_chunck->size_confirm ); -*/ - switch(stream_chunck->type) { - case ASF_STREAMING_CLEAR: // $C Clear ASF configuration - mp_msg(MSGT_NETWORK,MSGL_V,"=====> Clearing ASF stream configuration!\n"); - if( drop_packet!=NULL ) *drop_packet = 1; - return stream_chunck->size; - break; - case ASF_STREAMING_DATA: // $D Data follows -// printf("=====> Data follows\n"); - break; - case ASF_STREAMING_END_TRANS: // $E Transfer complete - mp_msg(MSGT_NETWORK,MSGL_V,"=====> Transfer complete\n"); - if( drop_packet!=NULL ) *drop_packet = 1; - return stream_chunck->size; - break; - case ASF_STREAMING_HEADER: // $H ASF header chunk follows - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF header chunk follows\n"); - break; - default: - mp_msg(MSGT_NETWORK,MSGL_V,"=====> Unknown stream type 0x%x\n", stream_chunck->type ); - } - return stream_chunck->size+4; -} - -extern int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len); -extern const char asf_file_header_guid[]; -extern const char asf_stream_header_guid[]; -extern const char asf_stream_group_guid[]; -extern int audio_id; -extern int video_id; - -static void close_s(stream_t *stream) { - close(stream->fd); - stream->fd=-1; -} - -static int max_idx(int s_count, int *s_rates, int bound) { - int i, best = -1, rate = -1; - for (i = 0; i < s_count; i++) { - if (s_rates[i] > rate && s_rates[i] <= bound) { - rate = s_rates[i]; - best = i; - } - } - return best; -} - -static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { - ASF_header_t asfh; - ASF_stream_chunck_t chunk; - asf_http_streaming_ctrl_t* asf_ctrl = (asf_http_streaming_ctrl_t*) streaming_ctrl->data; - char* buffer=NULL, *chunk_buffer=NULL; - int i,r,size,pos = 0; - int start; - int buffer_size = 0; - int chunk_size2read = 0; - int bw = streaming_ctrl->bandwidth; - int *v_rates = NULL, *a_rates = NULL; - int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1; - - if(asf_ctrl == NULL) return -1; - - // The ASF header can be in several network chunks. For example if the content description - // is big, the ASF header will be split in 2 network chunk. - // So we need to retrieve all the chunk before starting to parse the header. - do { - for( r=0; r < (int)sizeof(ASF_stream_chunck_t) ; ) { - i = nop_streaming_read(fd,((char*)&chunk)+r,sizeof(ASF_stream_chunck_t) - r,streaming_ctrl); - if(i <= 0) return -1; - r += i; - } - // Endian handling of the stream chunk - le2me_ASF_stream_chunck_t(&chunk); - size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t); - if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_WarnDropHeader); - if(size < 0){ - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); - return -1; - } - if (chunk.type != ASF_STREAMING_HEADER) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk); - return -1; - } - - // audit: do not overflow buffer_size - if (size > SIZE_MAX - buffer_size) return -1; - buffer = (char*) malloc(size+buffer_size); - if(buffer == NULL) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_ASF_BufferMallocFailed,size+buffer_size); - return -1; - } - if( chunk_buffer!=NULL ) { - memcpy( buffer, chunk_buffer, buffer_size ); - free( chunk_buffer ); - } - chunk_buffer = buffer; - buffer += buffer_size; - buffer_size += size; - - for(r = 0; r < size;) { - i = nop_streaming_read(fd,buffer+r,size-r,streaming_ctrl); - if(i < 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingNetworkStream); - return -1; - } - r += i; - } - - if( chunk_size2read==0 ) { - if(size < (int)sizeof(asfh)) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunk2Small); - return -1; - } else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n"); - memcpy(&asfh,buffer,sizeof(asfh)); - le2me_ASF_header_t(&asfh); - chunk_size2read = asfh.objh.size; - mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read); - } - } while( buffer_size<chunk_size2read); - buffer = chunk_buffer; - size = buffer_size; - - if(asfh.cno > 256) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrSubChunkNumberInvalid); - return -1; - } - - start = sizeof(asfh); - - pos = find_asf_guid(buffer, asf_file_header_guid, start, size); - if (pos >= 0) { - ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos]; - pos += sizeof(ASF_file_header_t); - if (pos > size) goto len_err_out; - le2me_ASF_file_header_t(fileh); -/* - if(fileh.packetsize != fileh.packetsize2) { - printf("Error packetsize check don't match\n"); - return -1; - } -*/ - asf_ctrl->packet_size = fileh->max_packet_size; - // before playing. - // preroll: time in ms to bufferize before playing - streaming_ctrl->prebuffer_size = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0)); - } - - pos = start; - while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0) - { - ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos]; - pos += sizeof(ASF_stream_header_t); - if (pos > size) goto len_err_out; - le2me_ASF_stream_header_t(streamh); - switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { - case 0xF8699E40 : // audio stream - if(asf_ctrl->audio_streams == NULL){ - asf_ctrl->audio_streams = malloc(sizeof(int)); - asf_ctrl->n_audio = 1; - } else { - asf_ctrl->n_audio++; - asf_ctrl->audio_streams = (int*)realloc(asf_ctrl->audio_streams, - asf_ctrl->n_audio*sizeof(int)); - } - asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh->stream_no; - break; - case 0xBC19EFC0 : // video stream - if(asf_ctrl->video_streams == NULL){ - asf_ctrl->video_streams = malloc(sizeof(int)); - asf_ctrl->n_video = 1; - } else { - asf_ctrl->n_video++; - asf_ctrl->video_streams = (int*)realloc(asf_ctrl->video_streams, - asf_ctrl->n_video*sizeof(int)); - } - asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh->stream_no; - break; - } - } - - // always allocate to avoid lots of ifs later - v_rates = calloc(asf_ctrl->n_video, sizeof(int)); - a_rates = calloc(asf_ctrl->n_audio, sizeof(int)); - - pos = find_asf_guid(buffer, asf_stream_group_guid, start, size); - if (pos >= 0) { - // stream bitrate properties object - int stream_count; - char *ptr = &buffer[pos]; - - mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); - stream_count = le2me_16(*(uint16_t*)ptr); - ptr += sizeof(uint16_t); - if (ptr > &buffer[size]) goto len_err_out; - mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n", - stream_count, stream_count ); - for( i=0 ; i<stream_count ; i++ ) { - uint32_t rate; - int id; - int j; - id = le2me_16(*(uint16_t*)ptr); - ptr += sizeof(uint16_t); - if (ptr > &buffer[size]) goto len_err_out; - memcpy(&rate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc - ptr += sizeof(uint32_t); - if (ptr > &buffer[size]) goto len_err_out; - rate = le2me_32(rate); - mp_msg(MSGT_NETWORK, MSGL_V, - " stream id=[0x%x][%u]\n", id, id); - mp_msg(MSGT_NETWORK, MSGL_V, - " max bitrate=[0x%x][%u]\n", rate, rate); - for (j = 0; j < asf_ctrl->n_video; j++) { - if (id == asf_ctrl->video_streams[j]) { - mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n"); - v_rates[j] = rate; - break; - } - } - for (j = 0; j < asf_ctrl->n_audio; j++) { - if (id == asf_ctrl->audio_streams[j]) { - mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n"); - a_rates[j] = rate; - break; - } - } - } - } - free(buffer); - - // automatic stream selection based on bandwidth - if (bw == 0) bw = INT_MAX; - mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw); - - if (asf_ctrl->n_audio) { - // find lowest-bitrate audio stream - a_rate = a_rates[0]; - a_idx = 0; - for (i = 0; i < asf_ctrl->n_audio; i++) { - if (a_rates[i] < a_rate) { - a_rate = a_rates[i]; - a_idx = i; - } - } - if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) { - // both audio and video are not possible, try video only next - a_idx = -1; - a_rate = 0; - } - } - // find best video stream - v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate); - if (v_idx >= 0) - v_rate = v_rates[v_idx]; - - // find best audio stream - a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate); - - free(v_rates); - free(a_rates); - - if (a_idx < 0 && v_idx < 0) { - mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay); - return -1; - } - - if (audio_id > 0) - // a audio stream was forced - asf_ctrl->audio_id = audio_id; - else if (a_idx >= 0) - asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx]; - else if (asf_ctrl->n_audio) { - mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio); - audio_id = -2; - } - - if (video_id > 0) - // a video stream was forced - asf_ctrl->video_id = video_id; - else if (v_idx >= 0) - asf_ctrl->video_id = asf_ctrl->video_streams[v_idx]; - else if (asf_ctrl->n_video) { - mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo); - video_id = -2; - } - - return 1; - -len_err_out: - mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_InvalidLenInHeader); - if (buffer) free(buffer); - if (v_rates) free(v_rates); - if (a_rates) free(a_rates); - return -1; -} - -static int asf_http_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { - static ASF_stream_chunck_t chunk; - int read,chunk_size = 0; - static int rest = 0, drop_chunk = 0, waiting = 0; - asf_http_streaming_ctrl_t *asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data; - - while(1) { - if (rest == 0 && waiting == 0) { - read = 0; - while(read < (int)sizeof(ASF_stream_chunck_t)){ - int r = nop_streaming_read( fd, ((char*)&chunk) + read, - sizeof(ASF_stream_chunck_t)-read, - streaming_ctrl ); - if(r <= 0){ - if( r < 0) - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingChunkHeader); - return -1; - } - read += r; - } - - // Endian handling of the stream chunk - le2me_ASF_stream_chunck_t(&chunk); - chunk_size = asf_streaming( &chunk, &drop_chunk ); - if(chunk_size < 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); - return -1; - } - chunk_size -= sizeof(ASF_stream_chunck_t); - - if(chunk.type != ASF_STREAMING_HEADER && (!drop_chunk)) { - if (asf_http_ctrl->packet_size < chunk_size) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunkBiggerThanPacket); - return -1; - } - waiting = asf_http_ctrl->packet_size; - } else { - waiting = chunk_size; - } - - } else if (rest){ - chunk_size = rest; - rest = 0; - } - - read = 0; - if ( waiting >= chunk_size) { - if (chunk_size > size){ - rest = chunk_size - size; - chunk_size = size; - } - while(read < chunk_size) { - int got = nop_streaming_read( fd,buffer+read,chunk_size-read,streaming_ctrl ); - if(got <= 0) { - if(got < 0) - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingChunk); - return -1; - } - read += got; - } - waiting -= read; - if (drop_chunk) continue; - } - if (rest == 0 && waiting > 0 && size-read > 0) { - int s = MIN(waiting,size-read); - memset(buffer+read,0,s); - waiting -= s; - read += s; - } - break; - } - - return read; -} - -static int asf_http_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl ) { - return -1; - // to shut up gcc warning - fd++; - pos++; - streaming_ctrl=NULL; -} - -static int asf_header_check( HTTP_header_t *http_hdr ) { - ASF_obj_header_t *objh; - if( http_hdr==NULL ) return -1; - if( http_hdr->body==NULL || http_hdr->body_size<sizeof(ASF_obj_header_t) ) return -1; - - objh = (ASF_obj_header_t*)http_hdr->body; - if( ASF_LOAD_GUID_PREFIX(objh->guid)==0x75B22630 ) return 0; - return -1; -} - -static int asf_http_streaming_type(char *content_type, char *features, HTTP_header_t *http_hdr ) { - if( content_type==NULL ) return ASF_Unknown_e; - if( !strcasecmp(content_type, "application/octet-stream") || - !strcasecmp(content_type, "application/vnd.ms.wms-hdr.asfv1") || // New in Corona, first request - !strcasecmp(content_type, "application/x-mms-framed") || // New in Corana, second request - !strcasecmp(content_type, "video/x-ms-asf")) { - - if( strstr(features, "broadcast") ) { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Live stream\n"); - return ASF_Live_e; - } else { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Prerecorded\n"); - return ASF_Prerecorded_e; - } - } else { - // Ok in a perfect world, web servers should be well configured - // so we could used mime type to know the stream type, - // but guess what? All of them are not well configured. - // So we have to check for an asf header :(, but it works :p - if( http_hdr->body_size>sizeof(ASF_obj_header_t) ) { - if( asf_header_check( http_hdr )==0 ) { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n"); - return ASF_PlainText_e; - } else if( (!strcasecmp(content_type, "text/html")) ) { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> HTML, MPlayer is not a browser...yet!\n"); - return ASF_Unknown_e; - } else { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Redirector\n"); - return ASF_Redirector_e; - } - } else { - if( (!strcasecmp(content_type, "audio/x-ms-wax")) || - (!strcasecmp(content_type, "audio/x-ms-wma")) || - (!strcasecmp(content_type, "video/x-ms-asf")) || - (!strcasecmp(content_type, "video/x-ms-afs")) || - (!strcasecmp(content_type, "video/x-ms-wvx")) || - (!strcasecmp(content_type, "video/x-ms-wmv")) || - (!strcasecmp(content_type, "video/x-ms-wma")) ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ASFRedirector); - return ASF_Redirector_e; - } else if( !strcasecmp(content_type, "text/plain") ) { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n"); - return ASF_PlainText_e; - } else { - mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF unknown content-type: %s\n", content_type ); - return ASF_Unknown_e; - } - } - } - return ASF_Unknown_e; -} - -static HTTP_header_t *asf_http_request(streaming_ctrl_t *streaming_ctrl) { - HTTP_header_t *http_hdr; - URL_t *url = NULL; - URL_t *server_url = NULL; - asf_http_streaming_ctrl_t *asf_http_ctrl; - char str[250]; - char *ptr; - int i, enable; - - int offset_hi=0, offset_lo=0, length=0; - int asf_nb_stream=0, stream_id; - - // Sanity check - if( streaming_ctrl==NULL ) return NULL; - url = streaming_ctrl->url; - asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data; - if( url==NULL || asf_http_ctrl==NULL ) return NULL; - - // Common header for all requests. - http_hdr = http_new_header(); - http_set_field( http_hdr, "Accept: */*" ); - http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" ); - http_add_basic_authentication( http_hdr, url->username, url->password ); - - // Check if we are using a proxy - if( !strcasecmp( url->protocol, "http_proxy" ) ) { - server_url = url_new( (url->file)+1 ); - if( server_url==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_InvalidProxyURL); - http_free( http_hdr ); - return NULL; - } - http_set_uri( http_hdr, server_url->url ); - sprintf( str, "Host: %.220s:%d", server_url->hostname, server_url->port ); - url_free( server_url ); - } else { - http_set_uri( http_hdr, url->file ); - sprintf( str, "Host: %.220s:%d", url->hostname, url->port ); - } - - http_set_field( http_hdr, str ); - http_set_field( http_hdr, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}" ); - sprintf(str, - "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=%u", - offset_hi, offset_lo, asf_http_ctrl->request, length ); - http_set_field( http_hdr, str ); - - switch( asf_http_ctrl->streaming_type ) { - case ASF_Live_e: - case ASF_Prerecorded_e: - http_set_field( http_hdr, "Pragma: xPlayStrm=1" ); - ptr = str; - ptr += sprintf( ptr, "Pragma: stream-switch-entry="); - if(asf_http_ctrl->n_audio > 0) { - for( i=0; i<asf_http_ctrl->n_audio ; i++ ) { - stream_id = asf_http_ctrl->audio_streams[i]; - if(stream_id == asf_http_ctrl->audio_id) { - enable = 0; - } else { - enable = 2; - continue; - } - asf_nb_stream++; - ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable); - } - } - if(asf_http_ctrl->n_video > 0) { - for( i=0; i<asf_http_ctrl->n_video ; i++ ) { - stream_id = asf_http_ctrl->video_streams[i]; - if(stream_id == asf_http_ctrl->video_id) { - enable = 0; - } else { - enable = 2; - continue; - } - asf_nb_stream++; - ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable); - } - } - http_set_field( http_hdr, str ); - sprintf( str, "Pragma: stream-switch-count=%d", asf_nb_stream ); - http_set_field( http_hdr, str ); - break; - case ASF_Redirector_e: - break; - case ASF_Unknown_e: - // First request goes here. - break; - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_UnknownASFStreamType); - } - - http_set_field( http_hdr, "Connection: Close" ); - http_build_request( http_hdr ); - - return http_hdr; -} - -static int asf_http_parse_response(asf_http_streaming_ctrl_t *asf_http_ctrl, HTTP_header_t *http_hdr ) { - char *content_type, *pragma; - char features[64] = "\0"; - size_t len; - if( http_response_parse(http_hdr)<0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_Failed2ParseHTTPResponse); - return -1; - } - switch( http_hdr->status_code ) { - case 200: - break; - case 401: // Authentication required - return ASF_Authenticate_e; - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ServerReturn, http_hdr->status_code, http_hdr->reason_phrase); - return -1; - } - - content_type = http_get_field( http_hdr, "Content-Type"); -//printf("Content-Type: [%s]\n", content_type); - - pragma = http_get_field( http_hdr, "Pragma"); - while( pragma!=NULL ) { - char *comma_ptr=NULL; - char *end; -//printf("Pragma: [%s]\n", pragma ); - // The pragma line can get severals attributes - // separeted with a comma ','. - do { - if( !strncasecmp( pragma, "features=", 9) ) { - pragma += 9; - end = strstr( pragma, "," ); - if( end==NULL ) { - len = strlen(pragma); - } else { - len = (unsigned int)(end-pragma); - } - if(len > sizeof(features) - 1) { - mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_ASFHTTPParseWarnCuttedPragma,pragma,len,sizeof(features) - 1); - len = sizeof(features) - 1; - } - strncpy( features, pragma, len ); - features[len]='\0'; - break; - } - comma_ptr = strstr( pragma, "," ); - if( comma_ptr!=NULL ) { - pragma = comma_ptr+1; - if( pragma[0]==' ' ) pragma++; - } - } while( comma_ptr!=NULL ); - pragma = http_get_next_field( http_hdr ); - } - asf_http_ctrl->streaming_type = asf_http_streaming_type( content_type, features, http_hdr ); - return 0; -} - -static int asf_http_streaming_start( stream_t *stream, int *demuxer_type ) { - HTTP_header_t *http_hdr=NULL; - URL_t *url = stream->streaming_ctrl->url; - asf_http_streaming_ctrl_t *asf_http_ctrl; - char buffer[BUFFER_SIZE]; - int i, ret; - int fd = stream->fd; - int done; - int auth_retry = 0; - - asf_http_ctrl = malloc(sizeof(asf_http_streaming_ctrl_t)); - if( asf_http_ctrl==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return -1; - } - asf_http_ctrl->streaming_type = ASF_Unknown_e; - asf_http_ctrl->request = 1; - asf_http_ctrl->audio_streams = asf_http_ctrl->video_streams = NULL; - asf_http_ctrl->n_audio = asf_http_ctrl->n_video = 0; - stream->streaming_ctrl->data = (void*)asf_http_ctrl; - - do { - done = 1; - if( fd>0 ) closesocket( fd ); - - if( !strcasecmp( url->protocol, "http_proxy" ) ) { - if( url->port==0 ) url->port = 8080; - } else { - if( url->port==0 ) url->port = 80; - } - fd = connect2Server( url->hostname, url->port, 1); - if( fd<0 ) return fd; - - http_hdr = asf_http_request( stream->streaming_ctrl ); - mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request [%s]\n", http_hdr->buffer ); - for(i=0; i < (int)http_hdr->buffer_size ; ) { - int r = send( fd, http_hdr->buffer+i, http_hdr->buffer_size-i, 0 ); - if(r <0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SocketWriteError,strerror(errno)); - return -1; - } - i += r; - } - http_free( http_hdr ); - http_hdr = http_new_header(); - do { - i = recv( fd, buffer, BUFFER_SIZE, 0 ); -//printf("read: %d\n", i ); - if( i<=0 ) { - perror("read"); - http_free( http_hdr ); - return -1; - } - http_response_append( http_hdr, buffer, i ); - } while( !http_is_header_entire( http_hdr ) ); - if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { - http_hdr->buffer[http_hdr->buffer_size]='\0'; - mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer ); - } - ret = asf_http_parse_response(asf_http_ctrl, http_hdr); - if( ret<0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_HeaderParseFailed); - http_free( http_hdr ); - return -1; - } - switch( asf_http_ctrl->streaming_type ) { - case ASF_Live_e: - case ASF_Prerecorded_e: - case ASF_PlainText_e: - if( http_hdr->body_size>0 ) { - if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { - http_free( http_hdr ); - return -1; - } - } - if( asf_http_ctrl->request==1 ) { - if( asf_http_ctrl->streaming_type!=ASF_PlainText_e ) { - // First request, we only got the ASF header. - ret = asf_streaming_parse_header(fd,stream->streaming_ctrl); - if(ret < 0) return -1; - if(asf_http_ctrl->n_audio == 0 && asf_http_ctrl->n_video == 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoStreamFound); - return -1; - } - asf_http_ctrl->request++; - done = 0; - } else { - done = 1; - } - } - break; - case ASF_Redirector_e: - if( http_hdr->body_size>0 ) { - if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { - http_free( http_hdr ); - return -1; - } - } - *demuxer_type = DEMUXER_TYPE_PLAYLIST; - done = 1; - break; - case ASF_Authenticate_e: - if( http_authenticate( http_hdr, url, &auth_retry)<0 ) return -1; - asf_http_ctrl->streaming_type = ASF_Unknown_e; - done = 0; - break; - case ASF_Unknown_e: - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_UnknownASFStreamingType); - closesocket(fd); - http_free( http_hdr ); - return -1; - } - // Check if we got a redirect. - } while(!done); - - stream->fd = fd; - if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e ) { - stream->streaming_ctrl->streaming_read = nop_streaming_read; - stream->streaming_ctrl->streaming_seek = nop_streaming_seek; - } else { - stream->streaming_ctrl->streaming_read = asf_http_streaming_read; - stream->streaming_ctrl->streaming_seek = asf_http_streaming_seek; - stream->streaming_ctrl->buffering = 1; - } - stream->streaming_ctrl->status = streaming_playing_e; - stream->close = close_s; - - http_free( http_hdr ); - return 0; -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - URL_t *url; - - stream->streaming_ctrl = streaming_ctrl_new(); - if( stream->streaming_ctrl==NULL ) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - url_free(url); - - mp_msg(MSGT_OPEN, MSGL_INFO, MSGTR_MPDEMUX_ASF_InfoStreamASFURL, stream->url); - if((!strncmp(stream->url, "http", 4)) && (*file_format!=DEMUXER_TYPE_ASF && *file_format!=DEMUXER_TYPE_UNKNOWN)) { - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - if(asf_streaming_start(stream, file_format) < 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_ASF_StreamingFailed); - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - *file_format = DEMUXER_TYPE_ASF; - stream->type = STREAMTYPE_STREAM; - fixup_network_stream_cache(stream); - return STREAM_OK; -} - -stream_info_t stream_info_asf = { - "mms and mms over http streaming", - "null", - "Bertrand, Reimar Doeffinger, Albeu", - "originally based on work by Majormms (is that code still there?)", - open_s, - {"mms", "mmsu", "mmst", "http", "http_proxy", "mmshttp", NULL}, - NULL, - 0 // Urls are an option string -}; -
--- a/libmpdemux/audio_in.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,219 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "config.h" - -#include "audio_in.h" -#include "mp_msg.h" -#include "help_mp.h" -#include <string.h> -#include <errno.h> - -// sanitizes ai structure before calling other functions -int audio_in_init(audio_in_t *ai, int type) -{ - ai->type = type; - ai->setup = 0; - - ai->channels = -1; - ai->samplerate = -1; - ai->blocksize = -1; - ai->bytes_per_sample = -1; - ai->samplesize = -1; - - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - ai->alsa.handle = NULL; - ai->alsa.log = NULL; - ai->alsa.device = strdup("default"); - return 0; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->oss.audio_fd = -1; - ai->oss.device = strdup("/dev/dsp"); - return 0; -#endif - default: - return -1; - } -} - -int audio_in_setup(audio_in_t *ai) -{ - - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - if (ai_alsa_init(ai) < 0) return -1; - ai->setup = 1; - return 0; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - if (ai_oss_init(ai) < 0) return -1; - ai->setup = 1; - return 0; -#endif - default: - return -1; - } -} - -int audio_in_set_samplerate(audio_in_t *ai, int rate) -{ - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - ai->req_samplerate = rate; - if (!ai->setup) return 0; - if (ai_alsa_setup(ai) < 0) return -1; - return ai->samplerate; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->req_samplerate = rate; - if (!ai->setup) return 0; - if (ai_oss_set_samplerate(ai) < 0) return -1; - return ai->samplerate; -#endif - default: - return -1; - } -} - -int audio_in_set_channels(audio_in_t *ai, int channels) -{ - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - ai->req_channels = channels; - if (!ai->setup) return 0; - if (ai_alsa_setup(ai) < 0) return -1; - return ai->channels; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - ai->req_channels = channels; - if (!ai->setup) return 0; - if (ai_oss_set_channels(ai) < 0) return -1; - return ai->channels; -#endif - default: - return -1; - } -} - -int audio_in_set_device(audio_in_t *ai, char *device) -{ -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - int i; -#endif - if (ai->setup) return -1; - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - if (ai->alsa.device) free(ai->alsa.device); - ai->alsa.device = strdup(device); - /* mplayer cannot handle colons in arguments */ - for (i = 0; i < (int)strlen(ai->alsa.device); i++) { - if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; - } - return 0; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - if (ai->oss.device) free(ai->oss.device); - ai->oss.device = strdup(device); - return 0; -#endif - default: - return -1; - } -} - -int audio_in_uninit(audio_in_t *ai) -{ - if (ai->setup) { - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - if (ai->alsa.log) - snd_output_close(ai->alsa.log); - if (ai->alsa.handle) { - snd_pcm_close(ai->alsa.handle); - } - ai->setup = 0; - return 0; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - close(ai->oss.audio_fd); - ai->setup = 0; - return 0; -#endif - } - } - return -1; -} - -int audio_in_start_capture(audio_in_t *ai) -{ - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - return snd_pcm_start(ai->alsa.handle); -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - return 0; -#endif - default: - return -1; - } -} - -int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer) -{ - int ret; - - switch (ai->type) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - case AUDIO_IN_ALSA: - ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size); - if (ret != ai->alsa.chunk_size) { - if (ret < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, snd_strerror(ret)); - if (ret == -EPIPE) { - if (ai_alsa_xrun(ai) == 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut); - } else { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover); - } - } - } else { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples); - } - return -1; - } - return ret; -#endif -#ifdef USE_OSS_AUDIO - case AUDIO_IN_OSS: - ret = read(ai->oss.audio_fd, buffer, ai->blocksize); - if (ret != ai->blocksize) { - if (ret < 0) { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, strerror(errno)); - } else { - mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples); - } - return -1; - } - return ret; -#endif - default: - return -1; - } -}
--- a/libmpdemux/audio_in.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -#ifndef _audio_in_h -#define _audio_in_h - -#define AUDIO_IN_ALSA 1 -#define AUDIO_IN_OSS 2 - -#include "config.h" - -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) -#include <alsa/asoundlib.h> - -typedef struct { - char *device; - - snd_pcm_t *handle; - snd_output_t *log; - int buffer_time, period_time, chunk_size; - size_t bits_per_sample, bits_per_frame; -} ai_alsa_t; -#endif - -#ifdef USE_OSS_AUDIO -typedef struct { - char *device; - - int audio_fd; -} ai_oss_t; -#endif - -typedef struct -{ - int type; - int setup; - - /* requested values */ - int req_channels; - int req_samplerate; - - /* real values read-only */ - int channels; - int samplerate; - int blocksize; - int bytes_per_sample; - int samplesize; - -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - ai_alsa_t alsa; -#endif -#ifdef USE_OSS_AUDIO - ai_oss_t oss; -#endif -} audio_in_t; - -int audio_in_init(audio_in_t *ai, int type); -int audio_in_setup(audio_in_t *ai); -int audio_in_set_device(audio_in_t *ai, char *device); -int audio_in_set_samplerate(audio_in_t *ai, int rate); -int audio_in_set_channels(audio_in_t *ai, int channels); -int audio_in_uninit(audio_in_t *ai); -int audio_in_start_capture(audio_in_t *ai); -int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer); - -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) -int ai_alsa_setup(audio_in_t *ai); -int ai_alsa_init(audio_in_t *ai); -int ai_alsa_xrun(audio_in_t *ai); -#endif - -#ifdef USE_OSS_AUDIO -int ai_oss_set_samplerate(audio_in_t *ai); -int ai_oss_set_channels(audio_in_t *ai); -int ai_oss_init(audio_in_t *ai); -#endif - -#endif /* _audio_in_h */
--- a/libmpdemux/cache2.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -#include "config.h" - -// Initial draft of my new cache system... -// Note it runs in 2 processes (using fork()), but doesn't requires locking!! -// TODO: seeking, data consistency checking - -#define READ_USLEEP_TIME 10000 -#define FILL_USLEEP_TIME 50000 -#define PREFILL_SLEEP_TIME 200 - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <sys/types.h> -#include <unistd.h> - -#include "osdep/timer.h" -#ifndef WIN32 -#include <sys/wait.h> -#include "osdep/shmem.h" -#else -#include <windows.h> -static DWORD WINAPI ThreadProc(void* s); -#endif - -#include "mp_msg.h" -#include "help_mp.h" - -#include "stream.h" - -int stream_fill_buffer(stream_t *s); -int stream_seek_long(stream_t *s,off_t pos); - -extern int mp_input_check_interrupt(int time); - -typedef struct { - // constats: - unsigned char *buffer; // base pointer of the alllocated buffer memory - int buffer_size; // size of the alllocated buffer memory - int sector_size; // size of a single sector (2048/2324) - int back_size; // we should keep back_size amount of old bytes for backward seek - int fill_limit; // we should fill buffer only if space>=fill_limit - int seek_limit; // keep filling cache if distanse is less that seek limit - // filler's pointers: - int eof; - off_t min_filepos; // buffer contain only a part of the file, from min-max pos - off_t max_filepos; - off_t offset; // filepos <-> bufferpos offset value (filepos of the buffer's first byte) - // reader's pointers: - off_t read_filepos; - // commands/locking: -// int seek_lock; // 1 if we will seek/reset buffer, 2 if we are ready for cmd -// int fifo_flag; // 1 if we should use FIFO to notice cache about buffer reads. - // callback - stream_t* stream; -} cache_vars_t; - -static int min_fill=0; - -int cache_fill_status=0; - -void cache_stats(cache_vars_t* s){ - int newb=s->max_filepos-s->read_filepos; // new bytes in the buffer - mp_msg(MSGT_CACHE,MSGL_INFO,"0x%06X [0x%06X] 0x%06X ",(int)s->min_filepos,(int)s->read_filepos,(int)s->max_filepos); - mp_msg(MSGT_CACHE,MSGL_INFO,"%3d %% (%3d%%)\n",100*newb/s->buffer_size,100*min_fill/s->buffer_size); -} - -int cache_read(cache_vars_t* s,unsigned char* buf,int size){ - int total=0; - while(size>0){ - int pos,newb,len; - - //printf("CACHE2_READ: 0x%X <= 0x%X <= 0x%X \n",s->min_filepos,s->read_filepos,s->max_filepos); - - if(s->read_filepos>=s->max_filepos || s->read_filepos<s->min_filepos){ - // eof? - if(s->eof) break; - // waiting for buffer fill... - usec_sleep(READ_USLEEP_TIME); // 10ms - continue; // try again... - } - - newb=s->max_filepos-s->read_filepos; // new bytes in the buffer - if(newb<min_fill) min_fill=newb; // statistics... - -// printf("*** newb: %d bytes ***\n",newb); - - pos=s->read_filepos - s->offset; - if(pos<0) pos+=s->buffer_size; else - if(pos>=s->buffer_size) pos-=s->buffer_size; - - if(newb>s->buffer_size-pos) newb=s->buffer_size-pos; // handle wrap... - if(newb>size) newb=size; - - // check: - if(s->read_filepos<s->min_filepos) mp_msg(MSGT_CACHE,MSGL_ERR,"Ehh. s->read_filepos<s->min_filepos !!! Report bug...\n"); - - // len=write(mem,newb) - //printf("Buffer read: %d bytes\n",newb); - memcpy(buf,&s->buffer[pos],newb); - buf+=newb; - len=newb; - // ... - - s->read_filepos+=len; - size-=len; - total+=len; - - } - cache_fill_status=(s->max_filepos-s->read_filepos)/(s->buffer_size / 100); - return total; -} - -int cache_fill(cache_vars_t* s){ - int back,back2,newb,space,len,pos; - off_t read=s->read_filepos; - - if(read<s->min_filepos || read>s->max_filepos){ - // seek... - mp_msg(MSGT_CACHE,MSGL_DBG2,"Out of boundaries... seeking to 0x%"PRIX64" \n",(int64_t)read); - // streaming: drop cache contents only if seeking backward or too much fwd: - if(s->stream->type!=STREAMTYPE_STREAM || - read<s->min_filepos || read>=s->max_filepos+s->seek_limit) - { - s->offset= // FIXME!? - s->min_filepos=s->max_filepos=read; // drop cache content :( - if(s->stream->eof) stream_reset(s->stream); - stream_seek(s->stream,read); - mp_msg(MSGT_CACHE,MSGL_DBG2,"Seek done. new pos: 0x%"PRIX64" \n",(int64_t)stream_tell(s->stream)); - } - } - - // calc number of back-bytes: - back=read - s->min_filepos; - if(back<0) back=0; // strange... - if(back>s->back_size) back=s->back_size; - - // calc number of new bytes: - newb=s->max_filepos - read; - if(newb<0) newb=0; // strange... - - // calc free buffer space: - space=s->buffer_size - (newb+back); - - // calc bufferpos: - pos=s->max_filepos - s->offset; - if(pos>=s->buffer_size) pos-=s->buffer_size; // wrap-around - - if(space<s->fill_limit){ -// printf("Buffer is full (%d bytes free, limit: %d)\n",space,s->fill_limit); - return 0; // no fill... - } - -// printf("### read=0x%X back=%d newb=%d space=%d pos=%d\n",read,back,newb,space,pos); - - // reduce space if needed: - if(space>s->buffer_size-pos) space=s->buffer_size-pos; - -// if(space>32768) space=32768; // limit one-time block size - if(space>4*s->sector_size) space=4*s->sector_size; - -// if(s->seek_lock) return 0; // FIXME - -#if 1 - // back+newb+space <= buffer_size - back2=s->buffer_size-(space+newb); // max back size - if(s->min_filepos<(read-back2)) s->min_filepos=read-back2; -#else - s->min_filepos=read-back; // avoid seeking-back to temp area... -#endif - - // .... - //printf("Buffer fill: %d bytes of %d\n",space,s->buffer_size); - //len=stream_fill_buffer(s->stream); - //memcpy(&s->buffer[pos],s->stream->buffer,len); // avoid this extra copy! - // .... - len=stream_read(s->stream,&s->buffer[pos],space); - if(!len) s->eof=1; - - s->max_filepos+=len; - if(pos+len>=s->buffer_size){ - // wrap... - s->offset+=s->buffer_size; - } - - return len; - -} - -cache_vars_t* cache_init(int size,int sector){ - int num; -#ifndef WIN32 - cache_vars_t* s=shmem_alloc(sizeof(cache_vars_t)); -#else - cache_vars_t* s=malloc(sizeof(cache_vars_t)); -#endif - if(s==NULL) return NULL; - - memset(s,0,sizeof(cache_vars_t)); - num=size/sector; - if(num < 16){ - num = 16; - }//32kb min_size - s->buffer_size=num*sector; - s->sector_size=sector; -#ifndef WIN32 - s->buffer=shmem_alloc(s->buffer_size); -#else - s->buffer=malloc(s->buffer_size); -#endif - - if(s->buffer == NULL){ -#ifndef WIN32 - shmem_free(s,sizeof(cache_vars_t)); -#else - free(s); -#endif - return NULL; - } - - s->fill_limit=8*sector; - s->back_size=s->buffer_size/2; - return s; -} - -void cache_uninit(stream_t *s) { - cache_vars_t* c = s->cache_data; - if(!s->cache_pid) return; -#ifndef WIN32 - kill(s->cache_pid,SIGKILL); - waitpid(s->cache_pid,NULL,0); -#else - TerminateThread((HANDLE)s->cache_pid,0); - free(c->stream); -#endif - if(!c) return; -#ifndef WIN32 - shmem_free(c->buffer,c->buffer_size); - shmem_free(s->cache_data,sizeof(cache_vars_t)); -#else - free(c->buffer); - free(s->cache_data); -#endif -} - -static void exit_sighandler(int x){ - // close stream - exit(0); -} - -int stream_enable_cache(stream_t *stream,int size,int min,int seek_limit){ - int ss=(stream->type==STREAMTYPE_VCD)?VCD_SECTOR_DATA:STREAM_BUFFER_SIZE; - cache_vars_t* s; - - if (stream->type==STREAMTYPE_STREAM && stream->fd < 0) { - // The stream has no 'fd' behind it, so is non-cacheable - mp_msg(MSGT_CACHE,MSGL_STATUS,"\rThis stream is non-cacheable\n"); - return 1; - } - - s=cache_init(size,ss); - if(s == NULL) return 0; - stream->cache_data=s; - s->stream=stream; // callback - s->seek_limit=seek_limit; - - - //make sure that we won't wait from cache_fill - //more data than it is alowed to fill - if (s->seek_limit > s->buffer_size - s->fill_limit ){ - s->seek_limit = s->buffer_size - s->fill_limit; - } - if (min > s->buffer_size - s->fill_limit) { - min = s->buffer_size - s->fill_limit; - } - -#ifndef WIN32 - if((stream->cache_pid=fork())){ -#else - { - DWORD threadId; - stream_t* stream2=malloc(sizeof(stream_t)); - memcpy(stream2,s->stream,sizeof(stream_t)); - s->stream=stream2; - stream->cache_pid = CreateThread(NULL,0,ThreadProc,s,0,&threadId); -#endif - // wait until cache is filled at least prefill_init % - mp_msg(MSGT_CACHE,MSGL_V,"CACHE_PRE_INIT: %"PRId64" [%"PRId64"] %"PRId64" pre:%d eof:%d \n", - (int64_t)s->min_filepos,(int64_t)s->read_filepos,(int64_t)s->max_filepos,min,s->eof); - while(s->read_filepos<s->min_filepos || s->max_filepos-s->read_filepos<min){ - mp_msg(MSGT_CACHE,MSGL_STATUS,MSGTR_CacheFill, - 100.0*(float)(s->max_filepos-s->read_filepos)/(float)(s->buffer_size), - (int64_t)s->max_filepos-s->read_filepos - ); - if(s->eof) break; // file is smaller than prefill size - if(mp_input_check_interrupt(PREFILL_SLEEP_TIME)) - return 0; - } - mp_msg(MSGT_CACHE,MSGL_STATUS,"\n"); - return 1; // parent exits - } - -#ifdef WIN32 -} -static DWORD WINAPI ThreadProc(void*s){ -#endif - -// cache thread mainloop: - signal(SIGTERM,exit_sighandler); // kill - while(1){ - if(!cache_fill((cache_vars_t*)s)){ - usec_sleep(FILL_USLEEP_TIME); // idle - } -// cache_stats(s->cache_data); - } -} - -int cache_stream_fill_buffer(stream_t *s){ - int len; - if(s->eof){ s->buf_pos=s->buf_len=0; return 0; } - if(!s->cache_pid) return stream_fill_buffer(s); - -// cache_stats(s->cache_data); - - if(s->pos!=((cache_vars_t*)s->cache_data)->read_filepos) mp_msg(MSGT_CACHE,MSGL_ERR,"!!! read_filepos differs!!! report this bug...\n"); - - len=cache_read(s->cache_data,s->buffer, ((cache_vars_t*)s->cache_data)->sector_size); - //printf("cache_stream_fill_buffer->read -> %d\n",len); - - if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; } - s->buf_pos=0; - s->buf_len=len; - s->pos+=len; -// printf("[%d]",len);fflush(stdout); - return len; - -} - -int cache_stream_seek_long(stream_t *stream,off_t pos){ - cache_vars_t* s; - off_t newpos; - if(!stream->cache_pid) return stream_seek_long(stream,pos); - - s=stream->cache_data; -// s->seek_lock=1; - - mp_msg(MSGT_CACHE,MSGL_DBG2,"CACHE2_SEEK: 0x%"PRIX64" <= 0x%"PRIX64" (0x%"PRIX64") <= 0x%"PRIX64" \n",s->min_filepos,pos,s->read_filepos,s->max_filepos); - - newpos=pos/s->sector_size; newpos*=s->sector_size; // align - stream->pos=s->read_filepos=newpos; - s->eof=0; // !!!!!!! - - cache_stream_fill_buffer(stream); - - pos-=newpos; - if(pos>=0 && pos<=stream->buf_len){ - stream->buf_pos=pos; // byte position in sector - return 1; - } - -// stream->buf_pos=stream->buf_len=0; -// return 1; - - mp_msg(MSGT_CACHE,MSGL_V,"cache_stream_seek: WARNING! Can't seek to 0x%"PRIX64" !\n",(int64_t)(pos+newpos)); - return 0; -}
--- a/libmpdemux/cdd.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -#ifndef __CDD_H__ -#define __CDD_H__ - -#include "config.h" -#ifndef HAVE_LIBCDIO -#include <cdda_interface.h> -#include <cdda_paranoia.h> -#else -#include <cdio/cdda.h> -#include <cdio/paranoia.h> -#endif - -typedef struct { - char cddb_hello[1024]; - unsigned long disc_id; - unsigned int tracks; - char *cache_dir; - char *freedb_server; - int freedb_proto_level; - int anonymous; - char category[100]; - char *xmcd_file; - size_t xmcd_file_size; - void *user_data; -} cddb_data_t; - -typedef struct { - unsigned int min, sec, frame; -} cd_toc_t; - -typedef struct cd_track { - char *name; - unsigned int track_nb; - unsigned int min; - unsigned int sec; - unsigned int msec; - unsigned long frame_begin; - unsigned long frame_length; - struct cd_track *prev; - struct cd_track *next; -} cd_track_t; - -typedef struct { - char *artist; - char *album; - char *genre; - unsigned int nb_tracks; - unsigned int min; - unsigned int sec; - unsigned msec; - cd_track_t *first; - cd_track_t *last; - cd_track_t *current; -} cd_info_t; - -typedef struct { -#ifndef HAVE_LIBCDIO - cdrom_drive* cd; - cdrom_paranoia* cdp; -#else - cdrom_drive_t* cd; - cdrom_paranoia_t* cdp; -#endif - int sector; - int start_sector; - int end_sector; - cd_info_t *cd_info; -} cdda_priv; - -cd_info_t* cd_info_new(); -void cd_info_free(cd_info_t *cd_info); -cd_track_t* cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length); -cd_track_t* cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb); - -void cd_info_debug(cd_info_t *cd_info); - -#endif // __CDD_H__
--- a/libmpdemux/cdda.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,391 +0,0 @@ -#include "config.h" - -#include "stream.h" -#include "m_option.h" -#include "m_struct.h" -#include "bswap.h" - -#include <stdio.h> -#include <stdlib.h> -#include "demuxer.h" - -#include "cdd.h" - -#include "mp_msg.h" -#include "help_mp.h" - -#ifndef CD_FRAMESIZE_RAW -#define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW -#endif - - -extern char *cdrom_device; - -static struct cdda_params { - int speed; - int paranoia_mode; - char* generic_dev; - int sector_size; - int search_overlap; - int toc_bias; - int toc_offset; - int no_skip; - char* device; - m_span_t span; -} cdda_dflts = { - -1, - 0, - NULL, - 0, - -1, - 0, - 0, - 0, - NULL, - { 0, 0 } -}; - -#define ST_OFF(f) M_ST_OFF(struct cdda_params,f) -m_option_t cdda_params_fields[] = { - { "speed", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, - { "paranoia", ST_OFF(paranoia_mode), CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL }, - { "generic-dev", ST_OFF(generic_dev), CONF_TYPE_STRING, 0, 0, 0, NULL }, - { "sector-size", ST_OFF(sector_size), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, - { "overlap", ST_OFF(search_overlap), CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL }, - { "toc-bias", ST_OFF(toc_bias), CONF_TYPE_INT, 0, 0, 0, NULL }, - { "toc-offset", ST_OFF(toc_offset), CONF_TYPE_INT, 0, 0, 0, NULL }, - { "noskip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 0, 1, NULL }, - { "skip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 1, 0, NULL }, - { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, - { "span", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, - /// For url parsing - { "hostname", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, - { "port", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, - { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, - {NULL, NULL, 0, 0, 0, 0, NULL} -}; -static struct m_struct_st stream_opts = { - "cdda", - sizeof(struct cdda_params), - &cdda_dflts, - cdda_params_fields -}; - -/// We keep these options but now they set the defaults -m_option_t cdda_opts[] = { - { "speed", &cdda_dflts.speed, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, - { "paranoia", &cdda_dflts.paranoia_mode, CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL }, - { "generic-dev", &cdda_dflts.generic_dev, CONF_TYPE_STRING, 0, 0, 0, NULL }, - { "sector-size", &cdda_dflts.sector_size, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, - { "overlap", &cdda_dflts.search_overlap, CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL }, - { "toc-bias", &cdda_dflts.toc_bias, CONF_TYPE_INT, 0, 0, 0, NULL }, - { "toc-offset", &cdda_dflts.toc_offset, CONF_TYPE_INT, 0, 0, 0, NULL }, - { "noskip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 0, 1, NULL }, - { "skip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 1, 0, NULL }, - { "device", &cdda_dflts.device, CONF_TYPE_STRING, 0, 0, 0, NULL }, - { "span", &cdda_dflts.span, CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - -extern int cdd_identify(const char *dev); -extern int cddb_resolve(const char *dev, char **xmcd_file); -extern cd_info_t* cddb_parse_xmcd(char *xmcd_file); - -static int seek(stream_t* s,off_t pos); -static int fill_buffer(stream_t* s, char* buffer, int max_len); -static void close_cdda(stream_t* s); - -static int open_cdda(stream_t *st,int m, void* opts, int* file_format) { - struct cdda_params* p = (struct cdda_params*)opts; - int mode = p->paranoia_mode; - int offset = p->toc_offset; -#ifndef HAVE_LIBCDIO - cdrom_drive* cdd = NULL; -#else - cdrom_drive_t* cdd = NULL; -#endif - cdda_priv* priv; - cd_info_t *cd_info,*cddb_info = NULL; - unsigned int audiolen=0; - int last_track; - int i; - char *xmcd_file = NULL; - - if(m != STREAM_READ) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - - if(!p->device) { - if (cdrom_device) - p->device = strdup(cdrom_device); - else - p->device = strdup(DEFAULT_CDROM_DEVICE); - } - -#ifdef MPLAYER_NETWORK - // cdd_identify returns -1 if it cannot read the TOC, - // in which case there is no point in calling cddb_resolve - if(cdd_identify(p->device) >= 0 && strncmp(st->url,"cddb",4) == 0) { - i = cddb_resolve(p->device, &xmcd_file); - if(i == 0) { - cddb_info = cddb_parse_xmcd(xmcd_file); - free(xmcd_file); - } - } -#endif - -#ifndef HAVE_LIBCDIO - if(p->generic_dev) - cdd = cdda_identify_scsi(p->generic_dev,p->device,0,NULL); - else -#endif -#if defined(__NetBSD__) - cdd = cdda_identify_scsi(p->device,p->device,0,NULL); -#else - cdd = cdda_identify(p->device,0,NULL); -#endif - - if(!cdd) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice); - m_struct_free(&stream_opts,opts); - free(cddb_info); - return STREAM_ERROR; - } - - cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); - - if(p->sector_size) { - cdd->nsectors = p->sector_size; -#ifndef HAVE_LIBCDIO - cdd->bigbuff = p->sector_size * CD_FRAMESIZE_RAW; -#endif - } - - if(cdda_open(cdd) != 0) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenDisc); - cdda_close(cdd); - m_struct_free(&stream_opts,opts); - free(cddb_info); - return STREAM_ERROR; - } - - cd_info = cd_info_new(); - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks,cdda_tracks(cdd)); - for(i=0;i<cdd->tracks;i++) { - char track_name[80]; - long sec=cdda_track_firstsector(cdd,i+1); - long off=cdda_track_lastsector(cdd,i+1)-sec+1; - - sprintf(track_name, "Track %d", i+1); - cd_info_add_track(cd_info, track_name, i+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off ); - audiolen += off; - } - cd_info->min = (unsigned int)(audiolen/(60*75)); - cd_info->sec = (unsigned int)((audiolen/75)%60); - cd_info->msec = (unsigned int)(audiolen%75); - - priv = malloc(sizeof(cdda_priv)); - memset(priv, 0, sizeof(cdda_priv)); - priv->cd = cdd; - priv->cd_info = cd_info; - - if(p->toc_bias) - offset -= cdda_track_firstsector(cdd,1); - - if(offset) { - int i; - for(i = 0 ; i < cdd->tracks + 1 ; i++) - cdd->disc_toc[i].dwStartSector += offset; - } - - if(p->speed) - cdda_speed_set(cdd,p->speed); - - last_track = cdda_tracks(cdd); - if (p->span.start > last_track) p->span.start = last_track; - if (p->span.end < p->span.start) p->span.end = p->span.start; - if (p->span.end > last_track) p->span.end = last_track; - if(p->span.start) - priv->start_sector = cdda_track_firstsector(cdd,p->span.start); - else - priv->start_sector = cdda_disc_firstsector(cdd); - - if(p->span.end) { - priv->end_sector = cdda_track_lastsector(cdd,p->span.end); - } else - priv->end_sector = cdda_disc_lastsector(cdd); - - priv->cdp = paranoia_init(cdd); - if(priv->cdp == NULL) { - cdda_close(cdd); - free(priv); - cd_info_free(cd_info); - m_struct_free(&stream_opts,opts); - free(cddb_info); - return STREAM_ERROR; - } - - if(mode == 0) - mode = PARANOIA_MODE_DISABLE; - else if(mode == 1) - mode = PARANOIA_MODE_OVERLAP; - else - mode = PARANOIA_MODE_FULL; - - if(p->no_skip) - mode |= PARANOIA_MODE_NEVERSKIP; -#ifndef HAVE_LIBCDIO - paranoia_modeset(cdd, mode); - - if(p->search_overlap >= 0) - paranoia_overlapset(cdd,p->search_overlap); -#else - paranoia_modeset(priv->cdp, mode); - - if(p->search_overlap >= 0) - paranoia_overlapset(priv->cdp,p->search_overlap); -#endif - - paranoia_seek(priv->cdp,priv->start_sector,SEEK_SET); - priv->sector = priv->start_sector; - -#ifdef MPLAYER_NETWORK - if(cddb_info) { - cd_info_free(cd_info); - priv->cd_info = cddb_info; - cd_info_debug( cddb_info ); - } -#endif - - st->priv = priv; - st->start_pos = priv->start_sector*CD_FRAMESIZE_RAW; - st->end_pos = priv->end_sector*CD_FRAMESIZE_RAW; - st->type = STREAMTYPE_CDDA; - st->sector_size = CD_FRAMESIZE_RAW; - - st->fill_buffer = fill_buffer; - st->seek = seek; - st->close = close_cdda; - - *file_format = DEMUXER_TYPE_RAWAUDIO; - - m_struct_free(&stream_opts,opts); - - return STREAM_OK; -} - -#ifndef HAVE_LIBCDIO -static void cdparanoia_callback(long inpos, int function) { -#else -static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function) { -#endif -} - -static int fill_buffer(stream_t* s, char* buffer, int max_len) { - cdda_priv* p = (cdda_priv*)s->priv; - cd_track_t *cd_track; - int16_t * buf; - int i; - - buf = paranoia_read(p->cdp,cdparanoia_callback); - -#ifdef WORDS_BIGENDIAN - for(i=0;i<CD_FRAMESIZE_RAW/2;i++) - buf[i]=le2me_16(buf[i]); -#endif - - p->sector++; - s->pos = p->sector*CD_FRAMESIZE_RAW; - memcpy(buffer,buf,CD_FRAMESIZE_RAW); - - if((p->sector < p->start_sector) || (p->sector >= p->end_sector)) { - s->eof = 1; - return 0; - } - - for(i=0;i<p->cd->tracks;i++){ - if(p->cd->disc_toc[i].dwStartSector==p->sector-1) { - cd_track = cd_info_get_track(p->cd_info, i+1); -//printf("Track %d, sector=%d\n", i, p->sector-1); - if( cd_track!=NULL ) { - mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb); - } - break; - } - } - - - return CD_FRAMESIZE_RAW; -} - -static int seek(stream_t* s,off_t newpos) { - cdda_priv* p = (cdda_priv*)s->priv; - cd_track_t *cd_track; - int sec; - int current_track=0, seeked_track=0; - int i; - - s->pos = newpos; - if(s->pos < 0) { - s->eof = 1; - return 0; - } - - sec = s->pos/CD_FRAMESIZE_RAW; -//printf("pos: %d, sec: %d ## %d\n", (int)s->pos, (int)sec, CD_FRAMESIZE_RAW); -//printf("sector: %d new: %d\n", p->sector, sec ); - - for(i=0;i<p->cd->tracks;i++){ -// printf("trk #%d: %d .. %d\n",i,p->cd->disc_toc[i].dwStartSector,p->cd->disc_toc[i+1].dwStartSector); - if( p->sector>=p->cd->disc_toc[i].dwStartSector && p->sector<p->cd->disc_toc[i+1].dwStartSector ) { - current_track = i; - } - if( sec>=p->cd->disc_toc[i].dwStartSector && sec<p->cd->disc_toc[i+1].dwStartSector ) { - seeked_track = i; - } - } -//printf("current: %d, seeked: %d\n", current_track, seeked_track); - if( current_track!=seeked_track ) { -//printf("Track %d, sector=%d\n", seeked_track, sec); - cd_track = cd_info_get_track(p->cd_info, seeked_track+1); - if( cd_track!=NULL ) { - mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb); - } - - } -#if 0 - if(sec < p->start_sector) - sec = p->start_sector; - else if(sec > p->end_sector) - sec = p->end_sector; -#endif - - p->sector = sec; -// s->pos = sec*CD_FRAMESIZE_RAW; - -//printf("seek: %d, sec: %d\n", (int)s->pos, sec); - paranoia_seek(p->cdp,sec,SEEK_SET); - return 1; -} - -static void close_cdda(stream_t* s) { - cdda_priv* p = (cdda_priv*)s->priv; - paranoia_free(p->cdp); - cdda_close(p->cd); - cd_info_free(p->cd_info); - free(p); -} - -stream_info_t stream_info_cdda = { - "CDDA", - "cdda", - "Albeu", - "", - open_cdda, - { "cdda", "cddb", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/cddb.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,878 +0,0 @@ -/* - * CDDB HTTP protocol - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2002, MPlayer team. - * - * Implementation follow the freedb.howto1.06.txt specification - * from http://freedb.freedb.org - * - * discid computation by Jeremy D. Zawodny - * Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com> - * Code release under GPL - * - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <stdarg.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#ifdef WIN32 -#ifdef __MINGW32__ -#define mkdir(a,b) mkdir(a) -#endif -#include <windows.h> -#ifdef HAVE_WINSOCK2 -#include <winsock2.h> -#endif -#else -#include <netdb.h> -#include <sys/ioctl.h> -#endif -#include <sys/types.h> -#include <sys/stat.h> - -#include "mp_msg.h" -#include "help_mp.h" - -#if defined(__linux__) - #include <linux/cdrom.h> -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) - #include <sys/cdio.h> -#elif defined(WIN32) - #include <ddk/ntddcdrm.h> -#elif (__bsdi__) - #include <dvd.h> -#endif - -#include "cdd.h" -#include "version.h" -#include "stream.h" -#include "network.h" - -#define DEFAULT_FREEDB_SERVER "freedb.freedb.org" -#define DEFAULT_CACHE_DIR "/.cddb/" - -stream_t* open_cdda(char *dev, char *track); - -static cd_toc_t cdtoc[100]; -static int cdtoc_last_track; - -#if defined(__linux__) || defined(__bsdi__) -int -read_toc(const char *dev) { - int drive; - struct cdrom_tochdr tochdr; - struct cdrom_tocentry tocentry; - int i; - - drive = open(dev, O_RDONLY | O_NONBLOCK); - if( drive<0 ) { - return drive; - } - - ioctl(drive, CDROMREADTOCHDR, &tochdr); - for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) { - tocentry.cdte_track = i; - tocentry.cdte_format = CDROM_MSF; - ioctl(drive, CDROMREADTOCENTRY, &tocentry); - cdtoc[i-1].min = tocentry.cdte_addr.msf.minute; - cdtoc[i-1].sec = tocentry.cdte_addr.msf.second; - cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame; - cdtoc[i-1].frame += cdtoc[i-1].min*60*75; - cdtoc[i-1].frame += cdtoc[i-1].sec*75; - } - tocentry.cdte_track = 0xAA; - tocentry.cdte_format = CDROM_MSF; - ioctl(drive, CDROMREADTOCENTRY, &tocentry); - cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute; - cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second; - cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame; - cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75; - cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75; - close(drive); - return tochdr.cdth_trk1; -} - -#elif defined(WIN32) -int -read_toc(const char *dev) { - HANDLE drive; - DWORD r; - CDROM_TOC toc; - char device[10]; - int i; - - sprintf(device, "\\\\.\\%s", dev); - drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - - if(!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadTOC); - return 0; - } - - for (i = toc.FirstTrack; i <= toc.LastTrack; i++) { - toc.FirstTrack = i; - cdtoc[i-1].min = toc.TrackData[i - 1].Address[1]; - cdtoc[i-1].sec = toc.TrackData[i - 1].Address[2]; - cdtoc[i-1].frame = toc.TrackData[i - 1].Address[3]; - cdtoc[i-1].frame += cdtoc[i-1].min*60*75; - cdtoc[i-1].frame += cdtoc[i-1].sec*75; - } - toc.FirstTrack = 0xAA; - cdtoc[toc.LastTrack].min = toc.TrackData[toc.LastTrack].Address[1]; - cdtoc[toc.LastTrack].sec = toc.TrackData[toc.LastTrack].Address[2]; - cdtoc[toc.LastTrack].frame = toc.TrackData[toc.LastTrack].Address[3]; - cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].min*60*75; - cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].sec*75; - CloseHandle(drive); - return toc.LastTrack; -} - -#elif defined(__FreeBSD__) || defined(__DragonFly__) -int -read_toc(const char *dev) { - int drive; - struct ioc_toc_header tochdr; - struct ioc_read_toc_single_entry tocentry; - int i; - - drive = open(dev, O_RDONLY | O_NONBLOCK); - if( drive<0 ) { - return drive; - } - - ioctl(drive, CDIOREADTOCHEADER, &tochdr); - for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { - tocentry.track = i; - tocentry.address_format = CD_MSF_FORMAT; - ioctl(drive, CDIOREADTOCENTRY, &tocentry); - cdtoc[i-1].min = tocentry.entry.addr.msf.minute; - cdtoc[i-1].sec = tocentry.entry.addr.msf.second; - cdtoc[i-1].frame = tocentry.entry.addr.msf.frame; - cdtoc[i-1].frame += cdtoc[i-1].min*60*75; - cdtoc[i-1].frame += cdtoc[i-1].sec*75; - } - tocentry.track = 0xAA; - tocentry.address_format = CD_MSF_FORMAT; - ioctl(drive, CDIOREADTOCENTRY, &tocentry); - cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute; - cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second; - cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame; - cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75; - cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75; - close(drive); - return tochdr.ending_track; -} - -#elif defined(__NetBSD__) || defined(__OpenBSD__) -int -read_toc(const char *dev) { - int drive; - struct ioc_toc_header tochdr; - struct ioc_read_toc_entry tocentry; - int i; - struct cd_toc_entry toc_buffer; - - drive = open(dev, O_RDONLY | O_NONBLOCK); - if( drive<0 ) { - return drive; - } - - ioctl(drive, CDIOREADTOCHEADER, &tochdr); - for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { - tocentry.starting_track = i; - tocentry.address_format = CD_MSF_FORMAT; - tocentry.data = &toc_buffer; - tocentry.data_len = sizeof(toc_buffer); - ioctl(drive, CDIOREADTOCENTRYS, &tocentry); - cdtoc[i-1].min = toc_buffer.addr.msf.minute; - cdtoc[i-1].sec = toc_buffer.addr.msf.second; - cdtoc[i-1].frame = toc_buffer.addr.msf.frame; - cdtoc[i-1].frame += cdtoc[i-1].min*60*75; - cdtoc[i-1].frame += cdtoc[i-1].sec*75; - } - tocentry.starting_track = 0xAA; - tocentry.address_format = CD_MSF_FORMAT; - ioctl(drive, CDIOREADTOCENTRYS, &tocentry); - cdtoc[tochdr.ending_track].min = toc_buffer.addr.msf.minute; - cdtoc[tochdr.ending_track].sec = toc_buffer.addr.msf.second; - cdtoc[tochdr.ending_track].frame = toc_buffer.addr.msf.frame; - cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75; - cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75; - close(drive); - return tochdr.ending_track; -} -#endif - -/** -\brief Reads TOC from CD in the given device and prints the number of tracks - and the length of each track in minute:second:frame format. -\param *dev the device to analyse -\return if the command line -identify is given, returns the last track of - the TOC or -1 if the TOC can't be read, - otherwise just returns 0 and let cddb_resolve the TOC -*/ -int cdd_identify(const char *dev) -{ - cdtoc_last_track = 0; - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - int i, min, sec, frame; - cdtoc_last_track = read_toc(dev); - if (cdtoc_last_track < 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev); - return -1; - } - mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_CDDA_TRACKS=%d\n", cdtoc_last_track); - for (i = 1; i <= cdtoc_last_track; i++) - { - frame = cdtoc[i].frame - cdtoc[i-1].frame; - sec = frame / 75; - frame -= sec * 75; - min = sec / 60; - sec -= min * 60; - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK_%d_MSF=%02d:%02d:%02d\n", i, min, sec, frame); - } - } - return cdtoc_last_track; -} - -unsigned int -cddb_sum(int n) { - unsigned int ret; - - ret = 0; - while (n > 0) { - ret += (n % 10); - n /= 10; - } - return ret; -} - -unsigned long -cddb_discid(int tot_trks) { - unsigned int i, t = 0, n = 0; - - i = 0; - while (i < (unsigned int)tot_trks) { - n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec); - i++; - } - t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) - - ((cdtoc[0].min * 60) + cdtoc[0].sec); - return ((n % 0xff) << 24 | t << 8 | tot_trks); -} - - - -int -cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) { - char request[4096]; - int fd, ret = 0; - URL_t *url; - HTTP_header_t *http_hdr; - - if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1; - - sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level ); - mp_msg(MSGT_OPEN, MSGL_INFO,"Request[%s]\n", request ); - - url = url_new(request); - if( url==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NotAValidURL); - return -1; - } - - fd = http_send_request(url,0); - if( fd<0 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest); - return -1; - } - - http_hdr = http_read_response( fd ); - if( http_hdr==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse); - return -1; - } - - http_debug_hdr(http_hdr); - mp_msg(MSGT_OPEN, MSGL_INFO,"body=[%s]\n", http_hdr->body ); - - switch(http_hdr->status_code) { - case 200: - ret = reply_parser(http_hdr, cddb_data); - break; - case 400: - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorNOTFOUND); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorUnknown); - } - - http_free( http_hdr ); - url_free( url ); - - return ret; -} - -int -cddb_read_cache(cddb_data_t *cddb_data) { - char file_name[100]; - struct stat stats; - int file_fd, ret; - size_t file_size; - - if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1; - - sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id); - - file_fd = open(file_name, O_RDONLY -#ifdef WIN32 - | O_BINARY -#endif - ); - if( file_fd<0 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCacheFound); - return -1; - } - - ret = fstat( file_fd, &stats ); - if( ret<0 ) { - perror("fstat"); - file_size = 4096; - } else { - file_size = stats.st_size; - } - - cddb_data->xmcd_file = malloc(file_size); - if( cddb_data->xmcd_file==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); - close(file_fd); - return -1; - } - cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size); - if( cddb_data->xmcd_file_size!=file_size ) { - mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenRead); - close(file_fd); - return -1; - } - - close(file_fd); - - return 0; -} - -int -cddb_write_cache(cddb_data_t *cddb_data) { - // We have the file, save it for cache. - struct stat file_stat; - char file_name[100]; - int file_fd, ret; - int wrote=0; - - if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1; - - // Check if the CDDB cache dir exist - ret = stat( cddb_data->cache_dir, &file_stat ); - if( ret<0 ) { - // Directory not present, create it. - ret = mkdir( cddb_data->cache_dir, 0755 ); -#ifdef __MINGW32__ - if( ret<0 && errno != EEXIST ) { -#else - if( ret<0 ) { -#endif - perror("mkdir"); - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToCreateDirectory, cddb_data->cache_dir); - return -1; - } - } - - sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id ); - - file_fd = creat(file_name, S_IREAD|S_IWRITE); - if( file_fd<0 ) { - perror("create"); - return -1; - } - - wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size); - if( wrote<0 ) { - perror("write"); - close(file_fd); - return -1; - } - if( (unsigned int)wrote!=cddb_data->xmcd_file_size ) { - mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenWritten); - close(file_fd); - return -1; - } - - close(file_fd); - - return 0; -} - -int -cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { - unsigned long disc_id; - char category[100]; - char *ptr=NULL, *ptr2=NULL; - int ret, status; - - if( http_hdr==NULL || cddb_data==NULL ) return -1; - - ret = sscanf( http_hdr->body, "%d ", &status); - if( ret!=1 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - - switch(status) { - case 210: - ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id); - if( ret!=3 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - // Check if it's a xmcd database file - ptr = strstr(http_hdr->body, "# xmcd"); - if( ptr==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_InvalidXMCDDatabaseReturned); - return -1; - } - // Ok found the beginning of the file - // look for the end - ptr2 = strstr(ptr, "\r\n.\r\n"); - if( ptr2==NULL ) { - ptr2 = strstr(ptr, "\n.\n"); - if( ptr2==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_FIXME, "Unable to find '.'\n"); - ptr2=ptr+strlen(ptr); //return -1; - } - } - // Ok found the end - // do a sanity check - if( http_hdr->body_size<(unsigned int)(ptr2-ptr) ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnexpectedFIXME); - return -1; - } - cddb_data->xmcd_file = ptr; - cddb_data->xmcd_file_size = ptr2-ptr+2; - cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0'; - // Avoid the http_free function to free the xmcd file...save a mempcy... - http_hdr->body = NULL; - http_hdr->body_size = 0; - return cddb_write_cache(cddb_data); - default: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); - } - return 0; -} - -int -cddb_request_titles(cddb_data_t *cddb_data) { - char command[1024]; - sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id); - return cddb_http_request(command, cddb_read_parse, cddb_data); -} - -int -cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { - char album_title[100]; - char *ptr = NULL; - int ret; - - ptr = strstr(http_hdr->body, "\n"); - if( ptr==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnableToFindEOL); - return -1; - } - ptr++; - // We have a list of exact/inexact matches, so which one do we use? - // So let's take the first one. - ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title); - if( ret!=3 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - ptr = strstr(http_hdr->body, album_title); - if( ptr!=NULL ) { - char *ptr2; - int len; - ptr2 = strstr(ptr, "\n"); - if( ptr2==NULL ) { - len = (http_hdr->body_size)-(ptr-(http_hdr->body)); - } else { - len = ptr2-ptr+1; - } - strncpy(album_title, ptr, len); - album_title[len-2]='\0'; - } - mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title); - return 0; -} - -int -cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { - char album_title[100]; - char *ptr = NULL; - int ret, status; - - ret = sscanf( http_hdr->body, "%d ", &status); - if( ret!=1 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - - switch(status) { - case 200: - // Found exact match - ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title); - if( ret!=4 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - ptr = strstr(http_hdr->body, album_title); - if( ptr!=NULL ) { - char *ptr2; - int len; - ptr2 = strstr(ptr, "\n"); - if( ptr2==NULL ) { - len = (http_hdr->body_size)-(ptr-(http_hdr->body)); - } else { - len = ptr2-ptr+1; - } - strncpy(album_title, ptr, len); - album_title[len-2]='\0'; - } - mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title); - return cddb_request_titles(cddb_data); - case 202: - // No match found - mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_AlbumNotFound); - break; - case 210: - // Found exact matches, list follows - cddb_parse_matches_list(http_hdr, cddb_data); - return cddb_request_titles(cddb_data); -/* -body=[210 Found exact matches, list follows (until terminating `.') -misc c711930d Santana / Supernatural -rock c711930d Santana / Supernatural -blues c711930d Santana / Supernatural -.] -*/ - case 211: - // Found inexact matches, list follows - cddb_parse_matches_list(http_hdr, cddb_data); - return cddb_request_titles(cddb_data); - case 500: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_ServerReturnsCommandSyntaxErr); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); - } - return -1; -} - -int -cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { - int max; - int ret, status; - char *ptr; - - ret = sscanf( http_hdr->body, "%d ", &status); - if( ret!=1 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - - switch(status) { - case 210: - ptr = strstr(http_hdr->body, "max proto:"); - if( ptr==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - ret = sscanf(ptr, "max proto: %d", &max); - if( ret!=1 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - cddb_data->freedb_proto_level = max; - return 0; - default: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); - } - return -1; -} - -int -cddb_get_proto_level(cddb_data_t *cddb_data) { - return cddb_http_request("stat", cddb_proto_level_parse, cddb_data); -} - -int -cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { - int ret, status; - - ret = sscanf( http_hdr->body, "%d ", &status); - if( ret!=1 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); - return -1; - } - - switch(status) { - case 210: - // TODO: Parse the sites - ret = cddb_data->anonymous; // For gcc complaining about unused parameter. - return 0; - case 401: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_NoSitesInfoAvailable); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); - } - return -1; -} - -int -cddb_get_freedb_sites(cddb_data_t *cddb_data) { - return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data); -} - -void -cddb_create_hello(cddb_data_t *cddb_data) { - char host_name[51]; - char *user_name; - - if( cddb_data->anonymous ) { // Default is anonymous - /* Note from Eduardo Pérez Ureta <eperez@it.uc3m.es> : - * We don't send current user/host name in hello to prevent spam. - * Software that sends this is considered spyware - * that most people don't like. - */ - user_name = "anonymous"; - strcpy(host_name, "localhost"); - } else { - if( gethostname(host_name, 50)<0 ) { - strcpy(host_name, "localhost"); - } - user_name = getenv("LOGNAME"); - } - sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION ); -} - -int -cddb_retrieve(cddb_data_t *cddb_data) { - char offsets[1024], command[1024]; - char *ptr; - unsigned int i, time_len; - int ret; - - ptr = offsets; - for( i=0; i<cddb_data->tracks ; i++ ) { - ptr += sprintf(ptr, "%d+", cdtoc[i].frame ); - if (ptr-offsets > sizeof offsets - 40) break; - } - ptr[0]=0; - time_len = (cdtoc[cddb_data->tracks].frame)/75; - - cddb_data->freedb_server = DEFAULT_FREEDB_SERVER; - cddb_data->freedb_proto_level = 1; - cddb_data->xmcd_file = NULL; - - cddb_create_hello(cddb_data); - if( cddb_get_proto_level(cddb_data)<0 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToGetProtocolLevel); - return -1; - } - - //cddb_get_freedb_sites(&cddb_data); - - sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len ); - ret = cddb_http_request(command, cddb_query_parse, cddb_data); - if( ret<0 ) return -1; - - if( cddb_data->cache_dir!=NULL ) { - free(cddb_data->cache_dir); - } - return 0; -} - -int -cddb_resolve(const char *dev, char **xmcd_file) { - char cddb_cache_dir[] = DEFAULT_CACHE_DIR; - char *home_dir = NULL; - cddb_data_t cddb_data; - - if (cdtoc_last_track <= 0) - { - cdtoc_last_track = read_toc(dev); - if (cdtoc_last_track < 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev); - return -1; - } - } - cddb_data.tracks = cdtoc_last_track; - cddb_data.disc_id = cddb_discid(cddb_data.tracks); - cddb_data.anonymous = 1; // Don't send user info by default - - // Check if there is a CD in the drive - // FIXME: That's not really a good way to check - if( cddb_data.disc_id==0 ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCDInDrive); - return -1; - } - - home_dir = getenv("HOME"); -#ifdef __MINGW32__ - if( home_dir==NULL ) home_dir = getenv("USERPROFILE"); - if( home_dir==NULL ) home_dir = getenv("HOMEPATH"); - // Last resort, store the cddb cache in the mplayer directory - if( home_dir==NULL ) home_dir = (char *)get_path(""); -#endif - if( home_dir==NULL ) { - cddb_data.cache_dir = NULL; - } else { - cddb_data.cache_dir = malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1); - if( cddb_data.cache_dir==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); - return -1; - } - sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir ); - } - - // Check for a cached file - if( cddb_read_cache(&cddb_data)<0 ) { - // No Cache found - if( cddb_retrieve(&cddb_data)<0 ) { - return -1; - } - } - - if( cddb_data.xmcd_file!=NULL ) { -// printf("%s\n", cddb_data.xmcd_file ); - *xmcd_file = cddb_data.xmcd_file; - return 0; - } - - return -1; -} - -/******************************************************************************************************************* - * - * xmcd parser - * - *******************************************************************************************************************/ -char* -xmcd_parse_dtitle(cd_info_t *cd_info, char *line) { - char *ptr, *album; - ptr = strstr(line, "DTITLE="); - if( ptr!=NULL ) { - ptr += 7; - album = strstr(ptr, "/"); - if( album==NULL ) return NULL; - cd_info->album = malloc(strlen(album+2)+1); - if( cd_info->album==NULL ) { - return NULL; - } - strcpy( cd_info->album, album+2 ); - album--; - album[0] = '\0'; - cd_info->artist = malloc(strlen(ptr)+1); - if( cd_info->artist==NULL ) { - return NULL; - } - strcpy( cd_info->artist, ptr ); - } - return ptr; -} - -char* -xmcd_parse_dgenre(cd_info_t *cd_info, char *line) { - char *ptr; - ptr = strstr(line, "DGENRE="); - if( ptr!=NULL ) { - ptr += 7; - cd_info->genre = malloc(strlen(ptr)+1); - if( cd_info->genre==NULL ) { - return NULL; - } - strcpy( cd_info->genre, ptr ); - } - return ptr; -} - -char* -xmcd_parse_ttitle(cd_info_t *cd_info, char *line) { - unsigned int track_nb; - unsigned long sec, off; - char *ptr; - ptr = strstr(line, "TTITLE"); - if( ptr!=NULL ) { - ptr += 6; - // Here we point to the track number - track_nb = atoi(ptr); - ptr = strstr(ptr, "="); - if( ptr==NULL ) return NULL; - ptr++; - - sec = cdtoc[track_nb].frame; - off = cdtoc[track_nb+1].frame-sec+1; - - cd_info_add_track( cd_info, ptr, track_nb+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off ); - } - return ptr; -} - -cd_info_t* -cddb_parse_xmcd(char *xmcd_file) { - cd_info_t *cd_info = NULL; - int length, pos = 0; - char *ptr, *ptr2; - unsigned int audiolen; - if( xmcd_file==NULL ) return NULL; - - cd_info = cd_info_new(); - if( cd_info==NULL ) { - return NULL; - } - - length = strlen(xmcd_file); - ptr = xmcd_file; - while( ptr!=NULL && pos<length ) { - // Read a line - ptr2 = ptr; - while( ptr2[0]!='\0' && ptr2[0]!='\r' && ptr2[0]!='\n' ) ptr2++; - if( ptr2[0]=='\0' ) { - break; - } - ptr2[0] = '\0'; - // Ignore comments - if( ptr[0]!='#' ) { - // Search for the album title - if( xmcd_parse_dtitle(cd_info, ptr) ); - // Search for the genre - else if( xmcd_parse_dgenre(cd_info, ptr) ); - // Search for a track title - else if( xmcd_parse_ttitle(cd_info, ptr) ) audiolen++; // <-- audiolen++ to shut up gcc warning - } - if( ptr2[1]=='\n' ) ptr2++; - pos = (ptr2+1)-ptr; - ptr = ptr2+1; - } - - audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame; - cd_info->min = (unsigned int)(audiolen/(60*75)); - cd_info->sec = (unsigned int)((audiolen/75)%60); - cd_info->msec = (unsigned int)(audiolen%75); - - return cd_info; -}
--- a/libmpdemux/cdinfo.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * CD Info - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2002, MPlayer team. -*/ - -#include "config.h" - -#if defined(HAVE_CDDA) - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "mp_msg.h" -#include "help_mp.h" -#include "cdd.h" - -/******************************************************************************************************************* - * - * xmcd parser, cd info list - * - *******************************************************************************************************************/ - -cd_info_t* -cd_info_new() { - cd_info_t *cd_info = NULL; - - cd_info = malloc(sizeof(cd_info_t)); - if( cd_info==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); - return NULL; - } - - memset(cd_info, 0, sizeof(cd_info_t)); - - return cd_info; -} - -void -cd_info_free(cd_info_t *cd_info) { - cd_track_t *cd_track, *cd_track_next; - if( cd_info==NULL ) return; - if( cd_info->artist!=NULL ) free(cd_info->artist); - if( cd_info->album!=NULL ) free(cd_info->album); - if( cd_info->genre!=NULL ) free(cd_info->genre); - - cd_track_next = cd_info->first; - while( cd_track_next!=NULL ) { - cd_track = cd_track_next; - cd_track_next = cd_track->next; - if( cd_track->name!=NULL ) free(cd_track->name); - free(cd_track); - } -} - -cd_track_t* -cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length) { - cd_track_t *cd_track; - - if( cd_info==NULL || track_name==NULL ) return NULL; - - cd_track = malloc(sizeof(cd_track_t)); - if( cd_track==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); - return NULL; - } - memset(cd_track, 0, sizeof(cd_track_t)); - - cd_track->name = malloc(strlen(track_name)+1); - if( cd_track->name==NULL ) { - mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); - free(cd_track); - return NULL; - } - strcpy(cd_track->name, track_name); - cd_track->track_nb = track_nb; - cd_track->min = min; - cd_track->sec = sec; - cd_track->msec = msec; - cd_track->frame_begin = frame_begin; - cd_track->frame_length = frame_length; - - if( cd_info->first==NULL ) { - cd_info->first = cd_track; - } - if( cd_info->last!=NULL ) { - cd_info->last->next = cd_track; - } - - cd_track->prev = cd_info->last; - - cd_info->last = cd_track; - cd_info->current = cd_track; - - cd_info->nb_tracks++; - - return cd_track; -} - -cd_track_t* -cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb) { - cd_track_t *cd_track=NULL; - - if( cd_info==NULL ) return NULL; - - cd_track = cd_info->first; - while( cd_track!=NULL ) { - if( cd_track->track_nb==track_nb ) { - return cd_track; - } - cd_track = cd_track->next; - } - return NULL; -} - -void -cd_info_debug(cd_info_t *cd_info) { - cd_track_t *current_track; - printf("================ CD INFO === start =========\n"); - if( cd_info==NULL ) { - printf("cd_info is NULL\n"); - return; - } - printf(" artist=[%s]\n", cd_info->artist); - printf(" album=[%s]\n", cd_info->album); - printf(" genre=[%s]\n", cd_info->genre); - printf(" nb_tracks=%d\n", cd_info->nb_tracks); - printf(" length= %2d:%02d.%02d\n", cd_info->min, cd_info->sec, cd_info->msec); - current_track = cd_info->first; - while( current_track!=NULL ) { - printf(" #%2d %2d:%02d.%02d @ %7ld\t[%s] \n", current_track->track_nb, current_track->min, current_track->sec, current_track->msec, current_track->frame_begin, current_track->name); - current_track = current_track->next; - } - printf("================ CD INFO === end =========\n"); -} - -#endif
--- a/libmpdemux/cookies.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,278 +0,0 @@ -/* - * HTTP Cookies - * Reads Netscape and Mozilla cookies.txt files - * - * by Dave Lambley <mplayer@davel.me.uk> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <dirent.h> -#include <inttypes.h> - -#include "cookies.h" -#include "http.h" -#include "mp_msg.h" - -#define MAX_COOKIES 20 - -char *cookies_file = NULL; - -typedef struct cookie_list_type { - char *name; - char *value; - char *domain; - char *path; - - int secure; - - struct cookie_list_type *next; -} cookie_list_t; - -/* Pointer to the linked list of cookies */ -static struct cookie_list_type *cookie_list = NULL; - - -/* Like strdup, but stops at anything <31. */ -static char *col_dup(const char *src) -{ - char *dst; - int length = 0; - - while (src[length] > 31) - length++; - - dst = malloc(length + 1); - strncpy(dst, src, length); - dst[length] = 0; - - return dst; -} - -static int right_hand_strcmp(const char *cookie_domain, const char *url_domain) -{ - int c_l; - int u_l; - - c_l = strlen(cookie_domain); - u_l = strlen(url_domain); - - if (c_l > u_l) - return -1; - return strcmp(cookie_domain, url_domain + u_l - c_l); -} - -static int left_hand_strcmp(const char *cookie_path, const char *url_path) -{ - return strncmp(cookie_path, url_path, strlen(cookie_path)); -} - -/* Finds the start of all the columns */ -static int parse_line(char **ptr, char *cols[6]) -{ - int col; - cols[0] = *ptr; - - for (col = 1; col < 7; col++) { - for (; (**ptr) > 31; (*ptr)++); - if (**ptr == 0) - return 0; - (*ptr)++; - if ((*ptr)[-1] != 9) - return 0; - cols[col] = (*ptr); - } - - return 1; -} - -/* Loads a file into RAM */ -static char *load_file(const char *filename, off_t * length) -{ - int fd; - char *buffer; - - mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename); - - fd = open(filename, O_RDONLY); - if (fd < 0) { - mp_msg(MSGT_NETWORK, MSGL_V, "Could not open"); - return NULL; - } - - *length = lseek(fd, 0, SEEK_END); - - if (*length < 0) { - mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF"); - return NULL; - } - - if (*length > SIZE_MAX - 1) { - mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc."); - return NULL; - } - - lseek(fd, SEEK_SET, 0); - - if (!(buffer = malloc(*length + 1))) { - mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc."); - return NULL; - } - - if (read(fd, buffer, *length) != *length) { - mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny."); - return NULL; - } - close(fd); - buffer[*length] = 0; - - return buffer; -} - -/* Loads a cookies.txt file into a linked list. */ -static struct cookie_list_type *load_cookies_from(const char *filename, - struct cookie_list_type - *list) -{ - char *ptr; - off_t length; - - mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename); - - ptr = load_file(filename, &length); - if (!ptr) - return list; - - while (*ptr > 0) { - char *cols[7]; - if (parse_line(&ptr, cols)) { - struct cookie_list_type *new; - new = malloc(sizeof(cookie_list_t)); - new->name = col_dup(cols[5]); - new->value = col_dup(cols[6]); - new->path = col_dup(cols[2]); - new->domain = col_dup(cols[0]); - new->secure = (*(cols[3]) == 't') || (*(cols[3]) == 'T'); - new->next = list; - list = new; - } - } - return list; -} - -/* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */ -static struct cookie_list_type *load_cookies(void) -{ - DIR *dir; - struct dirent *ent; - struct cookie_list_type *list = NULL; - char *buf; - - char *homedir; - - if (cookies_file) - return load_cookies_from(cookies_file, list); - - homedir = getenv("HOME"); - if (!homedir) - return list; - - - buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1); - sprintf(buf, "%s/.mozilla/default", homedir); - dir = opendir(buf); - free(buf); - - if (dir) { - while ((ent = readdir(dir)) != NULL) { - if ((ent->d_name)[0] != '.') { - buf = malloc(strlen(getenv("HOME")) + - sizeof("/.mozilla/default/") + - strlen(ent->d_name) + sizeof("cookies.txt") + 1); - sprintf(buf, "%s/.mozilla/default/%s/cookies.txt", - getenv("HOME"), ent->d_name); - list = load_cookies_from(buf, list); - free(buf); - } - } - closedir(dir); - } - - buf = malloc(strlen(homedir) + sizeof("/.netscape/cookies.txt") + 1); - sprintf(buf, "%s/.netscape/cookies.txt", homedir); - list = load_cookies_from(buf, list); - free(buf); - - return list; -} - -/* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */ -void -cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url) -{ - int found_cookies = 0; - struct cookie_list_type *cookies[MAX_COOKIES]; - struct cookie_list_type *list, *start; - int i; - char *path; - char *buf; - - path = strchr(url, '/'); - if (!path) - path = ""; - - if (!cookie_list) - cookie_list = load_cookies(); - - - list = start = cookie_list; - - /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */ - while (list) { - /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */ - if ((right_hand_strcmp(list->domain, domain) == 0) - && (left_hand_strcmp(list->path, path) == 0) && !list->secure) { - int replacing = 0; - for (i = 0; i < found_cookies; i++) { - if (strcmp(list->name, cookies[i]->name) == 0) { - replacing = 0; - if (strlen(list->domain) <= strlen(cookies[i]->domain)) { - cookies[i] = list; - } else if (strlen(list->path) <= strlen(cookies[i]->path)) { - cookies[i] = list; - } - } - } - if (found_cookies > MAX_COOKIES) { - /* Cookie jar overflow! */ - break; - } - if (!replacing) - cookies[found_cookies++] = list; - } - list = list->next; - } - - - buf = strdup("Cookie:"); - - for (i = 0; i < found_cookies; i++) { - char *nbuf; - - nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) + - strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1); - sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name, - cookies[i]->value); - free(buf); - buf = nbuf; - } - - if (found_cookies) - http_set_field(http_hdr, buf); - else - free(buf); -}
--- a/libmpdemux/cookies.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -/* - * HTTP Cookies - * Reads Netscape and Mozilla cookies.txt files - * - * by Dave Lambley <mplayer@davel.me.uk> - */ - -#ifndef __COOKIES_H -#define __COOKIES_H - -#include "http.h" - -extern void cookies_set(HTTP_header_t * http_hdr, const char *hostname, - const char *url); - -#endif
--- a/libmpdemux/cue_read.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,604 +0,0 @@ -//=================== VideoCD BinCue ========================== - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> - -#include "config.h" -#include "mp_msg.h" -#include "help_mp.h" - -#include "stream.h" - -#include "cue_read.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -#define byte unsigned char -#define SIZERAW 2352 -#define SIZEISO_MODE1 2048 -#define SIZEISO_MODE2_RAW 2352 -#define SIZEISO_MODE2_FORM1 2048 -#define SIZEISO_MODE2_FORM2 2336 -#define AUDIO 0 -#define MODE1 1 -#define MODE2 2 -#define MODE1_2352 10 -#define MODE2_2352 20 -#define MODE1_2048 30 -#define MODE2_2336 40 -#define UNKNOWN -1 - -static struct stream_priv_s { - char* filename; -} stream_priv_dflts = { - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - { "string", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "cue", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static FILE* fd_cue; -static int fd_bin = 0; - -static char bin_filename[256]; - -static char cue_filename[256]; -static char bincue_path[256]; - - -typedef struct track -{ - unsigned short mode; - unsigned short minute; - unsigned short second; - unsigned short frame; - - /* (min*60 + sec) * 75 + fps */ - - unsigned long start_sector; - - /* = the sizes in bytes off all tracks bevor this one */ - /* its needed if there are mode1 tracks befor the mpeg tracks */ - unsigned long start_offset; - - /* unsigned char num[3]; */ -} tTrack; - -/* max 99 tracks on a cd */ -static tTrack tracks[100]; - -static struct cue_track_pos { - int track; - unsigned short mode; - unsigned short minute; - unsigned short second; - unsigned short frame; -} cue_current_pos; - -/* number of tracks on the cd */ -static int nTracks = 0; - -/* presumes Line is preloaded with the "current" line of the file */ -static int cue_getTrackinfo(char *Line, tTrack *track) -{ - char inum[3]; - char min; - char sec; - char fps; - int already_set = 0; - - /* Get the 'mode' */ - if (strncmp(&Line[2], "TRACK ", 6)==0) - { -/* strncpy(track->num, &Line[8], 2); track->num[2] = '\0'; */ - - track->mode = UNKNOWN; - if(strncmp(&Line[11], "AUDIO", 5)==0) track->mode = AUDIO; - if(strncmp(&Line[11], "MODE1/2352", 10)==0) track->mode = MODE1_2352; - if(strncmp(&Line[11], "MODE1/2048", 10)==0) track->mode = MODE1_2048; - if(strncmp(&Line[11], "MODE2/2352", 10)==0) track->mode = MODE2_2352; - if(strncmp(&Line[11], "MODE2/2336", 10)==0) track->mode = MODE2_2336; - } - else return(1); - - /* Get the track indexes */ - while(1) { - if(! fgets( Line, 256, fd_cue ) ) { break;} - - if (strncmp(&Line[2], "TRACK ", 6)==0) - { - /* next track starting */ - break; - } - - /* Track 0 or 1, take the first an get fill the values*/ - if (strncmp(&Line[4], "INDEX ", 6)==0) - { - /* check stuff here so if the answer is false the else stuff below won't be executed */ - strncpy(inum, &Line[10], 2); inum[2] = '\0'; - if ((already_set == 0) && - ((strcmp(inum, "00")==0) || (strcmp(inum, "01")==0))) - { - already_set = 1; - - min = ((Line[13]-'0')<<4) | (Line[14]-'0'); - sec = ((Line[16]-'0')<<4) | (Line[17]-'0'); - fps = ((Line[19]-'0')<<4) | (Line[20]-'0'); - - track->minute = (((min>>4)*10) + (min&0xf)); - track->second = (((sec>>4)*10) + (sec&0xf)); - track->frame = (((fps>>4)*10) + (fps&0xf)); - } - } - else if (strncmp(&Line[4], "PREGAP ", 7)==0) { ; /* ignore */ } - else if (strncmp(&Line[4], "FLAGS ", 6)==0) { ; /* ignore */ } - else mp_msg (MSGT_OPEN,MSGL_INFO, - MSGTR_MPDEMUX_CUEREAD_UnexpectedCuefileLine, Line); - } - return(0); -} - - - -/* FIXME: the string operations ( strcpy,strcat ) below depend - * on the arrays to have the same size, thus we need to make - * sure the sizes are in sync. - */ -static int cue_find_bin (char *firstline) { - int i,j; - char s[256]; - char t[256]; - - /* get the filename out of that */ - /* 12345 6 */ - mp_msg (MSGT_OPEN,MSGL_INFO, "[bincue] cue_find_bin(%s)\n", firstline); - if (strncmp(firstline, "FILE \"",6)==0) - { - i = 0; - j = 0; - while ( firstline[6 + i] != '"') - { - bin_filename[j] = firstline[6 + i]; - - /* if I found a path info, than delete all bevor it */ - switch (bin_filename[j]) - { - case '\\': - j = 0; - break; - - case '/': - j = 0; - break; - - default: - j++; - } - i++; - } - bin_filename[j+1] = '\0'; - - } - - /* now try to open that file, without path */ - fd_bin = open (bin_filename, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, - bin_filename); - - /* now try to find it with the path of the cue file */ - snprintf(s,sizeof( s ),"%s/%s",bincue_path,bin_filename); - fd_bin = open (s, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, - MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); - /* now I would say the whole filename is shit, build our own */ - strncpy(s, cue_filename, strlen(cue_filename) - 3 ); - s[strlen(cue_filename) - 3] = '\0'; - strcat(s, "bin"); - fd_bin = open (s, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, - MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); - - /* ok try it with path */ - snprintf(t, sizeof( t ), "%s/%s", bincue_path, s); - fd_bin = open (t, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, - MSGTR_MPDEMUX_CUEREAD_BinFilenameTested,t); - /* now I would say the whole filename is shit, build our own */ - strncpy(s, cue_filename, strlen(cue_filename) - 3 ); - s[strlen(cue_filename) - 3] = '\0'; - strcat(s, "img"); - fd_bin = open (s, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, - MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); - /* ok try it with path */ - snprintf(t, sizeof( t ), "%s/%s", bincue_path, s); - fd_bin = open (t, O_RDONLY); - if (fd_bin == -1) - { - mp_msg(MSGT_OPEN,MSGL_STATUS, - MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); - - /* I'll give up */ - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_CannotFindBinFile); - return -1; - } - } - } else strcpy(bin_filename, t); - - } else strcpy(bin_filename, s); - - } else strcpy(bin_filename, s); - - } - - mp_msg(MSGT_OPEN,MSGL_INFO, - MSGTR_MPDEMUX_CUEREAD_UsingBinFile, bin_filename); - return 0; -} - -static inline int cue_msf_2_sector(int minute, int second, int frame) { - return frame + (second + minute * 60 ) * 75; -} - -static inline int cue_get_msf(void) { - return cue_msf_2_sector (cue_current_pos.minute, - cue_current_pos.second, - cue_current_pos.frame); -} - -static inline void cue_set_msf(unsigned int sect){ - cue_current_pos.frame=sect%75; - sect=sect/75; - cue_current_pos.second=sect%60; - sect=sect/60; - cue_current_pos.minute=sect; -} - -static inline int cue_mode_2_sector_size(int mode) -{ - switch (mode) - { - case AUDIO: return AUDIO; - case MODE1_2352: return SIZERAW; - case MODE1_2048: return SIZEISO_MODE1; - case MODE2_2352: return SIZEISO_MODE2_RAW; - case MODE2_2336: return SIZEISO_MODE2_FORM2; - - default: - mp_msg(MSGT_OPEN,MSGL_FATAL, - MSGTR_MPDEMUX_CUEREAD_UnknownModeForBinfile); - abort(); - } - -} - - -static int cue_read_cue (char *in_cue_filename) -{ - struct stat filestat; - char sLine[256]; - unsigned int sect; - char *s,*t; - int i; - - /* we have no tracks at the beginning */ - nTracks = 0; - - fd_bin = 0; - - /* split the filename into a path and filename part */ - s = strdup(in_cue_filename); - t = strrchr(s, '/'); - if (t == (char *)NULL) - t = "."; - else { - *t = '\0'; - t = s; - if (*t == '\0') - strcpy(t, "/"); - } - - strlcpy(bincue_path,t,sizeof( bincue_path )); - mp_msg(MSGT_OPEN,MSGL_V,"dirname: %s, cuepath: %s\n", t, bincue_path); - - /* no path at all? */ - if (strcmp(bincue_path, ".") == 0) { - mp_msg(MSGT_OPEN,MSGL_V,"bincue_path: %s\n", bincue_path); - strlcpy(cue_filename,in_cue_filename,sizeof( cue_filename )); - } else { - strlcpy(cue_filename,in_cue_filename + strlen(bincue_path) + 1, - sizeof( cue_filename )); - } - - - - /* open the cue file */ - fd_cue = fopen (in_cue_filename, "r"); - if (fd_cue == NULL) - { - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_CannotOpenCueFile, in_cue_filename); - return -1; - } - - /* read the first line and hand it to find_bin, which will - test more than one possible name of the file */ - - if(! fgets( sLine, 256, fd_cue ) ) - { - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); - fclose (fd_cue); - return -1; - } - - if (cue_find_bin(sLine)) { - fclose (fd_cue); - return -1; - } - - - /* now build the track list */ - /* red the next line and call our track finder */ - if(! fgets( sLine, 256, fd_cue ) ) - { - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); - fclose (fd_cue); - return -1; - } - - while(!feof(fd_cue)) - { - if (cue_getTrackinfo(sLine, &tracks[nTracks++]) != 0) - { - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); - fclose (fd_cue); - return -1; - } - } - - /* make a fake track with stands for the Lead out */ - if (fstat (fd_bin, &filestat) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR, - MSGTR_MPDEMUX_CUEREAD_ErrGettingBinFileSize); - fclose (fd_cue); - return -1; - } - - sect = filestat.st_size / 2352; - - tracks[nTracks].frame = sect%75; - sect=sect/75; - tracks[nTracks].second = sect%60; - sect=sect/60; - tracks[nTracks].minute = sect; - - - /* let's calculate the start sectors and offsets */ - for(i = 0; i <= nTracks; i++) - { - tracks[i].start_sector = cue_msf_2_sector(tracks[i].minute, - tracks[nTracks].second, - tracks[nTracks].frame); - - /* if we're the first track we don't need to offset of the one befor */ - if (i == 0) - { - /* was always 0 on my svcds, but who knows */ - tracks[0].start_offset = tracks[0].start_sector * - cue_mode_2_sector_size(tracks[0].mode); - } else - { - tracks[i].start_offset = tracks[i-1].start_offset + - (tracks[i].start_sector - tracks[i-1].start_sector) * - cue_mode_2_sector_size(tracks[i-1].mode); - } - } - - fclose (fd_cue); - - return fd_bin; -} - - - - -static int cue_read_toc_entry(void) { - - int track = cue_current_pos.track - 1; - - /* check if its a valid track, if not return -1 */ - if (track >= nTracks) - return -1; - - - switch (tracks[track].mode) - { - case AUDIO: - cue_current_pos.mode = AUDIO; - break; - case MODE1_2352: - cue_current_pos.mode = MODE1; - break; - case MODE1_2048: - cue_current_pos.mode = MODE1; - break; - default: /* MODE2_2352 and MODE2_2336 */ - cue_current_pos.mode = MODE2; - } - cue_current_pos.minute = tracks[track].minute; - cue_current_pos.second = tracks[track].second; - cue_current_pos.frame = tracks[track].frame; - - return 0; -} - -static int cue_vcd_seek_to_track (int track){ - cue_current_pos.track = track; - - if (cue_read_toc_entry ()) - return -1; - - return VCD_SECTOR_DATA * cue_get_msf(); -} - -static int cue_vcd_get_track_end (int track){ - cue_current_pos.frame = tracks[track].frame; - cue_current_pos.second = tracks[track].second; - cue_current_pos.minute = tracks[track].minute; - - return VCD_SECTOR_DATA * cue_get_msf(); -} - -static void cue_vcd_read_toc(void){ - int i; - for (i = 0; i < nTracks; ++i) { - - mp_msg(MSGT_OPEN,MSGL_INFO, - MSGTR_MPDEMUX_CUEREAD_InfoTrackFormat, - i+1, - tracks[i].mode, - tracks[i].minute, - tracks[i].second, - tracks[i].frame - ); - } -} - -static int cue_vcd_read(stream_t *stream, char *mem, int size) { - unsigned long position; - int track = cue_current_pos.track - 1; - - position = tracks[track].start_offset + - (cue_msf_2_sector(cue_current_pos.minute, - cue_current_pos.second, - cue_current_pos.frame) - - tracks[track].start_sector) - * cue_mode_2_sector_size(tracks[track].mode); - - - if(position >= tracks[track+1].start_offset) - return 0; - - if(lseek(fd_bin, position+VCD_SECTOR_OFFS, SEEK_SET) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_MPDEMUX_CUEREAD_UnexpectedBinFileEOF); - return 0; - } - - if(read(fd_bin, mem, VCD_SECTOR_DATA) != VCD_SECTOR_DATA) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_MPDEMUX_CUEREAD_CannotReadNBytesOfPayload, VCD_SECTOR_DATA); - return 0; - } - - cue_current_pos.frame++; - if (cue_current_pos.frame==75){ - cue_current_pos.frame=0; - cue_current_pos.second++; - if (cue_current_pos.second==60){ - cue_current_pos.second=0; - cue_current_pos.minute++; - } - } - - return VCD_SECTOR_DATA; -} - -static int seek(stream_t *s,off_t newpos) { - s->pos=newpos; - cue_set_msf(s->pos/VCD_SECTOR_DATA); - return 1; -} - - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - struct stream_priv_s* p = (struct stream_priv_s*)opts; - int ret,ret2,f,track = 0; - char *filename = NULL, *colon = NULL; - - if(mode != STREAM_READ || !p->filename) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - filename = strdup(p->filename); - if(!filename) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - colon = strstr(filename, ":"); - if(colon) { - if(strlen(colon)>1) - track = atoi(colon+1); - *colon = 0; - } - if(!track) - track = 1; - - f = cue_read_cue(filename); - if(f < 0) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - cue_vcd_read_toc(); - ret2=cue_vcd_get_track_end(track); - ret=cue_vcd_seek_to_track(track); - if(ret<0){ - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n"); - return STREAM_UNSUPORTED; - } - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CUEREAD_CueStreamInfo_FilenameTrackTracksavail, filename, track, ret, ret2); - - stream->fd = f; - stream->type = STREAMTYPE_VCDBINCUE; - stream->sector_size = VCD_SECTOR_DATA; - stream->flags = STREAM_READ | STREAM_SEEK_FW; - stream->start_pos = ret; - stream->end_pos = ret2; - stream->fill_buffer = cue_vcd_read; - stream->seek = seek; - - free(filename); - m_struct_free(&stream_opts,opts); - return STREAM_OK; -} - -stream_info_t stream_info_cue = { - "CUE track", - "cue", - "Albeu", - "based on the code from ???", - open_s, - { "cue", NULL }, - &stream_opts, - 1 // Urls are an option string -}; -
--- a/libmpdemux/cue_read.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - -//int cue_read_cue (char *in_cue_filename); -//int cue_vcd_seek_to_track (int track); -//int cue_vcd_get_track_end (int track); -//void cue_vcd_read_toc (); -//int cue_vcd_read(char *mem); -//inline void cue_set_msf(unsigned int sect);
--- a/libmpdemux/dvb_tune.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,791 +0,0 @@ -/* dvbtune - tune.c - - Copyright (C) Dave Chapman 2001,2002 - - Modified for use with MPlayer, for details see the changelog at - http://svn.mplayerhq.hu/mplayer/trunk/ - $Id$ - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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. - Or, point your browser to http://www.gnu.org/copyleft/gpl.html - -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <sys/ioctl.h> -#include <sys/poll.h> -#include <unistd.h> -#include <fcntl.h> -#include <error.h> -#include <time.h> -#include <errno.h> -#include "config.h" - -#ifdef HAVE_DVB_HEAD - #include <linux/dvb/dmx.h> - #include <linux/dvb/frontend.h> - char* dvb_frontenddev[4]={"/dev/dvb/adapter0/frontend0","/dev/dvb/adapter1/frontend0","/dev/dvb/adapter2/frontend0","/dev/dvb/adapter3/frontend0"}; - char* dvb_dvrdev[4]={"/dev/dvb/adapter0/dvr0","/dev/dvb/adapter1/dvr0","/dev/dvb/adapter2/dvr0","/dev/dvb/adapter3/dvr0"}; - char* dvb_demuxdev[4]={"/dev/dvb/adapter0/demux0","/dev/dvb/adapter1/demux0","/dev/dvb/adapter2/demux0","/dev/dvb/adapter3/demux0"}; - static char* dvb_secdev[4]={"","","",""}; //UNUSED, ONLY FOR UNIFORMITY -#else - #include <ost/dmx.h> - #include <ost/sec.h> - #include <ost/frontend.h> - char* dvb_frontenddev[4]={"/dev/ost/frontend0","/dev/ost/frontend1","/dev/ost/frontend2","/dev/ost/frontend3"}; - char* dvb_dvrdev[4]={"/dev/ost/dvr0","/dev/ost/dvr1","/dev/ost/dvr2","/dev/ost/dvr3"}; - static char* dvb_secdev[4]={"/dev/ost/sec0","/dev/ost/sec1","/dev/ost/sec2","/dev/ost/sec3"}; - char* dvb_demuxdev[4]={"/dev/ost/demux0","/dev/ost/demux1","/dev/ost/demux2","/dev/ost/demux3"}; -#endif - -#include "dvbin.h" -#include "mp_msg.h" - - - -int dvb_get_tuner_type(int fe_fd) -{ -#ifdef HAVE_DVB_HEAD - struct dvb_frontend_info fe_info; -#else - FrontendInfo fe_info; -#endif - - int res; - - res = ioctl(fe_fd, FE_GET_INFO, &fe_info); - if(res < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); - return 0; - } - - switch(fe_info.type) - { - case FE_OFDM: - mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-T\n"); - return TUNER_TER; - - case FE_QPSK: - mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-S\n"); - return TUNER_SAT; - - case FE_QAM: - mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-C\n"); - return TUNER_CBL; - -#ifdef DVB_ATSC - case FE_ATSC: - mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); - return TUNER_ATSC; -#endif - default: - mp_msg(MSGT_DEMUX, MSGL_ERR, "UNKNOWN TUNER TYPE\n"); - return 0; - } - -} - -int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype); - -int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt, int *pids) -{ - int i; - - priv->fe_fd = open(dvb_frontenddev[n], O_RDWR | O_NONBLOCK); - if(priv->fe_fd < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING FRONTEND DEVICE %s: ERRNO %d\n", dvb_frontenddev[n], errno); - return 0; - } -#ifdef HAVE_DVB_HEAD - priv->sec_fd=0; -#else - priv->sec_fd = open(dvb_secdev[n], O_RDWR); - if(priv->sec_fd < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING SEC DEVICE %s: ERRNO %d\n", dvb_secdev[n], errno); - close(priv->fe_fd); - return 0; - } -#endif - priv->demux_fds_cnt = 0; - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_OPEN_DEVICES(%d)\n", demux_cnt); - for(i = 0; i < demux_cnt; i++) - { - priv->demux_fds[i] = open(dvb_demuxdev[n], O_RDWR | O_NONBLOCK); - if(priv->demux_fds[i] < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DEMUX 0: %d\n", errno); - return 0; - } - else - { - mp_msg(MSGT_DEMUX, MSGL_V, "OPEN(%d), file %s: FD=%d, CNT=%d\n", i, dvb_demuxdev[n], priv->demux_fds[i], priv->demux_fds_cnt); - priv->demux_fds_cnt++; - } - } - - - priv->dvr_fd = open(dvb_dvrdev[n], O_RDONLY| O_NONBLOCK); - if(priv->dvr_fd < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DVR DEVICE %s: %d\n", dvb_dvrdev[n], errno); - return 0; - } - - return 1; -} - - -int dvb_fix_demuxes(dvb_priv_t *priv, int cnt, int *pids) -{ - int i; - - mp_msg(MSGT_DEMUX, MSGL_V, "FIX %d -> %d\n", priv->demux_fds_cnt, cnt); - if(priv->demux_fds_cnt >= cnt) - { - for(i = priv->demux_fds_cnt-1; i >= cnt; i--) - { - mp_msg(MSGT_DEMUX, MSGL_V, "FIX, CLOSE fd(%d): %d\n", i, priv->demux_fds[i]); - close(priv->demux_fds[i]); - } - priv->demux_fds_cnt = cnt; - } - else if(priv->demux_fds_cnt < cnt) - { - for(i = priv->demux_fds_cnt; i < cnt; i++) - { - priv->demux_fds[i] = open(dvb_demuxdev[priv->card], O_RDWR | O_NONBLOCK); - mp_msg(MSGT_DEMUX, MSGL_V, "FIX, OPEN fd(%d): %d\n", i, priv->demux_fds[i]); - if(priv->demux_fds[i] < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DEMUX 0: %d\n", errno); - return 0; - } - else - priv->demux_fds_cnt++; - } - } - - return 1; -} - -int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype) -{ - int i; - struct dmx_pes_filter_params pesFilterParams; - - pesFilterParams.pid = pid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_TS_TAP; -#ifdef HAVE_DVB_HEAD - pesFilterParams.pes_type = pestype; -#else - pesFilterParams.pesType = pestype; -#endif - - pesFilterParams.flags = DMX_IMMEDIATE_START; - - errno = 0; - if ((i = ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams)) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR IN SETTING DMX_FILTER %i for fd %d: ERRNO: %d", pid, fd, errno); - return 0; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "SET PES FILTER ON PID %d to fd %d, RESULT: %d, ERRNO: %d\n", pid, fd, i, errno); - return 1; -} - - -int dvb_demux_stop(int fd) -{ - int i; - i = ioctl(fd, DMX_STOP); - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "STOPPING FD: %d, RESULT: %d\n", fd, i); - - return (i==0); -} - - -int dvb_demux_start(int fd) -{ - int i; - i = ioctl(fd, DMX_START); - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "STARTING FD: %d, RESULT: %d\n", fd, i); - - return (i==0); -} - - -static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, - fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, - fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int tmout); - - -int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, - fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, - fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout) -{ - int ris; - - mp_msg(MSGT_DEMUX, MSGL_INFO, "dvb_tune Freq: %lu\n", (long unsigned int) freq); - - ris = tune_it(priv->fe_fd, priv->sec_fd, freq, srate, pol, tone, specInv, diseqc, modulation, HP_CodeRate, TransmissionMode, guardInterval, bandWidth, LP_CodeRate, hier, timeout); - - if(ris != 0) - mp_msg(MSGT_DEMUX, MSGL_INFO, "dvb_tune, TUNING FAILED\n"); - - return (ris == 0); -} - - -#ifndef HAVE_DVB_HEAD -static int SecGetStatus (int fd, struct secStatus *state) -{ - if(ioctl(fd, SEC_GET_STATUS, state) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, ("SEC GET STATUS: ")); - return -1; - } - - switch (state->busMode) - { - case SEC_BUS_IDLE: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: IDLE (%d)\n",state->busMode); - break; - case SEC_BUS_BUSY: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: BUSY (%d)\n",state->busMode); - break; - case SEC_BUS_OFF: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OFF (%d)\n",state->busMode); - break; - case SEC_BUS_OVERLOAD: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OVERLOAD (%d)\n",state->busMode); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: unknown (%d)\n",state->busMode); - break; - } - - switch (state->selVolt) - { - case SEC_VOLTAGE_OFF: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: OFF (%d)\n",state->selVolt); - break; - case SEC_VOLTAGE_LT: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: LT (%d)\n",state->selVolt); - break; - case SEC_VOLTAGE_13: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13 (%d)\n",state->selVolt); - break; - case SEC_VOLTAGE_13_5: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13.5 (%d)\n",state->selVolt); - break; - case SEC_VOLTAGE_18: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18 (%d)\n",state->selVolt); - break; - case SEC_VOLTAGE_18_5: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18.5 (%d)\n",state->selVolt); - break; - default: - mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: unknown (%d)\n",state->selVolt); - break; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "SEC CONT TONE: %s\n", (state->contTone == SEC_TONE_ON ? "ON" : "OFF")); - return 0; -} - -#endif - -static void print_status(fe_status_t festatus) -{ - mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); - if (festatus & FE_HAS_SIGNAL) mp_msg(MSGT_DEMUX, MSGL_V," FE_HAS_SIGNAL"); -#ifdef HAVE_DVB_HEAD - if (festatus & FE_TIMEDOUT) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TIMEDOUT"); -#else - if (festatus & FE_HAS_POWER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_POWER"); - if (festatus & FE_SPECTRUM_INV) mp_msg(MSGT_DEMUX, MSGL_V, " FE_SPECTRUM_INV"); - if (festatus & FE_TUNER_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TUNER_HAS_LOCK"); -#endif - if (festatus & FE_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_LOCK"); - if (festatus & FE_HAS_CARRIER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_CARRIER"); - if (festatus & FE_HAS_VITERBI) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_VITERBI"); - if (festatus & FE_HAS_SYNC) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_SYNC"); - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); -} - - -#ifdef HAVE_DVB_HEAD -static int check_status(int fd_frontend,struct dvb_frontend_parameters* feparams, int tuner_type, uint32_t base, int tmout) -{ - int32_t strength; - fe_status_t festatus; - struct pollfd pfd[1]; - int ok=0, locks=0; - time_t tm1, tm2; - - if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); - return -1; - } - - pfd[0].fd = fd_frontend; - pfd[0].events = POLLPRI; - - mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend status\n"); - tm1 = tm2 = time((time_t*) NULL); - while(!ok) - { - festatus = 0; - if(poll(pfd,1,tmout*1000) > 0) - { - if (pfd[0].revents & POLLPRI) - { - if(ioctl(fd_frontend, FE_READ_STATUS, &festatus) >= 0) - if(festatus & FE_HAS_LOCK) - locks++; - } - } - usleep(10000); - tm2 = time((time_t*) NULL); - if((festatus & FE_TIMEDOUT) || (locks >= 2) || (tm2 - tm1 >= tmout)) - ok = 1; - } - - if(festatus & FE_HAS_LOCK) - { - if(ioctl(fd_frontend,FE_GET_FRONTEND,feparams) >= 0) - { - switch(tuner_type) - { - case FE_OFDM: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); - break; - case FE_QPSK: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((feparams->frequency)+base)); - mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); - mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",feparams->u.qpsk.fec_inner); - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); - break; - case FE_QAM: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); - mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); - mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",feparams->u.qpsk.fec_inner); - break; -#ifdef DVB_ATSC - case FE_ATSC: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); - mp_msg(MSGT_DEMUX, MSGL_V, " Modulation: %d\n",feparams->u.vsb.modulation); - break; -#endif - default: - break; - } - } - - strength=0; - if(ioctl(fd_frontend,FE_READ_BER,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); - - strength=0; - if(ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); - - strength=0; - if(ioctl(fd_frontend,FE_READ_SNR,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); - - strength=0; - if(ioctl(fd_frontend,FE_READ_UNCORRECTED_BLOCKS,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "UNC: %d\n",strength); - - print_status(festatus); - } - else - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "Not able to lock to the signal on the given frequency, timeout: %d\n", tmout); - return -1; - } - return 0; -} - -#else - -static int check_status(int fd_frontend,FrontendParameters* feparams,int tuner_type,uint32_t base, int tmout) -{ - int i,res; - int32_t strength; - fe_status_t festatus; - FrontendEvent event; - - struct pollfd pfd[1]; - - while(1) - { - if(ioctl(fd_frontend, FE_GET_EVENT, &event) == -1) - break; - } - - i = 0; res = -1; - while ((i < 3) && (res < 0)) - { - if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); - return -1; - } - - pfd[0].fd = fd_frontend; - pfd[0].events = POLLIN | POLLPRI; - - if(poll(pfd,1,tmout*1000) > 0) - { - if (pfd[0].revents & POLLPRI) - { - mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend event\n"); - if ( ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_EVENT"); - return -1; - } - mp_msg(MSGT_DEMUX, MSGL_V, "Received "); - switch(event.type) - { - case FE_UNEXPECTED_EV: - mp_msg(MSGT_DEMUX, MSGL_V, "unexpected event\n"); - res = -1; - break; - - case FE_FAILURE_EV: - mp_msg(MSGT_DEMUX, MSGL_V, "failure event\n"); - res = -1; - break; - - case FE_COMPLETION_EV: - mp_msg(MSGT_DEMUX, MSGL_V, "completion event\n"); - res = 0; - break; - } - } - i++; - } - } - - if (res > 0) - switch (event.type) - { - case FE_UNEXPECTED_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_UNEXPECTED_EV\n"); - break; - case FE_COMPLETION_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_COMPLETION_EV\n"); - break; - case FE_FAILURE_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_FAILURE_EV\n"); - break; - } - - if (event.type == FE_COMPLETION_EV) - { - switch(tuner_type) - { - case FE_OFDM: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); - break; - - case FE_QPSK: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((event.u.completionEvent.Frequency)+base)); - mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); - mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); - break; - - case FE_QAM: - mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); - mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); - mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); - break; - - default: - break; - } - - strength=0; - if(ioctl(fd_frontend,FE_READ_BER,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); - - strength=0; - if(ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); - - strength=0; - if(ioctl(fd_frontend,FE_READ_SNR,&strength) >= 0) - mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); - - festatus=0; - mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); - - if(ioctl(fd_frontend,FE_READ_STATUS,&festatus) >= 0) - print_status(festatus); - else - mp_msg(MSGT_DEMUX, MSGL_ERR, " ERROR, UNABLE TO READ_STATUS"); - - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); - } - else - { - mp_msg(MSGT_DEMUX, MSGL_V, "Not able to lock to the signal on the given frequency\n"); - return -1; - } - return 0; -} -#endif - -#ifdef HAVE_DVB_HEAD - -static struct diseqc_cmd { - struct dvb_diseqc_master_cmd cmd; - uint32_t wait; -}; - -static int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, - fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b) -{ - if(ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1) - return -1; - if(ioctl(fd, FE_SET_VOLTAGE, v) == -1) - return -1; - usleep(15 * 1000); - if(ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1) - return -1; - usleep(cmd->wait * 1000); - usleep(15 * 1000); - if(ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1) - return -1; - usleep(15 * 1000); - if(ioctl(fd, FE_SET_TONE, t) == -1) - return -1; - - return 0; -} - -/* digital satellite equipment control, - * specification is available from http://www.eutelsat.com/ - */ -static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) -{ - struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; - - /* param: high nibble: reset bits, low nibble set bits, - * bits are: option, position, polarizaion, band - */ - cmd.cmd.msg[3] = - 0xf0 | (((sat_no * 4) & 0x0f) | (hi_lo ? 1 : 0) | (polv ? 0 : 2)); - - return diseqc_send_msg(secfd, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, - &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, - (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A); -} - -#else - -static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) -{ - struct secCommand scmd; - struct secCmdSequence scmds; - - scmds.continuousTone = (hi_lo ? SEC_TONE_ON : SEC_TONE_OFF); - scmds.voltage = (polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); - scmds.miniCommand = SEC_MINI_NONE; - - scmd.type = SEC_CMDTYPE_DISEQC; - scmds.numCommands = 1; - scmds.commands = &scmd; - - scmd.u.diseqc.addr = 0x10; - scmd.u.diseqc.cmd = 0x38; - scmd.u.diseqc.numParams = 1; - scmd.u.diseqc.params[0] = 0xf0 | - (((sat_no) << 2) & 0x0F) | - (hi_lo ? 1 : 0) | - (polv ? 0 : 2); - - if (ioctl(secfd,SEC_SEND_SEQUENCE,&scmds) < 0) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "Error sending DisEqC"); - return -1; - } - - return 0; -} -#endif - -static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, - fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, - fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout) -{ - int res, hi_lo, dfd; -#ifdef HAVE_DVB_HEAD - struct dvb_frontend_parameters feparams; - struct dvb_frontend_info fe_info; -#else - FrontendParameters feparams; - FrontendInfo fe_info; - struct secStatus sec_state; -#endif - - - mp_msg(MSGT_DEMUX, MSGL_V, "TUNE_IT, fd_frontend %d, fd_sec %d\nfreq %lu, srate %lu, pol %c, tone %i, specInv, diseqc %u, fe_modulation_t modulation,fe_code_rate_t HP_CodeRate, fe_transmit_mode_t TransmissionMode,fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth\n", - fd_frontend, fd_sec, (long unsigned int)freq, (long unsigned int)srate, pol, tone, diseqc); - - - if ( (res = ioctl(fd_frontend,FE_GET_INFO, &fe_info) < 0)) - { - mp_msg(MSGT_DEMUX, MSGL_FATAL, "FE_GET_INFO FAILED\n"); - return -1; - } - - -#ifdef HAVE_DVB_HEAD - mp_msg(MSGT_DEMUX, MSGL_V, "Using DVB card \"%s\"\n", fe_info.name); -#endif - - switch(fe_info.type) - { - case FE_OFDM: -#ifdef HAVE_DVB_HEAD - if (freq < 1000000) freq*=1000UL; - feparams.frequency=freq; - feparams.inversion=specInv; - feparams.u.ofdm.bandwidth=bandwidth; - feparams.u.ofdm.code_rate_HP=HP_CodeRate; - feparams.u.ofdm.code_rate_LP=LP_CodeRate; - feparams.u.ofdm.constellation=modulation; - feparams.u.ofdm.transmission_mode=TransmissionMode; - feparams.u.ofdm.guard_interval=guardInterval; - feparams.u.ofdm.hierarchy_information=hier; -#else - if (freq < 1000000) freq*=1000UL; - feparams.Frequency=freq; - feparams.Inversion=specInv; - feparams.u.ofdm.bandWidth=bandwidth; - feparams.u.ofdm.HP_CodeRate=HP_CodeRate; - feparams.u.ofdm.LP_CodeRate=LP_CodeRate; - feparams.u.ofdm.Constellation=modulation; - feparams.u.ofdm.TransmissionMode=TransmissionMode; - feparams.u.ofdm.guardInterval=guardInterval; - feparams.u.ofdm.HierarchyInformation=hier; -#endif - mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-T to %d Hz, bandwidth: %d\n",freq, bandwidth); - break; - case FE_QPSK: - if (freq > 2200000) - { - // this must be an absolute frequency - if (freq < SLOF) - { -#ifdef HAVE_DVB_HEAD - freq = feparams.frequency=(freq-LOF1); -#else - freq = feparams.Frequency=(freq-LOF1); -#endif - hi_lo = 0; - } - else - { -#ifdef HAVE_DVB_HEAD - freq = feparams.frequency=(freq-LOF2); -#else - freq = feparams.Frequency=(freq-LOF2); -#endif - hi_lo = 1; - } - } - else - { - // this is an L-Band frequency -#ifdef HAVE_DVB_HEAD - feparams.frequency=freq; -#else - feparams.Frequency=freq; -#endif - } - -#ifdef HAVE_DVB_HEAD - feparams.inversion=specInv; - feparams.u.qpsk.symbol_rate=srate; - feparams.u.qpsk.fec_inner=HP_CodeRate; - dfd = fd_frontend; -#else - feparams.Inversion=specInv; - feparams.u.qpsk.SymbolRate=srate; - feparams.u.qpsk.FEC_inner=HP_CodeRate; - dfd = fd_sec; -#endif - - mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-S to Freq: %u, Pol: %c Srate: %d, 22kHz: %s, LNB: %d\n",freq,pol,srate,hi_lo ? "on" : "off", diseqc); - - if(do_diseqc(dfd, diseqc, (pol == 'V' ? 1 : 0), hi_lo) == 0) - mp_msg(MSGT_DEMUX, MSGL_V, "DISEQC SETTING SUCCEDED\n"); - else - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "DISEQC SETTING FAILED\n"); - return -1; - } - break; - case FE_QAM: - mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-C to %d, srate=%d\n",freq,srate); -#ifdef HAVE_DVB_HEAD - feparams.frequency=freq; - feparams.inversion=specInv; - feparams.u.qam.symbol_rate = srate; - feparams.u.qam.fec_inner = HP_CodeRate; - feparams.u.qam.modulation = modulation; -#else - feparams.Frequency=freq; - feparams.Inversion=specInv; - feparams.u.qam.SymbolRate = srate; - feparams.u.qam.FEC_inner = HP_CodeRate; - feparams.u.qam.QAM = modulation; -#endif - break; -#ifdef DVB_ATSC - case FE_ATSC: - mp_msg(MSGT_DEMUX, MSGL_V, "tuning ATSC to %d, modulation=%d\n",freq,modulation); - feparams.frequency=freq; - feparams.u.vsb.modulation = modulation; - break; -#endif - default: - mp_msg(MSGT_DEMUX, MSGL_V, "Unknown FE type. Aborting\n"); - return 0; - } - usleep(100000); - -#ifndef HAVE_DVB_HEAD - if (fd_sec) SecGetStatus(fd_sec, &sec_state); -#endif - - return(check_status(fd_frontend,&feparams,fe_info.type, (hi_lo ? LOF2 : LOF1), timeout)); -}
--- a/libmpdemux/dvbin.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,870 +0,0 @@ -/* - -dvbstream -(C) Dave Chapman <dave@dchapman.com> 2001, 2002. - -The latest version can be found at http://www.linuxstb.org/dvbstream - -Modified for use with MPlayer, for details see the changelog at -http://svn.mplayerhq.hu/mplayer/trunk/ -$Id$ - -Copyright notice: - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include "config.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/poll.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> - -#include "stream.h" -#include "demuxer.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -#include "dvbin.h" - - -#define MAX_CHANNELS 8 -#define CHANNEL_LINE_LEN 256 -#define min(a, b) ((a) <= (b) ? (a) : (b)) - - -//TODO: CAMBIARE list_ptr e da globale a per_priv - - -static struct stream_priv_s -{ - char *prog; - int card; - char *type; - int vid, aid; - int timeout; - char *file; -} -stream_defaults = -{ - "", 1, "", 0, 0, 30, NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s, f) - -/// URL definition -static m_option_t stream_params[] = { - {"prog", ST_OFF(prog), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"card", ST_OFF(card), CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, - {"type", ST_OFF(type), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"vid", ST_OFF(vid), CONF_TYPE_INT, 0, 0 ,0, NULL}, - {"aid", ST_OFF(aid), CONF_TYPE_INT, 0, 0 ,0, NULL}, - {"timeout",ST_OFF(timeout), CONF_TYPE_INT, M_OPT_RANGE, 1, 30, NULL}, - {"file", ST_OFF(file), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - - {"hostname", ST_OFF(prog), CONF_TYPE_STRING, 0, 0, 0, NULL }, - {"username", ST_OFF(card), CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - -static struct m_struct_st stream_opts = { - "dvbin", - sizeof(struct stream_priv_s), - &stream_defaults, - stream_params -}; - - - -m_option_t dvbin_opts_conf[] = { - {"prog", &stream_defaults.prog, CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"card", &stream_defaults.card, CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, - {"type", "DVB card type is autodetected and can't be overridden\n", CONF_TYPE_PRINT, CONF_NOCFG, 0 ,0, NULL}, - {"vid", &stream_defaults.vid, CONF_TYPE_INT, 0, 0 ,0, NULL}, - {"aid", &stream_defaults.aid, CONF_TYPE_INT, 0, 0 ,0, NULL}, - {"timeout", &stream_defaults.timeout, CONF_TYPE_INT, M_OPT_RANGE, 1, 30, NULL}, - {"file", &stream_defaults.file, CONF_TYPE_STRING, 0, 0 ,0, NULL}, - - {NULL, NULL, 0, 0, 0, 0, NULL} -}; - - - - -extern int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype); -extern int dvb_demux_stop(int fd); -extern int dvb_get_tuner_type(int fd); -int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt, int *pids); -int dvb_fix_demuxes(dvb_priv_t *priv, int cnt, int *pids); - -extern int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, - fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, - fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate, - fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout); -extern char *dvb_dvrdev[4], *dvb_demuxdev[4], *dvb_frontenddev[4]; - -static dvb_config_t *dvb_config = NULL; - - -static dvb_channels_list *dvb_get_channels(char *filename, int type) -{ - dvb_channels_list *list; - FILE *f; - char line[CHANNEL_LINE_LEN], *colon; - - int fields, cnt, pcnt, k; - dvb_channel_t *ptr, *tmp, chn; - char tmp_lcr[256], tmp_hier[256], inv[256], bw[256], cr[256], mod[256], transm[256], gi[256], vpid_str[256], apid_str[256]; - const char *cbl_conf = "%d:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; - const char *sat_conf = "%d:%c:%d:%d:%255[^:]:%255[^:]\n"; - const char *ter_conf = "%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; - const char *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]\n"; - - mp_msg(MSGT_DEMUX, MSGL_V, "CONFIG_READ FILE: %s, type: %d\n", filename, type); - if((f=fopen(filename, "r"))==NULL) - { - mp_msg(MSGT_DEMUX, MSGL_FATAL, "CAN'T READ CONFIG FILE %s\n", filename); - return NULL; - } - - list = malloc(sizeof(dvb_channels_list)); - if(list == NULL) - { - fclose(f); - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); - return NULL; - } - - ptr = &chn; - list->NUM_CHANNELS = 0; - list->channels = NULL; - while(! feof(f)) - { - if( fgets(line, CHANNEL_LINE_LEN, f) == NULL ) - continue; - - if((line[0] == '#') || (strlen(line) == 0)) - continue; - - colon = index(line, ':'); - if(colon) - { - k = colon - line; - if(!k) - continue; - ptr->name = (char*) malloc(k+1); - if(! ptr->name) - continue; - strncpy(ptr->name, line, k); - ptr->name[k] = 0; - } - else - continue; - k++; - apid_str[0] = vpid_str[0] = 0; - ptr->pids_cnt = 0; - ptr->freq = 0; - if(type == TUNER_TER) - { - fields = sscanf(&line[k], ter_conf, - &ptr->freq, inv, bw, cr, tmp_lcr, mod, - transm, gi, tmp_hier, vpid_str, apid_str); - mp_msg(MSGT_DEMUX, MSGL_V, - "TER, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d", - list->NUM_CHANNELS, fields, ptr->name, ptr->freq); - } - else if(type == TUNER_CBL) - { - fields = sscanf(&line[k], cbl_conf, - &ptr->freq, inv, &ptr->srate, - cr, mod, vpid_str, apid_str); - mp_msg(MSGT_DEMUX, MSGL_V, - "CBL, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d", - list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate); - } -#ifdef DVB_ATSC - else if(type == TUNER_ATSC) - { - fields = sscanf(&line[k], atsc_conf, - &ptr->freq, mod, vpid_str, apid_str); - mp_msg(MSGT_DEMUX, MSGL_V, - "ATSC, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", - list->NUM_CHANNELS, fields, ptr->name, ptr->freq); - } -#endif - else //SATELLITE - { - fields = sscanf(&line[k], sat_conf, - &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, vpid_str, apid_str); - ptr->pol = toupper(ptr->pol); - ptr->freq *= 1000UL; - ptr->srate *= 1000UL; - ptr->tone = -1; - ptr->inv = INVERSION_AUTO; - ptr->cr = FEC_AUTO; - if((ptr->diseqc > 4) || (ptr->diseqc < 0)) - continue; - if(ptr->diseqc > 0) - ptr->diseqc--; - mp_msg(MSGT_DEMUX, MSGL_V, - "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d", - list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, ptr->diseqc); - } - - if(vpid_str[0]) - { - pcnt = sscanf(vpid_str, "%d+%d+%d+%d+%d+%d+%d", &ptr->pids[0], &ptr->pids[1], &ptr->pids[2], &ptr->pids[3], - &ptr->pids[4], &ptr->pids[5], &ptr->pids[6]); - if(pcnt > 0) - { - ptr->pids_cnt = pcnt; - fields++; - } - } - - if(apid_str[0]) - { - cnt = ptr->pids_cnt; - pcnt = sscanf(apid_str, "%d+%d+%d+%d+%d+%d+%d+%d", &ptr->pids[cnt], &ptr->pids[cnt+1], &ptr->pids[cnt+2], - &ptr->pids[cnt+3], &ptr->pids[cnt+4], &ptr->pids[cnt+5], &ptr->pids[cnt+6], &ptr->pids[cnt+7]); - if(pcnt > 0) - { - ptr->pids_cnt += pcnt; - fields++; - } - } - - if((fields < 2) || (ptr->pids_cnt <= 0) || (ptr->freq == 0) || (strlen(ptr->name) == 0)) - continue; - - - ptr->pids[ptr->pids_cnt] = 0; //PID 0 is the PAT - ptr->pids_cnt++; - mp_msg(MSGT_DEMUX, MSGL_V, " PIDS: "); - for(cnt = 0; cnt < ptr->pids_cnt; cnt++) - mp_msg(MSGT_DEMUX, MSGL_V, " %d ", ptr->pids[cnt]); - mp_msg(MSGT_DEMUX, MSGL_V, "\n"); - - if((type == TUNER_TER) || (type == TUNER_CBL)) - { - if(! strcmp(inv, "INVERSION_ON")) - ptr->inv = INVERSION_ON; - else if(! strcmp(inv, "INVERSION_OFF")) - ptr->inv = INVERSION_OFF; - else - ptr->inv = INVERSION_AUTO; - - - if(! strcmp(cr, "FEC_1_2")) - ptr->cr =FEC_1_2; - else if(! strcmp(cr, "FEC_2_3")) - ptr->cr =FEC_2_3; - else if(! strcmp(cr, "FEC_3_4")) - ptr->cr =FEC_3_4; -#ifdef HAVE_DVB_HEAD - else if(! strcmp(cr, "FEC_4_5")) - ptr->cr =FEC_4_5; - else if(! strcmp(cr, "FEC_6_7")) - ptr->cr =FEC_6_7; - else if(! strcmp(cr, "FEC_8_9")) - ptr->cr =FEC_8_9; -#endif - else if(! strcmp(cr, "FEC_5_6")) - ptr->cr =FEC_5_6; - else if(! strcmp(cr, "FEC_7_8")) - ptr->cr =FEC_7_8; - else if(! strcmp(cr, "FEC_NONE")) - ptr->cr =FEC_NONE; - else ptr->cr =FEC_AUTO; - } - - - if((type == TUNER_TER) || (type == TUNER_CBL) || (type == TUNER_ATSC)) - { - if(! strcmp(mod, "QAM_128")) - ptr->mod = QAM_128; - else if(! strcmp(mod, "QAM_256")) - ptr->mod = QAM_256; - else if(! strcmp(mod, "QAM_64")) - ptr->mod = QAM_64; - else if(! strcmp(mod, "QAM_32")) - ptr->mod = QAM_32; - else if(! strcmp(mod, "QAM_16")) - ptr->mod = QAM_16; -#ifdef DVB_ATSC - else if(! strcmp(mod, "VSB_8") || ! strcmp(mod, "8VSB")) - ptr->mod = VSB_8; - else if(! strcmp(mod, "VSB_16") || !strcmp(mod, "16VSB")) - ptr->mod = VSB_16; - - ptr->inv = INVERSION_AUTO; -#endif - } - - if(type == TUNER_TER) - { - if(! strcmp(bw, "BANDWIDTH_6_MHZ")) - ptr->bw = BANDWIDTH_6_MHZ; - else if(! strcmp(bw, "BANDWIDTH_7_MHZ")) - ptr->bw = BANDWIDTH_7_MHZ; - else if(! strcmp(bw, "BANDWIDTH_8_MHZ")) - ptr->bw = BANDWIDTH_8_MHZ; - - - if(! strcmp(transm, "TRANSMISSION_MODE_2K")) - ptr->trans = TRANSMISSION_MODE_2K; - else if(! strcmp(transm, "TRANSMISSION_MODE_8K")) - ptr->trans = TRANSMISSION_MODE_8K; - - - if(! strcmp(gi, "GUARD_INTERVAL_1_32")) - ptr->gi = GUARD_INTERVAL_1_32; - else if(! strcmp(gi, "GUARD_INTERVAL_1_16")) - ptr->gi = GUARD_INTERVAL_1_16; - else if(! strcmp(gi, "GUARD_INTERVAL_1_8")) - ptr->gi = GUARD_INTERVAL_1_8; - else ptr->gi = GUARD_INTERVAL_1_4; - - if(! strcmp(tmp_lcr, "FEC_1_2")) - ptr->cr_lp =FEC_1_2; - else if(! strcmp(tmp_lcr, "FEC_2_3")) - ptr->cr_lp =FEC_2_3; - else if(! strcmp(tmp_lcr, "FEC_3_4")) - ptr->cr_lp =FEC_3_4; -#ifdef HAVE_DVB_HEAD - else if(! strcmp(tmp_lcr, "FEC_4_5")) - ptr->cr_lp =FEC_4_5; - else if(! strcmp(tmp_lcr, "FEC_6_7")) - ptr->cr_lp =FEC_6_7; - else if(! strcmp(tmp_lcr, "FEC_8_9")) - ptr->cr_lp =FEC_8_9; -#endif - else if(! strcmp(tmp_lcr, "FEC_5_6")) - ptr->cr_lp =FEC_5_6; - else if(! strcmp(tmp_lcr, "FEC_7_8")) - ptr->cr_lp =FEC_7_8; - else if(! strcmp(tmp_lcr, "FEC_NONE")) - ptr->cr_lp =FEC_NONE; - else ptr->cr_lp =FEC_AUTO; - - - if(! strcmp(tmp_hier, "HIERARCHY_1")) - ptr->hier = HIERARCHY_1; - else if(! strcmp(tmp_hier, "HIERARCHY_2")) - ptr->hier = HIERARCHY_2; - else if(! strcmp(tmp_hier, "HIERARCHY_4")) - ptr->hier = HIERARCHY_4; -#ifdef HAVE_DVB_HEAD - else if(! strcmp(tmp_hier, "HIERARCHY_AUTO")) - ptr->hier = HIERARCHY_AUTO; -#endif - else ptr->hier = HIERARCHY_NONE; - } - - tmp = (dvb_channel_t*)realloc(list->channels, sizeof(dvb_channel_t) * (list->NUM_CHANNELS + 1)); - if(tmp == NULL) - break; - - list->channels = tmp; - memcpy(&(list->channels[list->NUM_CHANNELS]), ptr, sizeof(dvb_channel_t)); - list->NUM_CHANNELS++; - if(sizeof(dvb_channel_t) * list->NUM_CHANNELS >= 1024*1024) - { - mp_msg(MSGT_DEMUX, MSGL_V, "dvbin.c, > 1MB allocated for channels struct, dropping the rest of the file\r\n"); - break; - } - } - - fclose(f); - if(list->NUM_CHANNELS == 0) - { - if(list->channels != NULL) - free(list->channels); - free(list); - return NULL; - } - - list->current = 0; - return list; -} - - - -static int dvb_streaming_read(stream_t *stream, char *buffer, int size) -{ - struct pollfd pfds[1]; - int pos=0, tries, rk, fd; - dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - - mp_msg(MSGT_DEMUX, MSGL_DBG3, "dvb_streaming_read(%d)\n", size); - - tries = priv->retry + 1; - - fd = stream->fd; - while(pos < size) - { - pfds[0].fd = fd; - pfds[0].events = POLLIN | POLLPRI; - - rk = size - pos; - if(poll(pfds, 1, 500) <= 0) - { - errno = 0; - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_streaming_read, attempt N. %d failed with errno %d when reading %d bytes\n", tries, errno, size-pos); - if(--tries > 0) - continue; - else - break; - } - if((rk = read(fd, &buffer[pos], rk)) > 0) - { - pos += rk; - mp_msg(MSGT_DEMUX, MSGL_DBG3, "ret (%d) bytes\n", pos); - } - } - - - if(! pos) - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_streaming_read, return %d bytes\n", pos); - - return pos; -} - -static void dvbin_close(stream_t *stream); - -int dvb_set_channel(dvb_priv_t *priv, int card, int n) -{ - dvb_channels_list *new_list; - dvb_channel_t *channel; - int do_tuning; - stream_t *stream = (stream_t*) priv->stream; - char buf[4096]; - dvb_config_t *conf = (dvb_config_t *) priv->config; - int devno; - int i; - - if((card < 0) || (card > conf->count)) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_set_channel: INVALID CARD NUMBER: %d vs %d, abort\n", card, conf->count); - return 0; - } - - devno = conf->cards[card].devno; - new_list = conf->cards[card].list; - if((n > new_list->NUM_CHANNELS) || (n < 0)) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_set_channel: INVALID CHANNEL NUMBER: %d, for card %d, abort\n", n, card); - return 0; - } - channel = &(new_list->channels[n]); - - if(priv->is_on) //the fds are already open and we have to stop the demuxers - { - for(i = 0; i < priv->demux_fds_cnt; i++) - dvb_demux_stop(priv->demux_fds[i]); - - priv->retry = 0; - while(dvb_streaming_read(stream, buf, 4096) > 0); //empty both the stream's and driver's buffer - if(priv->card != card) - { - dvbin_close(stream); - if(! dvb_open_devices(priv, devno, channel->pids_cnt, channel->pids)) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF CARD: %d, EXIT\n", card); - return 0; - } - strcpy(priv->prev_tuning, ""); - } - else //close all demux_fds with pos > pids required for the new channel or open other demux_fds if we have too few - { - if(! dvb_fix_demuxes(priv, channel->pids_cnt, channel->pids)) - return 0; - } - } - else - { - if(! dvb_open_devices(priv, devno, channel->pids_cnt, channel->pids)) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF CARD: %d, EXIT\n", card); - return 0; - } - strcpy(priv->prev_tuning, ""); - } - - dvb_config->priv = priv; - priv->card = card; - priv->list = new_list; - priv->retry = 5; - new_list->current = n; - stream->fd = priv->dvr_fd; - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_SET_CHANNEL: new channel name=%s, card: %d, channel %d\n", channel->name, card, n); - - switch(priv->tuner_type) - { - case TUNER_SAT: - sprintf(priv->new_tuning, "%d|%09d|%09d|%d|%c", priv->card, channel->freq, channel->srate, channel->diseqc, channel->pol); - break; - - case TUNER_TER: - sprintf(priv->new_tuning, "%d|%09d|%d|%d|%d|%d|%d|%d", priv->card, channel->freq, channel->inv, - channel->bw, channel->cr, channel->mod, channel->trans, channel->gi); - break; - - case TUNER_CBL: - sprintf(priv->new_tuning, "%d|%09d|%d|%d|%d|%d", priv->card, channel->freq, channel->inv, channel->srate, - channel->cr, channel->mod); - break; -#ifdef DVB_ATSC - case TUNER_ATSC: - sprintf(priv->new_tuning, "%d|%09d|%d", priv->card, channel->freq, channel->mod); - break; -#endif - } - - - - if(strcmp(priv->prev_tuning, priv->new_tuning)) - { - mp_msg(MSGT_DEMUX, MSGL_V, "DIFFERENT TUNING THAN THE PREVIOUS: %s -> %s\n", priv->prev_tuning, priv->new_tuning); - strcpy(priv->prev_tuning, priv->new_tuning); - do_tuning = 1; - } - else - { - mp_msg(MSGT_DEMUX, MSGL_V, "SAME TUNING PARAMETERS, NO TUNING\n"); - do_tuning = 0; - } - - stream->eof=1; - stream_reset(stream); - - - if(do_tuning) - if (! dvb_tune(priv, channel->freq, channel->pol, channel->srate, channel->diseqc, channel->tone, - channel->inv, channel->mod, channel->gi, channel->trans, channel->bw, channel->cr, channel->cr_lp, channel->hier, priv->timeout)) - return 0; - - - priv->is_on = 1; - - //sets demux filters and restart the stream - for(i = 0; i < channel->pids_cnt; i++) - { - if(! dvb_set_ts_filt(priv->demux_fds[i], channel->pids[i], DMX_PES_OTHER)) - return 0; - } - - return 1; -} - - - -int dvb_step_channel(dvb_priv_t *priv, int dir) -{ - int new_current; - dvb_channels_list *list; - - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_STEP_CHANNEL dir %d\n", dir); - - if(priv == NULL) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: NULL priv_ptr, quit\n"); - return 0; - } - - list = priv->list; - if(list == NULL) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: NULL list_ptr, quit\n"); - return 0; - } - - new_current = (list->NUM_CHANNELS + list->current + (dir == DVB_CHANNEL_HIGHER ? 1 : -1)) % list->NUM_CHANNELS; - - return dvb_set_channel(priv, priv->card, new_current); -} - - - - -extern char *get_path(const char *); - -static void dvbin_close(stream_t *stream) -{ - int i; - dvb_priv_t *priv = (dvb_priv_t *) stream->priv; - - for(i = priv->demux_fds_cnt-1; i >= 0; i--) - { - priv->demux_fds_cnt--; - mp_msg(MSGT_DEMUX, MSGL_V, "DVBIN_CLOSE, close(%d), fd=%d, COUNT=%d\n", i, priv->demux_fds[i], priv->demux_fds_cnt); - close(priv->demux_fds[i]); - } - close(priv->dvr_fd); - - close(priv->fe_fd); -#ifdef HAVE_DVB - close(priv->sec_fd); -#endif - - priv->is_on = 0; - dvb_config->priv = NULL; -} - - -static int dvb_streaming_start(dvb_priv_t *priv, struct stream_priv_s *opts, int tuner_type, char *progname) -{ - int i; - dvb_channel_t *channel = NULL; - stream_t *stream = (stream_t*) priv->stream; - - mp_msg(MSGT_DEMUX, MSGL_V, "\r\ndvb_streaming_start(PROG: %s, CARD: %d, VID: %d, AID: %d, TYPE: %s, FILE: %s)\r\n", - opts->prog, opts->card, opts->vid, opts->aid, opts->type, opts->file); - - priv->is_on = 0; - - i = 0; - while((channel == NULL) && i < priv->list->NUM_CHANNELS) - { - if(! strcmp(priv->list->channels[i].name, progname)) - channel = &(priv->list->channels[i]); - - i++; - } - - if(channel != NULL) - { - priv->list->current = i-1; - mp_msg(MSGT_DEMUX, MSGL_V, "PROGRAM NUMBER %d: name=%s, freq=%u\n", i-1, channel->name, channel->freq); - } - else - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "\n\nDVBIN: no such channel \"%s\"\n\n", progname); - return 0; - } - - - strcpy(priv->prev_tuning, ""); - if(!dvb_set_channel(priv, priv->card, priv->list->current)) - { - mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR, COULDN'T SET CHANNEL %i: ", priv->list->current); - dvbin_close(stream); - return 0; - } - - mp_msg(MSGT_DEMUX, MSGL_V, "SUCCESSFUL EXIT from dvb_streaming_start\n"); - - return 1; -} - - - - -static int dvb_open(stream_t *stream, int mode, void *opts, int *file_format) -{ - // I don't force the file format bacause, although it's almost always TS, - // there are some providers that stream an IP multicast with M$ Mpeg4 inside - struct stream_priv_s* p = (struct stream_priv_s*)opts; - dvb_priv_t *priv; - char *progname; - int tuner_type = 0; - - - if(mode != STREAM_READ) - return STREAM_UNSUPORTED; - - stream->priv = (dvb_priv_t*) malloc(sizeof(dvb_priv_t)); - if(stream->priv == NULL) - return STREAM_ERROR; - - priv = (dvb_priv_t *)stream->priv; - priv->stream = stream; - dvb_config = dvb_get_config(); - if(dvb_config == NULL) - { - free(priv); - mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB CONFIGURATION IS EMPTY, exit\n"); - return STREAM_ERROR; - } - dvb_config->priv = priv; - priv->config = dvb_config; - - if(p->card < 1 || p->card > priv->config->count) - { - free(priv); - mp_msg(MSGT_DEMUX, MSGL_ERR, "NO CONFIGURATION FOUND FOR CARD N. %d, exit\n", p->card); - return STREAM_ERROR; - } - priv->card = p->card - 1; - priv->timeout = p->timeout; - - tuner_type = priv->config->cards[priv->card].type; - - if(tuner_type == 0) - { - free(priv); - mp_msg(MSGT_DEMUX, MSGL_V, "OPEN_DVB: UNKNOWN OR UNDETECTABLE TUNER TYPE, EXIT\n"); - return STREAM_ERROR; - } - - - priv->tuner_type = tuner_type; - - mp_msg(MSGT_DEMUX, MSGL_V, "OPEN_DVB: prog=%s, card=%d, type=%d, vid=%d, aid=%d\n", - p->prog, priv->card+1, priv->tuner_type, p->vid, p->aid); - - priv->list = priv->config->cards[priv->card].list; - - if((! strcmp(p->prog, "")) && (priv->list != NULL)) - progname = priv->list->channels[0].name; - else - progname = p->prog; - - - if(! dvb_streaming_start(priv, p, tuner_type, progname)) - { - free(stream->priv); - stream->priv = NULL; - return STREAM_ERROR; - } - - stream->type = STREAMTYPE_DVB; - stream->fill_buffer = dvb_streaming_read; - stream->close = dvbin_close; - m_struct_free(&stream_opts, opts); - - *file_format = DEMUXER_TYPE_MPEG_TS; - - return STREAM_OK; -} - -#define MAX_CARDS 4 -dvb_config_t *dvb_get_config(void) -{ - int i, fd, type, size; - char filename[30], *conf_file, *name; - dvb_channels_list *list; - dvb_card_config_t *cards = NULL, *tmp; - dvb_config_t *conf = NULL; - - if(dvb_config != NULL) - return dvb_config; - - conf = (dvb_config_t*) malloc(sizeof(dvb_config_t)); - if(conf == NULL) - return NULL; - - conf->priv = NULL; - conf->count = 0; - conf->cards = NULL; - for(i=0; i<MAX_CARDS; i++) - { - sprintf(filename, "/dev/dvb/adapter%d/frontend0", i); - fd = open(filename, O_RDWR | O_NONBLOCK); - if(fd < 0) - { - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_CONFIG, can't open device %s, skipping\n", filename); - continue; - } - - type = dvb_get_tuner_type(fd); - close(fd); - if(type != TUNER_SAT && type != TUNER_TER && type != TUNER_CBL && type != TUNER_ATSC) - { - mp_msg(MSGT_DEMUX, MSGL_V, "DVB_CONFIG, can't detect tuner type of card %d, skipping\n", i); - continue; - } - - switch(type) - { - case TUNER_TER: - conf_file = get_path("channels.conf.ter"); - break; - case TUNER_CBL: - conf_file = get_path("channels.conf.cbl"); - break; - case TUNER_SAT: - conf_file = get_path("channels.conf.sat"); - break; - case TUNER_ATSC: - conf_file = get_path("channels.conf.atsc"); - break; - } - - if((access(conf_file, F_OK | R_OK) != 0)) - conf_file = get_path("channels.conf"); - - list = dvb_get_channels(conf_file, type); - if(list == NULL) - continue; - - size = sizeof(dvb_card_config_t) * (conf->count + 1); - tmp = realloc(conf->cards, size); - - if(tmp == NULL) - { - fprintf(stderr, "DVB_CONFIG, can't realloc %d bytes, skipping\n", size); - continue; - } - cards = tmp; - - name = (char*) malloc(20); - if(name==NULL) - { - fprintf(stderr, "DVB_CONFIG, can't realloc 20 bytes, skipping\n"); - continue; - } - - conf->cards = cards; - conf->cards[conf->count].devno = i; - conf->cards[conf->count].list = list; - conf->cards[conf->count].type = type; - sprintf(name, "DVB-%c card n. %d", type==TUNER_TER ? 'T' : (type==TUNER_CBL ? 'C' : 'S'), conf->count+1); - conf->cards[conf->count].name = name; - conf->count++; - } - - if(conf->count == 0) - { - free(conf); - conf = NULL; - } - - dvb_config = conf; - return conf; -} - - - -stream_info_t stream_info_dvb = { - "Dvb Input", - "dvbin", - "Nico", - "based on the code from ??? (probably Arpi)", - dvb_open, - { "dvb", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/dvbin.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* Imported from the dvbstream project - * - * Modified for use with MPlayer, for details see the changelog at - * http://svn.mplayerhq.hu/mplayer/trunk/ - * $Id$ - */ - -#ifndef DVBIN_H -#define DVBIN_H - -#include "stream.h" - -#define SLOF (11700*1000UL) -#define LOF1 (9750*1000UL) -#define LOF2 (10600*1000UL) - -#ifdef HAVE_DVB_HEAD - #include <linux/dvb/dmx.h> - #include <linux/dvb/frontend.h> - #include <linux/dvb/version.h> -#else - #include <ost/dmx.h> - #include <ost/sec.h> - #include <ost/frontend.h> - #define fe_status_t FrontendStatus - #define fe_spectral_inversion_t SpectralInversion - #define fe_modulation_t Modulation - #define fe_code_rate_t CodeRate - #define fe_transmit_mode_t TransmitMode - #define fe_guard_interval_t GuardInterval - #define fe_bandwidth_t BandWidth - #define fe_hierarchy_t Hierarchy - #define fe_sec_voltage_t SecVoltage - #define dmx_pes_filter_params dmxPesFilterParams - #define dmx_sct_filter_params dmxSctFilterParams - #define dmx_pes_type_t dmxPesType_t -#endif - -#undef DVB_ATSC -#if defined(DVB_API_VERSION_MINOR) -#if DVB_API_VERSION == 3 && DVB_API_VERSION_MINOR >= 1 -#define DVB_ATSC 1 -#endif -#endif - - -#define DVB_CHANNEL_LOWER -1 -#define DVB_CHANNEL_HIGHER 1 - -#include "inttypes.h" - -#ifndef DMX_FILTER_SIZE -#define DMX_FILTER_SIZE 16 -#endif - -typedef struct { - char *name; - int freq, srate, diseqc, tone; - char pol; - int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt; - fe_spectral_inversion_t inv; - fe_modulation_t mod; - fe_transmit_mode_t trans; - fe_bandwidth_t bw; - fe_guard_interval_t gi; - fe_code_rate_t cr, cr_lp; - fe_hierarchy_t hier; -} dvb_channel_t; - - -typedef struct { - uint16_t NUM_CHANNELS; - uint16_t current; - dvb_channel_t *channels; -} dvb_channels_list; - -typedef struct { - int type; - dvb_channels_list *list; - char *name; - int devno; -} dvb_card_config_t; - -typedef struct { - int count; - dvb_card_config_t *cards; - void *priv; -} dvb_config_t; - - -typedef struct { - int card; - int fe_fd; - int sec_fd; - int demux_fd[3], demux_fds[DMX_FILTER_SIZE], demux_fds_cnt; - int dvr_fd; - - dvb_config_t *config; - dvb_channels_list *list; - int tuner_type; - int is_on; - stream_t *stream; - char new_tuning[256], prev_tuning[256]; - int retry; - int timeout; -} dvb_priv_t; - - -#define TUNER_SAT 1 -#define TUNER_TER 2 -#define TUNER_CBL 3 -#define TUNER_ATSC 4 - -extern int dvb_step_channel(dvb_priv_t *, int); -extern int dvb_set_channel(dvb_priv_t *, int, int); -extern dvb_config_t *dvb_get_config(void); - -#endif
--- a/libmpdemux/dvdnav_stream.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,396 +0,0 @@ -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include "mp_msg.h" -#include "osdep/timer.h" -#include "input/input.h" -#include "stream.h" -#include "demuxer.h" -#include "dvdnav_stream.h" -#include "libvo/video_out.h" -#include "spudec.h" -#include "m_option.h" -#include "m_struct.h" -#include "help_mp.h" - -extern char *dvd_device; -extern char *audio_lang, *dvdsub_lang; - -static struct stream_priv_s { - int track; - char* device; -} stream_priv_dflts = { - 1, - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - {"filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, - {"hostname", ST_OFF(track), CONF_TYPE_INT, 0, 0, 0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "dvd", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -int dvd_nav_skip_opening=0; /* skip opening stalls? */ -int osd_show_dvd_nav_delay=0; /* count down for dvd nav text on OSD */ -char dvd_nav_text[50]; /* for reporting stuff to OSD */ -int osd_show_dvd_nav_highlight; /* show highlight area */ -int osd_show_dvd_nav_sx; /* start x .... */ -int osd_show_dvd_nav_ex; -int osd_show_dvd_nav_sy; -int osd_show_dvd_nav_ey; -int dvd_nav_still=0; /* are we on a still picture? */ - -dvdnav_priv_t * new_dvdnav_stream(char * filename) { - char * title_str; - dvdnav_priv_t *dvdnav_priv; - - if (!filename) - return NULL; - - if (!(dvdnav_priv=calloc(1,sizeof(*dvdnav_priv)))) - return NULL; - - if (!(dvdnav_priv->filename=strdup(filename))) { - free(dvdnav_priv); - return NULL; - } - - if(dvdnav_open(&(dvdnav_priv->dvdnav),dvdnav_priv->filename)!=DVDNAV_STATUS_OK) - { - free(dvdnav_priv->filename); - free(dvdnav_priv); - return NULL; - } - - if (!dvdnav_priv->dvdnav) { - free(dvdnav_priv); - return NULL; - } - - if(1) //from vlc: if not used dvdnav from cvs will fail - { - int len, event; - char buf[2048]; - - dvdnav_get_next_block(dvdnav_priv->dvdnav,buf,&event,&len); - } - - /* turn on dvdnav caching */ - dvdnav_set_readahead_flag(dvdnav_priv->dvdnav, 0); - if(dvdnav_set_PGC_positioning_flag(dvdnav_priv->dvdnav, 1) != DVDNAV_STATUS_OK) - mp_msg(MSGT_OPEN,MSGL_ERR,"stream_dvdnav, failed to set PGC positioning\n"); -#if 1 - /* report the title?! */ - if (dvdnav_get_title_string(dvdnav_priv->dvdnav,&title_str)==DVDNAV_STATUS_OK) { - mp_msg(MSGT_IDENTIFY, MSGL_INFO,"Title: '%s'\n",title_str); - } -#endif - - //dvdnav_event_clear(dvdnav_priv); - - return dvdnav_priv; -} - -int dvdnav_stream_reset(dvdnav_priv_t * dvdnav_priv) { - if (!dvdnav_priv) return 0; - -// if (dvdnav_reset(dvdnav_priv->dvdnav)!=DVDNAV_STATUS_OK) - return 0; - - dvdnav_priv->started=0; - - return 1; -} - -int dvdnav_stream_sleeping(dvdnav_priv_t * dvdnav_priv) { - unsigned int now; - - if (!dvdnav_priv) return 0; - - if(dvdnav_priv->sleeping) - { - now=GetTimer(); - while(dvdnav_priv->sleeping>1 || now<dvdnav_priv->sleep_until) { -// printf("%s %u<%u\n",__FUNCTION__,now,dvdnav_priv->sleep_until); -// usec_sleep(1000); /* 1ms granularity */ - return 1; - } - dvdnav_still_skip(dvdnav_priv->dvdnav); // continue past... - dvdnav_priv->sleeping=0; - mp_msg(MSGT_OPEN,MSGL_V, "%s: woke up!\n",__FUNCTION__); - } - dvd_nav_still=0; - mp_msg(MSGT_OPEN,MSGL_V, "%s: active\n",__FUNCTION__); - return 0; -} - -void dvdnav_stream_sleep(dvdnav_priv_t * dvdnav_priv, int seconds) { - if (!dvdnav_priv) return; - - if (!dvdnav_priv->started) return; - - dvdnav_priv->sleeping=0; - switch (seconds) { - case 0: - return; - case 0xff: - mp_msg(MSGT_OPEN,MSGL_V, "Sleeping indefinately\n" ); - dvdnav_priv->sleeping=2; - break; - default: - mp_msg(MSGT_OPEN,MSGL_V, "Sleeping %d sec(s)\n", seconds ); - dvdnav_priv->sleep_until = GetTimer();// + seconds*1000000; - dvdnav_priv->sleeping=1; - break; - } - //if (dvdnav_priv->started) dvd_nav_still=1; -} - -void dvdnav_stream_add_event(dvdnav_priv_t* dvdnav_priv, int event, unsigned char *buf, int len) { - //printf("%s: %d\n",__FUNCTION__,event); - - dvdnav_event_t * dvdnav_event; - mp_cmd_t * cmd; - - if (!dvdnav_priv->started) return; - - if (!(dvdnav_event=calloc(1,sizeof(*dvdnav_event)))) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: dvdnav_event: out of memory!\n",__FUNCTION__); - return; - } - dvdnav_event->event=event; - dvdnav_event->details=calloc(1,len); - memcpy(dvdnav_event->details,buf,len); - dvdnav_event->len=len; - - if (!(cmd = calloc(1,sizeof(*cmd)))) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: mp_cmd_t: out of memory!\n",__FUNCTION__); - free(dvdnav_event->details); - free(dvdnav_event); - return; - } - cmd->id=MP_CMD_DVDNAV_EVENT; // S+event; - cmd->name=strdup("dvdnav_event"); // FIXME: do I really need a 'name'? - cmd->nargs=1; - cmd->args[0].v.v=dvdnav_event; -} - -int dvdnav_stream_read(dvdnav_priv_t * dvdnav_priv, unsigned char *buf, int *len) { - int event = DVDNAV_NOP; - - if (!len) return -1; - *len=-1; - if (!dvdnav_priv) return -1; - if (!buf) return -1; - - if (dvd_nav_still) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: got a stream_read while I should be asleep!\n",__FUNCTION__); - *len=0; - return -1; - } - - if (dvdnav_get_next_block(dvdnav_priv->dvdnav,buf,&event,len)!=DVDNAV_STATUS_OK) { - mp_msg(MSGT_OPEN,MSGL_V, "Error getting next block from DVD %d (%s)\n",event, dvdnav_err_to_string(dvdnav_priv->dvdnav) ); - *len=-1; - } - else if (event!=DVDNAV_BLOCK_OK) { - - // need to handle certain events internally (like skipping stills) - switch (event) { - case DVDNAV_STILL_FRAME: { - dvdnav_still_event_t *still_event = (dvdnav_still_event_t*)(buf); - //if (dvdnav_priv->started) dvd_nav_still=1; - //else - dvdnav_still_skip(dvdnav_priv->dvdnav); // don't let dvdnav stall on this image - - break; - case DVDNAV_WAIT: - dvdnav_wait_skip(dvdnav_priv->dvdnav); - break; - } - } - - // got an event, repeat the read - dvdnav_stream_add_event(dvdnav_priv,event,buf,*len); - *len=0; - } -// printf("%s: got %d\n",__FUNCTION__,*len); - return event; -} - -void dvdnav_stream_fullstart(dvdnav_priv_t * dvdnav_priv) { - if (dvdnav_priv && !dvdnav_priv->started) { - dvdnav_stream_reset(dvdnav_priv); - dvdnav_priv->started=1; - } -} - -unsigned int * dvdnav_stream_get_palette(dvdnav_priv_t * dvdnav_priv) { - if (!dvdnav_priv) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv\n",__FUNCTION__); - return NULL; - } - if (!dvdnav_priv->dvdnav) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv->dvdnav\n",__FUNCTION__); - return NULL; - } - #if 0 - if (!dvdnav_priv->dvdnav->vm) { - mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv->dvdnav->vm\n",__FUNCTION__); - return NULL; - } - if (!dvdnav_priv->dvdnav->vm->state.pgc) { - printf("%s: NULL dvdnav_priv->dvdnav->vm->state.pgc\n",__FUNCTION__); - return NULL; - } - return dvdnav_priv->dvdnav->vm->state.pgc->palette; - #endif -} - -static void update_title_len(stream_t *stream) { - dvdnav_priv_t *priv = stream->priv; - dvdnav_status_t status; - uint32_t pos = 0, len = 0; - - status = dvdnav_get_position(priv->dvdnav, &pos, &len); - if(status == DVDNAV_STATUS_OK && len) - stream->end_pos = (off_t) len * 2048; -} - - -static int seek(stream_t *s, off_t newpos) { -uint32_t pos = 0, len = 0, sector = 0; -dvdnav_priv_t *priv = s->priv; - - if(newpos==0) { - if(dvdnav_stream_reset(priv->dvdnav)) - s->pos=0; - } - else { - if(s->end_pos && newpos > s->end_pos) - newpos = s->end_pos; - sector = newpos / 2048ULL; - if(dvdnav_sector_search(priv->dvdnav, (uint64_t) sector, SEEK_SET) != DVDNAV_STATUS_OK) - goto fail; - - s->pos = newpos; - } - - return 1; - -fail: - mp_msg(MSGT_STREAM,MSGL_INFO,"dvdnav_stream, seeking to %"PRIu64" failed: %s\n", newpos, dvdnav_err_to_string(priv->dvdnav)); - - return 1; -} - -static void stream_dvdnav_close(stream_t *s) { - dvdnav_priv_t *priv = s->priv; - dvdnav_close(priv->dvdnav); - priv->dvdnav = NULL; - free(priv); -} - - -static int fill_buffer(stream_t *s, char *but, int len) -{ - int event; - dvdnav_priv_t* dvdnav_priv=s->priv; - len=0; - if(!s->end_pos) - update_title_len(s); - while(!len) /* grab all event until DVDNAV_BLOCK_OK (len=2048), DVDNAV_STOP or DVDNAV_STILL_FRAME */ - { - if(-1==(event=dvdnav_stream_read(dvdnav_priv, s->buffer, &len)) || len==-1) - { - mp_msg(MSGT_CPLAYER,MSGL_ERR, "DVDNAV stream read error!\n"); - return 0; - } - switch (event) { - case DVDNAV_STOP: return len; - case DVDNAV_BLOCK_OK: return len; -#if 0 - case DVDNAV_STILL_FRAME: { - if(!dvdnav_priv->stillok) dvdnav_priv->stillcounter++; - dvdnav_priv->lockstillcounter++; - return len; - break; - } - - case DVDNAV_WAIT: { - if(dvdnav_priv->waitcounter>=DVDNAV_MAX_WAIT_FRAME) return len; - break; - } -#endif - } -#if 0 - if(dvdnav_priv->event.cell_really_change && - dvdnav_priv->started && - !dvdnav_priv->vts_domain) - return len; -#endif - } - mp_msg(MSGT_STREAM,MSGL_DBG2,"DVDNAV fill_buffer len: %d\n",len); - return len; -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - struct stream_priv_s* p = (struct stream_priv_s*)opts; - char *filename; - int event,len,tmplen=0; - uint32_t pos, l2; - dvdnav_priv_t *dvdnav_priv; - dvdnav_status_t status; - - //mp_msg(MSGT_OPEN,MSGL_INFO,"URL: %s\n", filename); - - if(p->device) filename = p->device; - else if(dvd_device) filename= dvd_device; - else filename = DEFAULT_DVD_DEVICE; - if(!(dvdnav_priv=new_dvdnav_stream(filename))) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,filename); - return STREAM_UNSUPORTED; - } - - if(dvdnav_title_play(dvdnav_priv->dvdnav, p->track) != DVDNAV_STATUS_OK) { - mp_msg(MSGT_OPEN,MSGL_FATAL,"dvdnav_stream, couldn't select title %d, error '%s'\n", p->track, dvdnav_err_to_string(dvdnav_priv->dvdnav)); - return STREAM_UNSUPORTED; - } - - stream->sector_size = 2048; - stream->flags = STREAM_READ | STREAM_SEEK; - stream->fill_buffer = fill_buffer; - stream->seek = seek; - stream->close = stream_dvdnav_close; - stream->type = STREAMTYPE_DVDNAV; - stream->priv=(void*)dvdnav_priv; - *file_format = DEMUXER_TYPE_MPEG_PS; - - update_title_len(stream); - if(!stream->pos) - mp_msg(MSGT_OPEN,MSGL_ERR, "INIT ERROR: %d, couldn't get init pos %s\r\n", status, dvdnav_err_to_string(dvdnav_priv->dvdnav)); - - return STREAM_OK; -} - -stream_info_t stream_info_dvdnav = { - "DVDNAV stream", - "null", - "", - "", - open_s, - { "dvdnav", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/dvdnav_stream.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -#ifndef _MPLAYER_DVDNAV_STREAM_H -#define _MPLAYER_DVDNAV_STREAM_H - -#include <dvdnav.h> - -typedef struct { - int event; /* event number fromd dvdnav_events.h */ - void * details; /* event details */ - int len; /* bytes in details */ -} dvdnav_event_t; - -typedef struct { - dvdnav_t * dvdnav; /* handle to libdvdnav stuff */ - char * filename; /* path */ - int ignore_timers; /* should timers be skipped? */ - int sleeping; /* are we sleeping? */ - unsigned int sleep_until; /* timer */ - int started; /* Has mplayer initialization finished? */ - unsigned char prebuf[STREAM_BUFFER_SIZE]; /* prefill buffer */ - int prelen; /* length of prefill buffer */ -} dvdnav_priv_t; - -extern int dvd_nav_still; -extern int dvd_nav_skip_opening; -extern char dvd_nav_text[50]; -extern int osd_show_dvd_nav_delay; -extern int osd_show_dvd_nav_highlight; -extern int osd_show_dvd_nav_sx; -extern int osd_show_dvd_nav_ex; -extern int osd_show_dvd_nav_sy; -extern int osd_show_dvd_nav_ey; - -dvdnav_priv_t * new_dvdnav_stream(char * filename); -int dvdnav_stream_reset(dvdnav_priv_t * dvdnav_priv); -void free_dvdnav_stream(dvdnav_priv_t * dvdnav_priv); - -void dvdnav_stream_ignore_timers(dvdnav_priv_t * dvdnav_priv, int ignore); -int dvdnav_stream_read(dvdnav_priv_t * dvdnav_priv, unsigned char *buf, int *len); - -void dvdnav_stream_sleep(dvdnav_priv_t *dvdnav_priv, int seconds); -int dvdnav_stream_sleeping(dvdnav_priv_t * dvdnav_priv); - -void dvdnav_stream_fullstart(dvdnav_priv_t *dvdnav_priv); -unsigned int * dvdnav_stream_get_palette(dvdnav_priv_t * dvdnav_priv); - -#endif
--- a/libmpdemux/freesdp/common.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@suidzer0.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 -*/ - -/** - * @file common.c - * - * @short Implementation of routines common to parse and formatting - * modules . - * - * This file implements the routines that operate over data structures - * that are used in both the parse and formatting modules. - **/ - -#include "priv.h" -#include "common.h" - -static void -safe_free (void *ptr) -{ - if (ptr) - free (ptr); -} - -fsdp_description_t * -fsdp_description_new (void) -{ - fsdp_description_t *result = malloc (sizeof (fsdp_description_t)); - - result->version = 0; - result->o_username = result->o_session_id = - result->o_announcement_version = NULL; - result->o_network_type = FSDP_NETWORK_TYPE_UNDEFINED; - result->o_address_type = FSDP_ADDRESS_TYPE_UNDEFINED; - result->o_address = NULL; - result->s_name = NULL; - result->i_information = NULL; - result->u_uri = NULL; - result->emails = NULL; - result->emails_count = 0; - result->phones = NULL; - result->phones_count = 0; - /* At first, there is no session-level definition for these - parameters */ - result->c_network_type = FSDP_NETWORK_TYPE_UNDEFINED; - result->c_address_type = FSDP_ADDRESS_TYPE_UNDEFINED; - result->c_address.address = NULL; - /* there is no session-level definition for these parameters */ - result->bw_modifiers = NULL; - result->bw_modifiers_count = 0; - result->time_periods = NULL; - result->time_periods_count = 0; - result->timezone_adj = NULL; - result->k_encryption_method = FSDP_ENCRYPTION_METHOD_UNDEFINED; - result->k_encryption_content = NULL; - /* Default/undefined values for attributes */ - result->a_category = result->a_keywords = result->a_tool = NULL; - result->a_type = FSDP_SESSION_TYPE_UNDEFINED; - result->a_sendrecv_mode = FSDP_SENDRECV_UNDEFINED; - result->a_charset = NULL; - result->a_sdplangs = result->a_langs = NULL; - result->a_controls = NULL; - result->a_range = NULL; - result->a_rtpmaps = NULL; - result->a_rtpmaps_count = 0; - result->a_sdplangs_count = 0; - result->a_langs_count = 0; - result->a_controls_count = 0; - result->unidentified_attributes = NULL; - result->unidentified_attributes_count = 0; - result->media_announcements = NULL; - result->media_announcements_count = 0; - - return result; -} - -void -fsdp_description_delete (fsdp_description_t * dsc) -{ - fsdp_description_recycle (dsc); - safe_free (dsc); -} - -void -fsdp_description_recycle (fsdp_description_t * dsc) -{ - /* Recursively free all strings and arrays */ - unsigned int i, j; - - if (!dsc) - return; - - safe_free (dsc->o_username); - safe_free (dsc->o_session_id); - safe_free (dsc->o_announcement_version); - safe_free (dsc->o_address); - safe_free (dsc->s_name); - safe_free (dsc->i_information); - safe_free (dsc->u_uri); - - for (i = 0; i < dsc->emails_count; i++) - safe_free ((char *) dsc->emails[i]); - safe_free (dsc->emails); - - for (i = 0; i < dsc->phones_count; i++) - safe_free ((char *) dsc->phones[i]); - safe_free (dsc->phones); - - safe_free (dsc->c_address.address); - - for (i = 0; i < dsc->bw_modifiers_count; i++) - safe_free (dsc->bw_modifiers[i].b_unknown_bw_modt); - safe_free (dsc->bw_modifiers); - - for (i = 0; i < dsc->time_periods_count; i++) - { - for (j = 0; j < dsc->time_periods[i]->repeats_count; j++) - { - safe_free (dsc->time_periods[i]->repeats[j]->offsets); - safe_free (dsc->time_periods[i]->repeats[j]); - } - safe_free (dsc->time_periods[i]->repeats); - safe_free (dsc->time_periods[i]); - } - safe_free (dsc->time_periods); - - safe_free (dsc->timezone_adj); - safe_free (dsc->a_category); - safe_free (dsc->a_keywords); - safe_free (dsc->a_tool); - - for (i = 0; i < dsc->a_rtpmaps_count; i++) - safe_free (dsc->a_rtpmaps[i]); - safe_free (dsc->a_rtpmaps); - - safe_free (dsc->a_charset); - - for (i = 0; i < dsc->a_sdplangs_count; i++) - safe_free (dsc->a_sdplangs[i]); - safe_free (dsc->a_sdplangs); - - for (i = 0; i < dsc->a_langs_count; i++) - safe_free (dsc->a_langs[i]); - safe_free (dsc->a_langs); - - for (i = 0; i < dsc->a_controls_count; i++) - safe_free (dsc->a_controls[i]); - safe_free (dsc->a_controls); - - safe_free (dsc->a_range); - - for (i = 0; i < dsc->media_announcements_count; i++) - { - for (j = 0; j < dsc->media_announcements[i]->formats_count; j++) - safe_free (dsc->media_announcements[i]->formats[j]); - safe_free (dsc->media_announcements[i]->formats); - safe_free (dsc->media_announcements[i]->i_title); - - for (j = 0; j < dsc->media_announcements[i]->bw_modifiers_count; j++) - { - if (FSDP_BW_MOD_TYPE_UNKNOWN == - dsc->media_announcements[i]->bw_modifiers[j].b_mod_type) - safe_free (dsc->media_announcements[i]->bw_modifiers[j]. - b_unknown_bw_modt); - } - safe_free (dsc->media_announcements[i]->bw_modifiers); - - safe_free (dsc->media_announcements[i]->k_encryption_content); - - for (j = 0; j < dsc->media_announcements[i]->a_rtpmaps_count; j++) - { - safe_free (dsc->media_announcements[i]->a_rtpmaps[j]->pt); - safe_free (dsc->media_announcements[i]->a_rtpmaps[j]-> - encoding_name); - safe_free (dsc->media_announcements[i]->a_rtpmaps[j]->parameters); - safe_free (dsc->media_announcements[i]->a_rtpmaps[j]); - } - safe_free (dsc->media_announcements[i]->a_rtpmaps); - - for (j = 0; j < dsc->media_announcements[i]->a_sdplangs_count; j++) - safe_free (dsc->media_announcements[i]->a_sdplangs[j]); - safe_free (dsc->media_announcements[i]->a_sdplangs); - - for (j = 0; j < dsc->media_announcements[i]->a_langs_count; j++) - safe_free (dsc->media_announcements[i]->a_langs[j]); - safe_free (dsc->media_announcements[i]->a_langs); - - for (j = 0; j < dsc->media_announcements[i]->a_controls_count; j++) - safe_free (dsc->media_announcements[i]->a_controls[j]); - safe_free (dsc->media_announcements[i]->a_controls); - - for (j = 0; j < dsc->media_announcements[i]->a_fmtps_count; j++) - safe_free (dsc->media_announcements[i]->a_fmtps[j]); - safe_free (dsc->media_announcements[i]->a_fmtps); - - for (j = 0; - j < dsc->media_announcements[i]->unidentified_attributes_count; j++) - safe_free (dsc->media_announcements[i]->unidentified_attributes[j]); - safe_free (dsc->media_announcements[i]->unidentified_attributes); - safe_free (dsc->media_announcements[i]); - } - safe_free (dsc->media_announcements); - - /* This prevents the user to make the library crash when incorrectly - using recycled but not rebuilt descriptions */ - dsc->emails_count = 0; - dsc->phones_count = 0; - dsc->bw_modifiers_count = 0; - dsc->time_periods_count = 0; - dsc->media_announcements_count = 0; -}
--- a/libmpdemux/freesdp/common.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,352 +0,0 @@ -/* - This file is part of FreeSDP. - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 -*/ - -/** - * @file common.h - * @ingroup common - * @short Public header common for both parsing and formatting modules. - **/ - -#ifndef FSDP_COMMON_H -#define FSDP_COMMON_H - -/* Macros to avoid name mangling when compiling with a C++ compiler */ -#ifdef __cplusplus -# define BEGIN_C_DECLS extern "C" { -# define END_C_DECLS } -#else /* !__cplusplus */ -# define BEGIN_C_DECLS -# define END_C_DECLS -#endif /* __cplusplus */ - -#include <sys/time.h> -#include <time.h> - -BEGIN_C_DECLS -/** - * @defgroup common FreeSDP Common Facilities - * - * Data types and routines common for both parsing and formatting - * modules. - **/ -/** @addtogroup common */ -/*@{*/ -/** - * @enum fsdp_error_t freesdp/common.h - * @short Error codes in the FreeSDP library. - * - * There is a FSDPE_MISSING_XXXX for each mandatory line, as - * FSDPE_MISSING_OWNER. This kind of error is reported when a - * mandatory description line, such as the owner line, is not found - * where it should be in the SDP description. There are also several - * error codes like FSDPE_INVALID_XXXX. These are returned when there - * is a recognized line in the parsed description that violates the - * SDP syntax or gives wrong parameters, for instance "c=foo bar", - * which would cause a FSDPE_INVALID_CONNECTION error code to be - * returned. - **/ -typedef enum -{ - FSDPE_OK = 0, - FSDPE_ILLEGAL_CHARACTER, /**< Misplaced '\r', '\n' or '\0' */ - FSDPE_MISSING_VERSION, /**< The first line is not like - v=... */ - FSDPE_INVALID_VERSION, /**< Parse error in version line, - perhaps, the version specified in - v=... is not valid for FreeSDP */ - FSDPE_MISSING_OWNER, /**< No owner line found in its - place */ - FSDPE_INVALID_OWNER, /**< Parse error in owner line */ - FSDPE_MISSING_NAME, /**< No session name found in its - place */ - FSDPE_EMPTY_NAME, /**< Empty session name line */ - - FSDPE_INVALID_CONNECTION, /**< Syntax error in connection - line */ - - FSDPE_INVALID_CONNECTION_ADDRTYPE, /**< Unrecognized address type in - connection line */ - FSDPE_INVALID_CONNECTION_NETTYPE, /**< Unrecognized network type in - connection line */ - FSDPE_INVALID_BANDWIDTH, /**< Parse error in bandwidth - line */ - FSDPE_MISSING_TIME, /**< No time period has been given - for the session */ - FSDPE_INVALID_TIME, /**< Parse error in time line */ - FSDPE_INVALID_REPEAT, /**< Parse error in repeat time - line */ - FSDPE_INVALID_TIMEZONE, /**< Parse error in timezone line */ - FSDPE_INVALID_ENCRYPTION_METHOD, /**< Unknown encryption method */ - FSDPE_INVALID_ATTRIBUTE, /**< Syntax error in an attribute - line */ - - FSDPE_INVALID_ATTRIBUTE_RTPMAP,/**< Parse error in a=rtpmap:... line */ - FSDPE_INVALID_SESSION_TYPE, /**< An unknown session type has been - specified in a `type:' - session-level attribute */ - - FSDPE_INVALID_MEDIA, /**< Parse error in media line */ - FSDPE_UNKNOWN_MEDIA_TYPE, /**< Unknown media type in media - line */ - - FSDPE_UNKNOWN_MEDIA_TRANSPORT, /**< A media transport has been - specified that is unknown */ - - FSDPE_OVERFILLED, /**< extra unknown lines are at the - end of the description */ - FSDPE_INVALID_LINE, /**< a line unknown to FreeSDP has been - found */ - FSDPE_MISSING_CONNECTION_INFO, /**< No connection information has - been provided for the whole - session nor one or more media */ - FSDPE_INVALID_INDEX, - /* FSDPE_MAXSIZE, description does not fit requested maximun size */ - FSDPE_INTERNAL_ERROR, - - FSDPE_INVALID_PARAMETER, /**< Some parameter of the called - FreeSDP routine has been given an - invalid value. This includes - cases such as NULL pointers. */ - FSDPE_BUFFER_OVERFLOW -} fsdp_error_t; - -/** - * @short Type of network - * - * Initially, SDP defines "Internet". New network types may be - * registered with IANA. However, the number of types is expected to - * be small and rarely extended. In addition, every new network type - * requires at least one new address type. - **/ -typedef enum -{ - FSDP_NETWORK_TYPE_UNDEFINED, /**< Not provided */ - FSDP_NETWORK_TYPE_INET /**< Internet */ -} fsdp_network_type_t; - -/** - * @short Type of address - * - * Initially, IPv4 and IPv6 are defined for the network type - * Internet. New address types may be registered with IANA. - **/ -typedef enum -{ - FSDP_ADDRESS_TYPE_UNDEFINED, /**< Not provided */ - FSDP_ADDRESS_TYPE_IPV4, /**< IP version 4 */ - FSDP_ADDRESS_TYPE_IPV6 /**< IP version 6 */ -} fsdp_address_type_t; - -/** - * @short Type of bandwith modifiers - * - * Bandwidth modifiers specify the meaning of the bandwidth - * value. Initially "Conference Total" and "Application Specific" are - * defined. Both use kilobits as bandwidth unit. "Conference Total" - * specifies that the bandwidth value is a proposed upper limit to the - * session bandwidth. "Application Specific" specifies thath the - * bandwidth value is the application concept of maximum bandwidth. - **/ -typedef enum -{ - FSDP_BW_MOD_TYPE_UNDEFINED, /**< Not provided */ - FSDP_BW_MOD_TYPE_UNKNOWN, /**< Unknown bandwidth - modifier (FreeSDP - ignores it) */ - FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL, /**< "CT - Conference Total" */ - FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC, /**< "AS - Application specific" */ - FSDP_BW_MOD_TYPE_RTCP_SENDERS, /**< "RS - RTCP bandwidth for - senders */ - FSDP_BW_MOD_TYPE_RTCP_RECEIVERS, /**< "RR - RTCP bandwidth for - receivers */ -} fsdp_bw_modifier_type_t; - -/** - * @short encryption method - * - * The encryption method specifies the way to get the encryption key. - **/ -typedef enum -{ - FSDP_ENCRYPTION_METHOD_UNDEFINED, /**< Not provided */ - FSDP_ENCRYPTION_METHOD_CLEAR, /**< The key field is the - untransformed key */ - FSDP_ENCRYPTION_METHOD_BASE64, /**< The key is base64 - encoded */ - FSDP_ENCRYPTION_METHOD_URI, /**< The key value provided is - a URI pointing to the actual - key */ - FSDP_ENCRYPTION_METHOD_PROMPT /**< The key is not provided - but should be got prompting - the user */ -} fsdp_encryption_method_t; - -/** - * @short Advised reception/transmission mode - * - * Depending on wheter sendrecv, recvonly, sendonly or inactive - * attribute is given, the tools used to participate in the session - * should be started in the corresponding transmission - * mode. FSDP_SENDRECV_SENDRECV is the default for sessions which are - * not of the conference type broadcast or H332. - **/ -typedef enum -{ - FSDP_SENDRECV_UNDEFINED, /**< Not specified */ - FSDP_SENDRECV_SENDRECV, /**< Send and receive */ - FSDP_SENDRECV_RECVONLY, /**< Receive only */ - FSDP_SENDRECV_SENDONLY, /**< Send only */ - FSDP_SENDRECV_INACTIVE /**< Do not send nor receive */ -} fsdp_sendrecv_mode_t; - -/** - * @short Values for `orient' media attribute. - * - * Normally used with whiteboard media, this attribute specifies the - * orientation of the whiteboard. - **/ -typedef enum -{ - FSDP_ORIENT_UNDEFINED, /**< Not specified */ - FSDP_ORIENT_PORTRAIT, /**< Portrait */ - FSDP_ORIENT_LANDSCAPE, /**< Landscape */ - FSDP_ORIENT_SEASCAPE /**< Upside down landscape */ -} fsdp_orient_t; - -/** - * @short Type of the conference - * - * The following types are initially defined: broadcast, meeting, - * moderated, test and H332. - **/ -typedef enum -{ - FSDP_SESSION_TYPE_UNDEFINED, /**< Not specified */ - FSDP_SESSION_TYPE_BROADCAST, /**< Broadcast session */ - FSDP_SESSION_TYPE_MEETING, /**< Meeting session */ - FSDP_SESSION_TYPE_MODERATED, /**< Moderated session */ - FSDP_SESSION_TYPE_TEST, /**< Test (do not display) */ - FSDP_SESSION_TYPE_H332 /**< H332 session */ -} fsdp_session_type_t; - -/** - * @short Media type - * - * The following types are defined initially: audio, video, - * application, data and control. - **/ -typedef enum -{ - FSDP_MEDIA_UNDEFINED, /**< Not specified */ - FSDP_MEDIA_VIDEO, /**< Video */ - FSDP_MEDIA_AUDIO, /**< Audio */ - FSDP_MEDIA_APPLICATION, /**< Application, such as whiteboard */ - FSDP_MEDIA_DATA, /**< bulk data */ - FSDP_MEDIA_CONTROL /**< Control channel */ -} fsdp_media_t; - -/** - * @short Transport protocol - * - * The transport protocol used depends on the address type. Initially, - * RTP over UDP Audio/Video Profile, and UDP are defined. - * - **/ -typedef enum -{ - FSDP_TP_UNDEFINED, /**< Not specified */ - FSDP_TP_RTP_AVP, /**< RTP Audio/Video Profile */ - FSDP_TP_UDP, /**< UDP */ - FSDP_TP_TCP, /**< TCP */ - FSDP_TP_UDPTL, /**< ITU-T T.38*/ - FSDP_TP_VAT, /**< old vat protocol (historic)*/ - FSDP_TP_OLD_RTP, /**< old rtp protocols (historic)*/ - FSDP_TP_H320 /**< TODO: add to the parser */ -} fsdp_transport_protocol_t; - -/** - * Session-level attributes whose value is specified as a character - * string in FreeSDP. These values are usually given to - * fsdp_get_strn_att() in order to get the corresponding value. - * - **/ -typedef enum -{ - FSDP_SESSION_STR_ATT_CATEGORY, - FSDP_SESSION_STR_ATT_KEYWORDS, - FSDP_SESSION_STR_ATT_TOOL, - FSDP_SESSION_STR_ATT_CHARSET, -} fsdp_session_str_att_t; - -/** - * @short FreeSDP SDP description media object. - * - * Object for media specific information in SDP descriptions. Each SDP - * description may include any number of media section. A - * fsdp_media_description_t object encapsulates the information in a - * media section, such as video, audio or whiteboard. - **/ -typedef struct fsdp_media_description_t_s fsdp_media_description_t; - -/** - * @short FreeSDP SDP session description object. - * - * Contains all the information extracted from a textual SDP - * description, including all the media announcements. - **/ -typedef struct fsdp_description_t_s fsdp_description_t; - -/** - * Allocates memory and initializes values for a new - * fsdp_description_t object. If you call this routine, do not forget - * about <code>fsdp_description_delete()</code> - * - * @return new fsdp_description_t object - **/ -fsdp_description_t *fsdp_description_new (void); - -/** - * Destroys a fsdp_description_t object. - * - * @param dsc pointer to the fsdp_description_t object to delete. - **/ -void fsdp_description_delete (fsdp_description_t * dsc); - -/** - * Calling this function over a description is equivalent to calling - * fsdp_description_delete and then fsdp_description_delete. This - * function is however more suitable and efficient for description - * processing loops. - * - * @param dsc pointer to the fsdp_description_t object to - * renew/recycle. - **/ -void fsdp_description_recycle (fsdp_description_t * dsc); - -/** - * * Returns a string correspondent to the error number. - * * - * * @param err_no error number. - * **/ -const char *fsdp_strerror (fsdp_error_t err_no); - - /*@}*//* closes addtogroup common */ - -END_C_DECLS -#endif /* FSDP_COMMON_H */
--- a/libmpdemux/freesdp/errorlist.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001, 2002 Federico Montesino Pouzols <fedemp@suidzer0.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 -*/ - -/** - * @file errorlist.c - * - * @short Translation table for error numbers - * - */ - -#ifndef FSDP_ERRORLIST_C -#define FSDP_ERRORLIST_C - -#include "common.h" - -const char *fsdp_error_t_s[] = { - "No error",/** FSDPE_OK **/ - "Illegal character detected",/** FSDPE_ILLEGAL_CHARACTER **/ - "Missing version item", /** FSDPE_MISSING_VERSION **/ - "Invalid version item", /** FSDPE_INVALID_VERSION **/ - "Owner item not present", /** FSDPE_MISSING_OWNER **/ - "Parse error in owner item", /** FSDPE_INVALID_OWNER **/ - "Session name not present", /** FSDPE_MISSING_NAME **/ - "Empty session name item", /** FSDPE_EMPTY_NAME **/ - "Syntax error in connection item", /** FSDPE_INVALID_CONNECTION **/ - "Unrecognized address type in connection item", /** FSDPE_INVALID_CONNECTION_ADDRTYPE **/ - "Unrecognized network type in connection item", /** FSDPE_INVALID_CONNECTION_NETTYPE **/ - "Parse error in bandwith item", /** FSDPE_INVALID_BANDWIDTH **/ - "No time period for the session", /** FSDPE_MISSING_TIME **/ - "Parse error in time item", /** FSDPE_INVALID_TIME **/ - "Parse error in repeat time item", /** FSDPE_INVALID_REPEAT **/ - "Parse error in timezone item", /** FSDPE_INVALID_TIMEZONE **/ - "Unknown encryption method", /** FSDPE_INVALID_ENCRYPTION_METHOD **/ - "Syntax error in an attribute item", /** FSDPE_INVALID_ATTRIBUTE **/ - "Syntax error in an rtpmap attribute item", /** FSDPE_INVALID_ATTRIBUTE_RTPMAP **/ - "Unknown session type in a session-level attribute", /** FSDPE_INVALID_SESSION_TYPE **/ - "Parse error in media item", /** FSDPE_INVALID_MEDIA **/ - "Unknown media type in media item", /** FSDPE_UNKNOWN_MEDIA_TYPE **/ - "Unknown media transport", /** FSDPE_UNKNOWN_MEDIA_TRANSPORT **/ - "Unknown extra lines in description item", /** FSDPE_OVERFILLED **/ - "Unknown line found", /** FSDPE_INVALID_LINE **/ - "No connection information provided", /** FSDPE_MISSING_CONNECTION_INFO **/ - "Description item does not fit in MAXSIZE", /** FSDPE_INVALID_INDEX **/ - "Internal error", /** FSDPE_INTERNAL_ERROR **/ - "Invalid function parameters", /** FSDPE_INVALID_PARAMETER **/ - "Buffer overflow" /** FSDPE_BUFFER_OVERFLOW **/ -}; - - -const char * -fsdp_strerror (fsdp_error_t err_no) -{ - return (fsdp_error_t_s[err_no]); -} - -#endif
--- a/libmpdemux/freesdp/parser.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1958 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 - - Benjamin Zores, (C) 2006 - added support in parser for the a=control: lines. - added support in parser for the a=range: lines. -*/ - -/** - * @file parser.c - * - * @short Parsing module implementation. - * - * This file implements the parsing routine <code>fsdp_parse</code> - * and the <code>fsdp_get_xxxx</code> routines that allow to get the - * session properties from a session description object build through - * the application of <code>fsdp_parse</code> to a textual SDP session - * description. - **/ - -#include "parserpriv.h" - -/** - * Moves the <code>c<code> pointer up to the beginning of the next - * line. - * - * @param c char pointer to pointer - * @retval FSDPE_ILLEGAL_CHARACTER, when an illegal '\r' character - * (not followed by a '\n') is found, returns - */ -#define NEXT_LINE(c) \ -({ \ - while ((*(c) != '\0') && (*(c) != '\r') && (*(c) != '\n')) { \ - (c)++; \ - } \ - if (*(c) == '\n') { \ - (c)++; \ - } else if (*(c) == '\r') { \ - (c)++; \ - if (*(c) == '\n') { \ - (c)++; \ - } else { \ - return FSDPE_ILLEGAL_CHARACTER; \ - } \ - } \ -}) - -fsdp_error_t -fsdp_parse (const char *text_description, fsdp_description_t * dsc) -{ - fsdp_error_t result; - const char *p = text_description, *p2; - unsigned int index, j; - /* temps for sscanf */ - const unsigned int TEMPCHARS = 6; - char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN]; - char longfsdp_buf[MAXLONGFIELDLEN]; - const unsigned int TEMPINTS = 2; - unsigned long int wuint[TEMPINTS]; - - if ((NULL == text_description) || (NULL == dsc)) - return FSDPE_INVALID_PARAMETER; - - /***************************************************************************/ - /* A) parse session-level description */ - /***************************************************************************/ - - /* `v=' line (protocol version) */ - /* according to the RFC, only `v=0' is valid */ - if (sscanf (p, "v=%1lu", &wuint[0])) - { - if (wuint[0] != 0) - return FSDPE_INVALID_VERSION; - } - else - { - return FSDPE_MISSING_VERSION; - } - NEXT_LINE (p); - - /* `o=' line (owner/creator and session identifier) */ - /* o=<username> <session id> <version> <network type> <address type> - <address> */ - if (!strncmp (p, "o=", 2)) - { - p += 2; - /* note that the following max lengths may vary in the future and - are quite arbitary */ - if (sscanf - (p, - "%" MSFLENS "[\x21-\xFF] %" MSFLENS "[0-9] %" MSFLENS - "[0-9] %2s %3s %" MSFLENS "s", fsdp_buf[0], fsdp_buf[1], - fsdp_buf[2], fsdp_buf[3], fsdp_buf[4], fsdp_buf[5]) != 6) - return FSDPE_INVALID_OWNER; - dsc->o_username = strdup (fsdp_buf[0]); - dsc->o_session_id = strdup (fsdp_buf[1]); - dsc->o_announcement_version = strdup (fsdp_buf[2]); - if (!strncmp (fsdp_buf[3], "IN", 2)) - { - dsc->o_network_type = FSDP_NETWORK_TYPE_INET; - if (!strncmp (fsdp_buf[4], "IP4", 3)) - dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV4; - else if (!strncmp (fsdp_buf[4], "IP6", 3)) - dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV6; - else - return FSDPE_INVALID_OWNER; - } - else - { - return FSDPE_INVALID_OWNER; - } - /* TODO? check valid unicast address/FQDN */ - dsc->o_address = strdup (fsdp_buf[5]); - } - else - { - return FSDPE_MISSING_OWNER; - } - NEXT_LINE (p); - - /* `s=' line (session name) -note that the name string cannot be empty */ - /* s=<session name> */ - if (!strncmp (p, "s=", 2)) - { - if (sscanf (p, "s=%" MLFLENS "[^\r\n]", longfsdp_buf) < 1) - return FSDPE_EMPTY_NAME; - dsc->s_name = strdup (longfsdp_buf); - } - else - { - return FSDPE_MISSING_NAME; - } - NEXT_LINE (p); - - /* `i=' line (session information) [optional] */ - /* i=<session description> */ - if (!strncmp (p, "i=", 2) - && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf)) - { - dsc->i_information = strdup (longfsdp_buf); - NEXT_LINE (p); - } - else - { - /* (optional) information absent */ - } - - /* `u=' line (URI of description) [optional] */ - /* u=<URI> */ - if (!strncmp (p, "u=", 2) - && sscanf (p, "u=%" MLFLENS "[^\r\n]", longfsdp_buf)) - { - /* TODO? check valid uri */ - dsc->u_uri = strdup (longfsdp_buf); - NEXT_LINE (p); - } - else - { - /* (optional) uri absent */ - } - - /* `e=' lines (email address) [zero or more] */ - /* e=<email address> */ - p2 = p; - j = 0; - while (!strncmp (p2, "e=", 2)) - { - /* First, count how many emails are there */ - j++; - NEXT_LINE (p2); - } - dsc->emails_count = j; - if (dsc->emails_count > 0) - { - /* Then, build the array of emails */ - dsc->emails = calloc (j, sizeof (const char *)); - for (j = 0; j < dsc->emails_count; j++) - { - sscanf (p, "e=%" MLFLENS "[^\r\n]", longfsdp_buf); - /* TODO? check valid email-address. */ - dsc->emails[j] = strdup (longfsdp_buf); - NEXT_LINE (p); - } - } - - /* `p=' lines (phone number) [zero or more] */ - /* p=<phone number> */ - j = 0; - /* assert ( p2 == p ); */ - while (!strncmp (p2, "p=", 2)) - { - j++; - NEXT_LINE (p2); - } - dsc->phones_count = j; - if (dsc->phones_count > 0) - { - dsc->phones = calloc (j, sizeof (const char *)); - for (j = 0; j < dsc->phones_count; j++) - { - sscanf (p, "p=%" MLFLENS "[^\r\n]", longfsdp_buf); - /* TODO? check valid phone-number. */ - dsc->phones[j] = strdup (longfsdp_buf); - NEXT_LINE (p); - } - } - - /* `c=' line (connection information - not required if included in all media) [optional] */ - /* c=<network type> <address type> <connection address> */ - result = fsdp_parse_c (&p, &(dsc->c_network_type), &(dsc->c_address_type), - &(dsc->c_address)); - if (FSDPE_OK != result) - return result; - - /* `b=' lines (bandwidth information) [optional] */ - /* b=<modifier>:<bandwidth-value> */ - result = - fsdp_parse_b (&p, &(dsc->bw_modifiers), &(dsc->bw_modifiers_count)); - if (FSDPE_OK != result) - return result; - - /* A.1) Time descriptions: */ - - /* `t=' lines (time the session is active) [1 or more] */ - /* t=<start time> <stop time> */ - j = 0; - p2 = p; - while (!strncmp (p2, "t=", 2)) - { - j++; - NEXT_LINE (p2); - while (!strncmp (p2, "r=", 2)) - NEXT_LINE (p2); - } - dsc->time_periods_count = j; - if (dsc->time_periods_count == 0) - return FSDPE_MISSING_TIME; - dsc->time_periods = calloc (dsc->time_periods_count, - sizeof (fsdp_time_period_t *)); - index = 0; - for (j = 0; j < dsc->time_periods_count; j++) - { - unsigned int h = 0; - if (sscanf (p, "t=%10lu %10lu", &wuint[0], &wuint[1]) != 2) - { - /* not all periods have been successfully parsed */ - dsc->time_periods_count = j; - return FSDPE_INVALID_TIME; - } - dsc->time_periods[j] = calloc (1, sizeof (fsdp_time_period_t)); - - /* convert from NTP to time_t time */ - if (wuint[0] != 0) - wuint[0] -= NTP_EPOCH_OFFSET; - if (wuint[1] != 0) - wuint[1] -= NTP_EPOCH_OFFSET; - dsc->time_periods[j]->start = wuint[0]; - dsc->time_periods[j]->stop = wuint[1]; - NEXT_LINE (p); - - /* `r' lines [zero or more repeat times for each t=] */ - /*r=<repeat interval> <active duration> <list of offsets from - start-time> */ - p2 = p; - while (!strncmp (p2, "r=", 2)) - { - h++; - NEXT_LINE (p2); - } - dsc->time_periods[j]->repeats_count = h; - if (h > 0) - { - unsigned int index2 = 0; - dsc->time_periods[j]->repeats = - calloc (h, sizeof (fsdp_repeat_t *)); - for (h = 0; h < dsc->time_periods[j]->repeats_count; h++) - { - /* - get_repeat_values(p,&(dsc->time_periods[index].repeats[index2])); - fsdp_error_t get_repeat_values (const char *r, fsdp_repeat_t - *repeat); - */ - if (sscanf (p, "r=%10s %10s %" MLFLENS "[^\r\n]", - fsdp_buf[0], fsdp_buf[1], longfsdp_buf) == 3) - { - fsdp_repeat_t *repeat; - dsc->time_periods[j]->repeats[h] = - calloc (1, sizeof (fsdp_repeat_t)); - repeat = dsc->time_periods[j]->repeats[h]; - /* get interval, duration and list of offsets */ - result = - fsdp_repeat_time_to_uint (fsdp_buf[0], - &(repeat->interval)); - if (result == FSDPE_OK) - { - result = - fsdp_repeat_time_to_uint (fsdp_buf[1], - &(repeat->duration)); - if (result == FSDPE_OK) - { - unsigned int k = 1; - const char *i = longfsdp_buf; - while (NULL != (i = strchr (i, ' '))) - { - k++; - if (NULL != i) - i++; - } - repeat->offsets_count = k; - repeat->offsets = calloc (k, sizeof (time_t)); - i = longfsdp_buf; - for (k = 0; - (k < repeat->offsets_count) - && (result == FSDPE_OK); k++) - { - result = - fsdp_repeat_time_to_uint (i, - &(repeat-> - offsets[k])); - i = strchr (i, ' '); - if (NULL != i) - i++; - } - if (k < repeat->offsets_count) - { - /* there where invalid repeat offsets */ - dsc->time_periods[j]->repeats_count = k; - return FSDPE_INVALID_REPEAT; - } - } - } - if (result != FSDPE_OK) - { - /* not all repeats have been succesfully parsed */ - dsc->time_periods[j]->repeats_count = h; - return FSDPE_INVALID_REPEAT; - } - NEXT_LINE (p); - } - else - { - /* not all repeats have been succesfully parsed */ - dsc->time_periods[j]->repeats_count = h; - return FSDPE_INVALID_REPEAT; - } - index2++; - } - } - } - - /* `z=' line (time zone adjustments) [zero or more] */ - /* z=<adjustment time> <offset> <adjustment time> <offset> .... */ - if (!strncmp (p, "z=", 2)) - { - if (sscanf (p, "z=%" MLFLENS "[^\r\n]", longfsdp_buf)) - { - /* TODO: guess how many pairs are there and process them */ - dsc->timezone_adj = strdup (longfsdp_buf); - NEXT_LINE (p); - } - else - { - return FSDPE_INVALID_TIMEZONE; - } - } - - /* `k=' line (encryption key) [optional] */ - /* k=<method> - k=<method>:<encryption key> */ - result = fsdp_parse_k (&p, &(dsc->k_encryption_method), - &(dsc->k_encryption_content)); - if (result != FSDPE_OK) - return result; - - /* A.2) Attributes */ - /* `a=' lines (session attribute) [0 or more] */ - /* a=<attribute> - a=<attribute>:<value> */ - while (!strncmp (p, "a=", 2)) - { - /* The "9" lenght specifier of the first string is subject to - changes */ - if (sscanf - (p, "a=%9[^:\r\n]:%" MSFLENS "[^\r\n]", fsdp_buf[0], - fsdp_buf[1]) == 2) - { - /* session-level value attributes */ - if (!strncmp (fsdp_buf[0], "cat", 3)) - dsc->a_category = strdup (fsdp_buf[1]); - else if (!strncmp (fsdp_buf[0], "keywds", 6)) - dsc->a_keywords = strdup (fsdp_buf[1]); - else if (!strncmp (fsdp_buf[0], "tool", 4)) - dsc->a_keywords = strdup (fsdp_buf[1]); - else if (!strncmp (fsdp_buf[0], "rtpmap", 6)) - fsdp_parse_rtpmap (&(dsc->a_rtpmaps), - &(dsc->a_rtpmaps_count), fsdp_buf[1]); - else if (!strncmp (fsdp_buf[0], "type", 4)) - { - if (!strncmp (fsdp_buf[1], "broadcast", 9)) - dsc->a_type = FSDP_SESSION_TYPE_BROADCAST; - else if (!strncmp (fsdp_buf[1], "meeting", 7)) - dsc->a_type = FSDP_SESSION_TYPE_MEETING; - else if (!strncmp (fsdp_buf[1], "moderated", 9)) - dsc->a_type = FSDP_SESSION_TYPE_MODERATED; - else if (!strncmp (fsdp_buf[1], "test", 4)) - dsc->a_type = FSDP_SESSION_TYPE_TEST; - else if (!strncmp (fsdp_buf[1], "H332", 4)) - dsc->a_type = FSDP_SESSION_TYPE_H332; - else - return FSDPE_INVALID_SESSION_TYPE; - } - else if (!strncmp (fsdp_buf[0], "charset", 7)) - dsc->a_charset = strdup (fsdp_buf[1]); - else if (!strncmp (fsdp_buf[0], "sdplang", 7)) - { - if (NULL == dsc->a_sdplangs) - { - dsc->a_sdplangs_count = 0; - dsc->a_sdplangs = - calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); - } - if (dsc->a_sdplangs_count < SDPLANGS_MAX_COUNT) - { - dsc->a_sdplangs[dsc->a_sdplangs_count] = - strdup (fsdp_buf[1]); - dsc->a_sdplangs_count++; - } - } - else if (!strncmp (fsdp_buf[0], "lang", 4)) - { - if (NULL == dsc->a_langs) - { - dsc->a_langs_count = 0; - dsc->a_langs = calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); - } - if (dsc->a_langs_count < SDPLANGS_MAX_COUNT) - { - dsc->a_langs[dsc->a_langs_count] = strdup (fsdp_buf[1]); - dsc->a_langs_count++; - } - } - else if (!strncmp (fsdp_buf[0], "control", 7)) - { - if (NULL == dsc->a_controls) - { - dsc->a_controls_count = 0; - dsc->a_controls = - calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *)); - } - if (dsc->a_controls_count < SDPCONTROLS_MAX_COUNT) - { - dsc->a_controls[dsc->a_controls_count] = - strdup (fsdp_buf[1]); - dsc->a_controls_count++; - } - } - else if (!strncmp (fsdp_buf[0], "range", 5)) - { - if (dsc->a_range) - free (dsc->a_range); - dsc->a_range = strdup (fsdp_buf[1]); - } - else - { - /* ignore unknown attributes, but provide access to them */ - *longfsdp_buf = '\0'; - strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); - strncat (longfsdp_buf, ":", MAXLONGFIELDLEN); - strncat (longfsdp_buf, fsdp_buf[1], MAXLONGFIELDLEN); - if (NULL == dsc->unidentified_attributes) - { - dsc->unidentified_attributes_count = 0; - dsc->unidentified_attributes = - calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, - sizeof (char *)); - } - if (dsc->unidentified_attributes_count < - UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) - { - dsc->unidentified_attributes - [dsc->unidentified_attributes_count] = - strdup (longfsdp_buf); - dsc->unidentified_attributes_count++; - } - } - NEXT_LINE (p); - } - else if (sscanf (p, "a=%20s", fsdp_buf[0]) == 1) - { - /* session-level property attributes */ - if (!strncmp (fsdp_buf[0], "recvonly", 8)) - dsc->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY; - else if (!strncmp (fsdp_buf[0], "sendonly", 8)) - dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY; - else if (!strncmp (fsdp_buf[0], "inactive", 8)) - dsc->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE; - else if (!strncmp (fsdp_buf[0], "sendrecv", 8)) - dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV; - else - { - /* ignore unknown attributes, but provide access to them */ - *longfsdp_buf = '\0'; - strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); - if (NULL == dsc->unidentified_attributes) - { - dsc->unidentified_attributes_count = 0; - dsc->unidentified_attributes = - calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, - sizeof (char *)); - } - if (dsc->unidentified_attributes_count < - UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) - { - dsc->unidentified_attributes - [dsc->unidentified_attributes_count] = - strdup (longfsdp_buf); - dsc->unidentified_attributes_count++; - } - } - NEXT_LINE (p); - } - else - return FSDPE_INVALID_ATTRIBUTE; - } - - /***************************************************************************/ - /* B) parse media-level descriptions */ - /***************************************************************************/ - p2 = p; - j = 0; - while ((*p2 != '\0') && !strncmp (p2, "m=", 2)) - { - char c; - j++; - NEXT_LINE (p2); - while (sscanf (p2, "%c=", &c) == 1) - { - if (c == 'i' || c == 'c' || c == 'b' || c == 'k' || c == 'a') - { - NEXT_LINE (p2); - } - else if (c == 'm') - { - break; - } - else - { - return FSDPE_INVALID_LINE; - } - } - } - dsc->media_announcements_count = j; - if (dsc->media_announcements_count == 0) - { - ; - /*return FSDPE_MISSING_MEDIA; */ - } - else - { /* dsc->media_announcements_count > 0 */ - dsc->media_announcements = - calloc (j, sizeof (fsdp_media_announcement_t *)); - for (j = 0; j < dsc->media_announcements_count; j++) - { - fsdp_media_announcement_t *media = NULL; - /* `m=' line (media name, transport address and format list) */ - /* m=<media> <port> <transport> <fmt list> */ - /* The max. string lengths are subject to change */ - if (sscanf (p, "m=%11s %8s %7s %" MLFLENS "[^\r\n]", - fsdp_buf[0], fsdp_buf[1], fsdp_buf[2], - longfsdp_buf) != 4) - { - return FSDPE_INVALID_MEDIA; - } - else - { - dsc->media_announcements[j] = - calloc (1, sizeof (fsdp_media_announcement_t)); - media = dsc->media_announcements[j]; - if (!strncmp (fsdp_buf[0], "audio", 5)) - media->media_type = FSDP_MEDIA_AUDIO; - else if (!strncmp (fsdp_buf[0], "video", 5)) - media->media_type = FSDP_MEDIA_VIDEO; - else if (!strncmp (fsdp_buf[0], "application", 11)) - media->media_type = FSDP_MEDIA_APPLICATION; - else if (!strncmp (fsdp_buf[0], "data", 4)) - media->media_type = FSDP_MEDIA_DATA; - else if (!strncmp (fsdp_buf[0], "control", 7)) - media->media_type = FSDP_MEDIA_CONTROL; - else - return FSDPE_UNKNOWN_MEDIA_TYPE; - { /* try to get port specification as port/number */ - char *slash; - if ((slash = strchr (fsdp_buf[1], '/'))) - { - *slash = '\0'; - slash++; - media->port = strtol (fsdp_buf[1], NULL, 10); - media->port_count = strtol (slash, NULL, 10); - } - else - { - media->port = strtol (fsdp_buf[1], NULL, 10); - media->port_count = 0; - } - } - if (!strncmp (fsdp_buf[2], "RTP/AVP", 7)) - media->transport = FSDP_TP_RTP_AVP; - else if (!strncmp (fsdp_buf[2], "udp", 3)) - media->transport = FSDP_TP_UDP; - else if (!strncmp (fsdp_buf[2], "TCP", 3)) - media->transport = FSDP_TP_TCP; - else if (!strncmp (fsdp_buf[2], "UDPTL", 5)) - media->transport = FSDP_TP_UDPTL; - else if (!strncmp (fsdp_buf[2], "vat", 3)) - media->transport = FSDP_TP_VAT; - else if (!strncmp (fsdp_buf[2], "rtp", 3)) - media->transport = FSDP_TP_OLD_RTP; - else - return FSDPE_UNKNOWN_MEDIA_TRANSPORT; - { - unsigned int k = 0; - char *s = longfsdp_buf; - while (NULL != (s = strchr (s, ' '))) - { - k++; - if (NULL != s) - s++; - } - k++; /* when there is no space left, count the last format */ - media->formats_count = k; - media->formats = calloc (k, sizeof (char *)); - s = longfsdp_buf; - for (k = 0; k < media->formats_count; k++) - { - char *space = strchr (s, ' '); - if (NULL != space) - *space = '\0'; - media->formats[k] = strdup (s); - s = space + 1; - } - } - NEXT_LINE (p); - } - - /* `i=' line (media title) [optional] */ - /* i=<media title> */ - if (!strncmp (p, "i=", 2) - && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf)) - { - media->i_title = strdup (longfsdp_buf); - NEXT_LINE (p); - } - else - { - /* (optional) information absent */ - } - - /* `c=' line (connection information - overrides session-level - line) [optional if provided at session-level] */ - /* c=<network type> <address type> <connection address> */ - result = fsdp_parse_c (&p, &(media->c_network_type), - &(media->c_address_type), - &(media->c_address)); - if (result != FSDPE_OK) - return result; - - /* `b=' lines (bandwidth information) [optional] */ - /* b=<modifier>:<bandwidth-value> */ - result = fsdp_parse_b (&p, &(media->bw_modifiers), - &(media->bw_modifiers_count)); - if (FSDPE_OK != result) - return result; - - /* `k=' line (encryption key) [optional] */ - /* k=<method> - k=<method>:<encryption key> */ - result = fsdp_parse_k (&p, &(media->k_encryption_method), - &(media->k_encryption_content)); - if (result != FSDPE_OK) - return result; - - /* B.1) Attributes */ - - /* `a=' lines (zero or more media attribute lines) [optional] */ - /* a=<attribute> - a=<attribute>:<value> */ - while (!strncmp (p, "a=", 2)) - { - if (sscanf - (p, "a=%9[^:\r\n]:%" MLFLENS "[^\r\n]", fsdp_buf[0], - longfsdp_buf) == 2) - { - /* media-level value attributes */ - if (!strncmp (fsdp_buf[0], "ptime", 5)) - media->a_ptime = strtoul (longfsdp_buf, NULL, 10); - else if (!strncmp (fsdp_buf[0], "maxptime", 8)) - media->a_maxptime = strtoul (longfsdp_buf, NULL, 10); - else if (!strncmp (fsdp_buf[0], "rtpmap", 6)) - fsdp_parse_rtpmap (&(media->a_rtpmaps), - &(media->a_rtpmaps_count), - longfsdp_buf); - else if (!strncmp (fsdp_buf[0], "orient", 6)) - { - if (!strncmp (longfsdp_buf, "portrait", 8)) - media->a_orient = FSDP_ORIENT_PORTRAIT; - else if (!strncmp (longfsdp_buf, "landscape", 9)) - media->a_orient = FSDP_ORIENT_LANDSCAPE; - else if (!strncmp (longfsdp_buf, "seascape", 9)) - media->a_orient = FSDP_ORIENT_SEASCAPE; - } - else if (!strncmp (fsdp_buf[0], "sdplang", 7)) - { - if (NULL == dsc->a_sdplangs) - { - media->a_sdplangs_count = 0; - media->a_sdplangs = - calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); - } - if (media->a_sdplangs_count < SDPLANGS_MAX_COUNT) - { - media->a_sdplangs[dsc->a_sdplangs_count] = - strdup (longfsdp_buf); - media->a_sdplangs_count++; - } - } - else if (!strncmp (fsdp_buf[0], "lang", 4)) - { - if (NULL == dsc->a_langs) - { - media->a_langs_count = 0; - media->a_langs = - calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); - } - if (media->a_langs_count < SDPLANGS_MAX_COUNT) - { - media->a_langs[dsc->a_langs_count] = - strdup (longfsdp_buf); - media->a_langs_count++; - } - } - else if (!strncmp (fsdp_buf[0], "control", 7)) - { - if (NULL == media->a_controls) - { - media->a_controls_count = 0; - media->a_controls = - calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *)); - } - if (media->a_controls_count < SDPCONTROLS_MAX_COUNT) - { - media->a_controls[media->a_controls_count] = - strdup (longfsdp_buf); - media->a_controls_count++; - } - } - else if (!strncmp (fsdp_buf[0], "range", 5)) - { - if (media->a_range) - free (media->a_range); - media->a_range = strdup (fsdp_buf[1]); - } - else if (!strncmp (fsdp_buf[0], "framerate", 9)) - media->a_framerate = strtod (longfsdp_buf, NULL); - else if (!strncmp (fsdp_buf[0], "fmtp", 4)) - { - if (NULL == media->a_fmtps) - { - media->a_fmtps_count = 0; - media->a_fmtps = - calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); - } - if (media->a_fmtps_count < SDPLANGS_MAX_COUNT) - { - media->a_fmtps[media->a_fmtps_count] = - strdup (longfsdp_buf); - media->a_fmtps_count++; - } - } - else if (!strncmp (fsdp_buf[0], "rtcp", 4)) - { - int opts = 0; - /* rtcp attribute: a=rtcp:<port> <nettype> <addrtype> <address> */ - opts = - sscanf (longfsdp_buf, "%lu %2s %3s %" MSFLENS "s", - &wuint[0], fsdp_buf[0], fsdp_buf[1], - fsdp_buf[2]); - if (opts >= 1) - { - media->a_rtcp_port = wuint[0]; - if (opts >= 2) - { - if (!strncmp (fsdp_buf[0], "IN", 2)) - { - media->a_rtcp_network_type = - FSDP_NETWORK_TYPE_INET; - } /* else - ; TODO: define error code? */ - if (opts >= 3) - { - if (!strncmp (fsdp_buf[1], "IP4", 3)) - media->a_rtcp_address_type = - FSDP_ADDRESS_TYPE_IPV4; - else if (!strncmp (fsdp_buf[1], "IP6", 3)) - media->a_rtcp_address_type = - FSDP_ADDRESS_TYPE_IPV6; - else - return FSDPE_INVALID_CONNECTION_NETTYPE; - /*add specific code? */ - if (opts >= 4) - media->a_rtcp_address = - strdup (fsdp_buf[2]); - } - } - } - } - else - { - /* ignore unknown attributes, but provide access to them */ - *fsdp_buf[1] = '\0'; - strncat (fsdp_buf[1], fsdp_buf[0], MAXLONGFIELDLEN); - strncat (fsdp_buf[1], ":", MAXLONGFIELDLEN); - strncat (fsdp_buf[1], longfsdp_buf, MAXLONGFIELDLEN); - if (NULL == media->unidentified_attributes) - { - media->unidentified_attributes_count = 0; - media->unidentified_attributes = - calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, - sizeof (char *)); - } - if (media->unidentified_attributes_count < - UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) - { - media->unidentified_attributes - [media->unidentified_attributes_count] = - strdup (fsdp_buf[1]); - media->unidentified_attributes_count++; - } - } - NEXT_LINE (p); - } - else if (sscanf (p, "a=%8s", fsdp_buf[0]) == 1) - { - /* media-level property attributes */ - if (!strncmp (fsdp_buf[0], "recvonly", 8)) - media->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY; - else if (!strncmp (fsdp_buf[0], "sendonly", 8)) - media->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY; - else if (!strncmp (fsdp_buf[0], "inactive", 8)) - media->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE; - else if (!strncmp (fsdp_buf[0], "sendrecv", 8)) - media->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV; - else - { - /* ignore unknown attributes, but provide access to them */ - *longfsdp_buf = '\0'; - strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); - if (NULL == media->unidentified_attributes) - { - media->unidentified_attributes_count = 0; - media->unidentified_attributes = - calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, - sizeof (char *)); - } - if (media->unidentified_attributes_count < - UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) - { - media->unidentified_attributes - [media->unidentified_attributes_count] = - strdup (longfsdp_buf); - media->unidentified_attributes_count++; - } - } - NEXT_LINE (p); - } - else - return FSDPE_INVALID_ATTRIBUTE; - } - } /* end of for */ - } - - /* Check c= has been given at session level or at media level for - all media */ - if (NULL == dsc->c_address.address) - { - unsigned int c; - for (c = 0; c < dsc->media_announcements_count; c++) - if (NULL == dsc->media_announcements[c]->c_address.address) - return FSDPE_MISSING_CONNECTION_INFO; - } - - /* finish */ - if (*p == '\0') - return FSDPE_OK; - else - return FSDPE_OVERFILLED; -} - -static fsdp_error_t -fsdp_parse_c (const char **p, fsdp_network_type_t * ntype, - fsdp_address_type_t * atype, - fsdp_connection_address_t * address) -{ - const unsigned int TEMPCHARS = 3; - char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN]; - - if (!strncmp (*p, "c=", 2)) - { - if (sscanf (*p, "c=%2s %3s %" MSFLENS "s", - fsdp_buf[0], fsdp_buf[1], fsdp_buf[2])) - { - if (!strncmp (fsdp_buf[0], "IN", 2)) - { - *ntype = FSDP_NETWORK_TYPE_INET; - if (!strncmp (fsdp_buf[1], "IP4", 3)) - *atype = FSDP_ADDRESS_TYPE_IPV4; - else if (!strncmp (fsdp_buf[1], "IP6", 3)) - *atype = FSDP_ADDRESS_TYPE_IPV6; - else - return FSDPE_INVALID_CONNECTION_NETTYPE; - } - else - { - return FSDPE_INVALID_CONNECTION_ADDRTYPE; - } - { - char *slash = strchr (fsdp_buf[2], '/'); - if (NULL == slash) - { - address->address = strdup (fsdp_buf[2]); - address->address_ttl = 0; - address->address_count = 0; - } - else - { - /* address is IP4 multicast */ - char *slash2; - *slash = '\0'; - slash++; - address->address = strdup (fsdp_buf[2]); - slash2 = strchr (slash + 1, '/'); - if (NULL == slash2) - { - address->address_ttl = strtol (slash, NULL, 10); - address->address_count = 0; - } - else - { - *slash2 = '\0'; - slash2++; - address->address_ttl = strtol (slash, NULL, 10); - address->address_count = strtol (slash2, NULL, 10); - } - } - } - NEXT_LINE (*p); - } - else - { - return FSDPE_INVALID_CONNECTION; - } - } - return FSDPE_OK; -} - -static fsdp_error_t -fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers, - unsigned int *bw_modifiers_count) -{ - char fsdp_buf[MAXSHORTFIELDLEN]; - unsigned long int wuint; - unsigned int i = 0; - char *lp = (char *) *p; - - /* count b= lines */ - while (!strncmp (lp, "b=", 2)) - { - NEXT_LINE (lp); - i++; - } - *bw_modifiers = calloc (i, sizeof (fsdp_bw_modifier_t)); - *bw_modifiers_count = i; - - while (i > 0) - { - unsigned int index = *bw_modifiers_count - i; - if (2 == sscanf (*p, "b=%20[^:\r\n]:%lu", fsdp_buf, &wuint)) - { - if (!strncmp (fsdp_buf, "CT", 2)) - (*bw_modifiers)[index].b_mod_type = - FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL; - else if (!strncmp (fsdp_buf, "AS", 2)) - (*bw_modifiers)[index].b_mod_type = - FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC; - else if (!strncmp (fsdp_buf, "RS", 2)) - (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_RTCP_SENDERS; - else if (!strncmp (fsdp_buf, "RR", 2)) - (*bw_modifiers)[index].b_mod_type = - FSDP_BW_MOD_TYPE_RTCP_RECEIVERS; - else - { - (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_UNKNOWN; - (*bw_modifiers)[index].b_unknown_bw_modt = - (char *) strdup (fsdp_buf); - } - (*bw_modifiers)[index].b_value = wuint; - NEXT_LINE (*p); - } - else - { - *bw_modifiers_count -= i; - return FSDPE_INVALID_BANDWIDTH; - } - i--; - } - return FSDPE_OK; -} - -static fsdp_error_t -fsdp_parse_k (const char **p, fsdp_encryption_method_t * method, - char **content) -{ - char fsdp_buf[MAXSHORTFIELDLEN]; - char longfsdp_buf[MAXLONGFIELDLEN]; - - if (!strncmp (*p, "k=", 2)) - { - if (sscanf (*p, "k=prompt")) - { - *method = FSDP_ENCRYPTION_METHOD_PROMPT; - *content = NULL; - NEXT_LINE (*p); - } - else - { - if (sscanf - (*p, "k=%6[^:\r\n]:%" MLFLENS "s", fsdp_buf, longfsdp_buf)) - { - if (!strncmp (fsdp_buf, "clear", 5)) - *method = FSDP_ENCRYPTION_METHOD_CLEAR; - else if (!strncmp (fsdp_buf, "base64", 6)) - *method = FSDP_ENCRYPTION_METHOD_BASE64; - else if (!strncmp (fsdp_buf, "uri", 3)) - *method = FSDP_ENCRYPTION_METHOD_URI; - else - return FSDPE_INVALID_ENCRYPTION_METHOD; - *content = strdup (longfsdp_buf); - NEXT_LINE (*p); - } - } - } - return FSDPE_OK; -} - -static fsdp_error_t -fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter, - const char *value) -{ - fsdp_error_t result = FSDPE_OK; - - if (0 == *counter) - { - *counter = 0; - *rtpmap = calloc (MEDIA_RTPMAPS_MAX_COUNT, sizeof (fsdp_rtpmap_t *)); - } - if (*counter < MEDIA_RTPMAPS_MAX_COUNT) - { - unsigned int c = *counter; - fsdp_rtpmap_t **map = *rtpmap; - char fsdp_buf[MAXSHORTFIELDLEN]; - char longfsdp_buf[MAXLONGFIELDLEN]; - map[c] = calloc (1, sizeof (fsdp_rtpmap_t)); - - /* a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding - parameters]> */ - if (2 == sscanf (value, "%s %s", fsdp_buf, longfsdp_buf)) - { - char *slash1; - map[c]->pt = strdup (fsdp_buf); - /* parse <encoding name>/<clock rate>[/<encoding parameters>] */ - slash1 = strchr (longfsdp_buf, '/'); - if (NULL == slash1) - { - result = FSDPE_INVALID_ATTRIBUTE_RTPMAP; - } - else - { - char *slash2; - *slash1 = '\0'; - slash1++; - map[c]->encoding_name = strdup (longfsdp_buf); - slash2 = strchr (slash1, '/'); - if (NULL != slash2) - { - *slash2 = '\0'; - slash2++; - map[c]->parameters = strdup (slash2); - } - map[c]->clock_rate = strtol (slash1, NULL, 10); - } - (*counter)++; - } - } - return result; -} - -static fsdp_error_t -fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds) -{ - const unsigned long SECONDS_PER_DAY = 86400; - const unsigned long SECONDS_PER_HOUR = 3600; - const unsigned long SECONDS_PER_MINUTE = 60; - char c; - unsigned long int wuint; - - if (sscanf (time, "%lu%c", &wuint, &c) == 2) - { - /* time with unit specification character */ - switch (c) - { - case 'd': - *seconds = wuint * SECONDS_PER_DAY; - break; - case 'h': - *seconds = wuint * SECONDS_PER_HOUR; - break; - case 'm': - *seconds = wuint * SECONDS_PER_MINUTE; - break; - case 's': - *seconds = wuint; - break; - default: - return FSDPE_INVALID_REPEAT; - break; - } - } - else if (sscanf (time, "%lu", &wuint) == 1) - { - /* time without unit specification character */ - *seconds = wuint; - } - else - { - return FSDPE_INVALID_REPEAT; - } - return FSDPE_OK; -} - -unsigned int -fsdp_get_version (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->version; -} - -const char * -fsdp_get_owner_username (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->o_username; -} - -const char * -fsdp_get_session_id (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->o_session_id; -} - -const char * -fsdp_get_announcement_version (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->o_announcement_version; -} - -fsdp_network_type_t -fsdp_get_owner_network_type (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_NETWORK_TYPE_UNDEFINED; - return dsc->o_network_type; -} - -fsdp_address_type_t -fsdp_get_owner_address_type (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_ADDRESS_TYPE_UNDEFINED; - return dsc->o_address_type; -} - -const char * -fsdp_get_owner_address (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->o_address; -} - -const char * -fsdp_get_name (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->s_name; -} - -const char * -fsdp_get_information (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->i_information; -} - -const char * -fsdp_get_uri (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->u_uri; -} - -unsigned int -fsdp_get_emails_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->emails_count; -} - -const char * -fsdp_get_email (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->emails_count)) - return NULL; - return dsc->emails[index]; -} - -unsigned int -fsdp_get_phones_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->phones_count; -} - -const char * -fsdp_get_phone (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->phones_count)) - return NULL; - return dsc->phones[index]; -} - -fsdp_network_type_t -fsdp_get_global_conn_network_type (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_NETWORK_TYPE_UNDEFINED; - return dsc->c_network_type; -} - -fsdp_address_type_t -fsdp_get_global_conn_address_type (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_ADDRESS_TYPE_UNDEFINED; - return dsc->c_address_type; -} - -const char * -fsdp_get_global_conn_address (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->c_address.address; -} - -unsigned int -fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->c_address.address_ttl; -} - -unsigned int -fsdp_get_global_conn_address_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->c_address.address_count; -} - -unsigned int -fsdp_get_bw_modifier_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->bw_modifiers_count; -} - -fsdp_bw_modifier_type_t -fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->bw_modifiers_count)) - return FSDP_BW_MOD_TYPE_UNDEFINED; - return dsc->bw_modifiers[index].b_mod_type; -} - -const char * -fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->bw_modifiers_count) || - (dsc->bw_modifiers[index].b_mod_type != FSDP_BW_MOD_TYPE_UNKNOWN)) - return NULL; - return dsc->bw_modifiers[index].b_unknown_bw_modt; -} - -unsigned long int -fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->bw_modifiers_count)) - return 0; - return dsc->bw_modifiers[index].b_value; -} - -time_t -fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return 0; - return dsc->time_periods[index]->start; -} - -time_t -fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return 0; - return dsc->time_periods[index]->stop; -} - -unsigned int -fsdp_get_period_repeats_count (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return 0; - return dsc->time_periods[index]->repeats_count; -} - -unsigned long int -fsdp_get_period_repeat_interval (const fsdp_description_t * dsc, - unsigned int index, unsigned int rindex) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return 0; - return dsc->time_periods[index]->repeats[rindex]->interval; -} - -unsigned long int -fsdp_get_period_repeat_duration (const fsdp_description_t * dsc, - unsigned int index, unsigned int rindex) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return 0; - return dsc->time_periods[index]->repeats[rindex]->duration; -} - -const unsigned long int * -fsdp_get_period_repeat_offsets (const fsdp_description_t * dsc, - unsigned int index, unsigned int rindex) -{ - if ((!dsc) || (index >= dsc->time_periods_count)) - return NULL; - return dsc->time_periods[index]->repeats[rindex]->offsets; -} - -const char * -fsdp_get_timezone_adj (const fsdp_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->timezone_adj; -} - -unsigned int -fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->unidentified_attributes_count; -} - -const char * -fsdp_get_unidentified_attribute (const fsdp_description_t * dsc, - unsigned int index) -{ - if (!dsc || (index < dsc->unidentified_attributes_count)) - return NULL; - return dsc->unidentified_attributes[index]; -} - -fsdp_encryption_method_t -fsdp_get_encryption_method (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_ENCRYPTION_METHOD_UNDEFINED; - return dsc->k_encryption_method; -} - -const char * -fsdp_get_encryption_content (const fsdp_description_t * dsc) -{ - if (!dsc || (dsc->k_encryption_method == FSDP_ENCRYPTION_METHOD_UNDEFINED)) - return NULL; - return dsc->k_encryption_content; -} - -unsigned int -fsdp_get_rtpmap_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_rtpmaps_count; -} - -const char * -fsdp_get_rtpmap_payload_type (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_rtpmaps_count)) - return NULL; - return dsc->a_rtpmaps[index]->pt; -} - -const char * -fsdp_get_rtpmap_encoding_name (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_rtpmaps_count)) - return NULL; - return dsc->a_rtpmaps[index]->encoding_name; -} - -unsigned int -fsdp_get_rtpmap_clock_rate (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_rtpmaps_count)) - return 0; - return dsc->a_rtpmaps[index]->clock_rate; -} - -const char * -fsdp_get_rtpmap_encoding_parameters (const fsdp_description_t * dsc, - unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_rtpmaps_count)) - return NULL; - return dsc->a_rtpmaps[index]->parameters; -} - -const char * -fsdp_get_str_att (const fsdp_description_t * dsc, fsdp_session_str_att_t att) -{ - /*TODO: change these individual attributes with a table, thus - avoiding this slow switch */ - char *result; - - if (!dsc) - return NULL; - - switch (att) - { - case FSDP_SESSION_STR_ATT_CATEGORY: - result = dsc->a_category; - break; - case FSDP_SESSION_STR_ATT_KEYWORDS: - result = dsc->a_keywords; - break; - case FSDP_SESSION_STR_ATT_TOOL: - result = dsc->a_tool; - break; - case FSDP_SESSION_STR_ATT_CHARSET: - result = dsc->a_charset; - break; - default: - result = NULL; - } - return result; -} - -unsigned int -fsdp_get_sdplang_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_sdplangs_count; -} - -const char * -fsdp_get_sdplang (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_sdplangs_count)) - return NULL; - return dsc->a_sdplangs[index]; -} - -unsigned int -fsdp_get_lang_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_langs_count; -} - -const char * -fsdp_get_lang (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_langs_count)) - return NULL; - return dsc->a_langs[index]; -} - -unsigned int -fsdp_get_control_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_controls_count; -} - -const char * -fsdp_get_control (const fsdp_description_t * dsc, unsigned int index) -{ - if ((!dsc) || (index >= dsc->a_controls_count)) - return NULL; - return dsc->a_controls[index]; -} - -const char * -fsdp_get_range (const fsdp_description_t * dsc) -{ - return dsc->a_range; -} - -fsdp_sendrecv_mode_t -fsdp_get_sendrecv_mode (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_SENDRECV_UNDEFINED; - return dsc->a_sendrecv_mode; -} - -fsdp_session_type_t -fsdp_get_session_type (const fsdp_description_t * dsc) -{ - if (!dsc) - return FSDP_SESSION_TYPE_UNDEFINED; - return dsc->a_type; -} - -unsigned int -fsdp_get_media_count (const fsdp_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->media_announcements_count; -} - -const fsdp_media_description_t * -fsdp_get_media (const fsdp_description_t * dsc, unsigned int index) -{ - if ((index >= dsc->media_announcements_count)) - return NULL; - return dsc->media_announcements[index]; -} - -fsdp_media_t -fsdp_get_media_type (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_MEDIA_UNDEFINED; - return dsc->media_type; -} - -unsigned int -fsdp_get_media_port (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->port; -} - -unsigned int -fsdp_get_media_port_count (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->port_count; -} - -fsdp_transport_protocol_t -fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_TP_UNDEFINED; - return dsc->transport; -} - -unsigned int -fsdp_get_media_formats_count (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->formats_count; -} - -const char * -fsdp_get_media_format (const fsdp_media_description_t * dsc, - unsigned int index) -{ - if (!dsc && (index < dsc->formats_count)) - return NULL; - return dsc->formats[index]; -} - -const char * -fsdp_get_media_title (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->i_title; -} - -fsdp_network_type_t -fsdp_get_media_network_type (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_NETWORK_TYPE_UNDEFINED; - return dsc->c_network_type; -} - -fsdp_address_type_t -fsdp_get_media_address_type (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_ADDRESS_TYPE_UNDEFINED; - return dsc->c_address_type; -} - -const char * -fsdp_get_media_address (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->c_address.address; -} - -unsigned int -fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->c_address.address_ttl; -} - -unsigned int -fsdp_get_media_address_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->c_address.address_count; -} - -fsdp_bw_modifier_type_t -fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc, - unsigned int index) -{ - if (!dsc || (index >= dsc->bw_modifiers_count)) - return FSDP_BW_MOD_TYPE_UNDEFINED; - return dsc->bw_modifiers[index].b_mod_type; -} - -const char * -fsdp_get_media_bw_modifier_type_unknown (const fsdp_media_description_t * dsc, - unsigned int index) -{ - if (!dsc || (index >= dsc->bw_modifiers_count) || - (FSDP_BW_MOD_TYPE_UNKNOWN != dsc->bw_modifiers[index].b_mod_type)) - return NULL; - return dsc->bw_modifiers[index].b_unknown_bw_modt; -} - -unsigned long int -fsdp_get_media_bw_value (const fsdp_media_description_t * dsc, - unsigned int index) -{ - if (!dsc || (index >= dsc->bw_modifiers_count)) - return 0; - return dsc->bw_modifiers[index].b_value; -} - -fsdp_encryption_method_t -fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_ENCRYPTION_METHOD_UNDEFINED; - return dsc->k_encryption_method; -} - -const char * -fsdp_get_media_encryption_content (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->k_encryption_content; -} - -unsigned int -fsdp_get_media_ptime (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_ptime; -} - -unsigned int -fsdp_get_media_maxptime (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_maxptime; -} - -unsigned int -fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->a_rtpmaps_count; -} - -const char * -fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_rtpmaps_count)) - return NULL; - return mdsc->a_rtpmaps[index]->pt; -} - -const char * -fsdp_get_media_rtpmap_encoding_name (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_rtpmaps_count)) - return NULL; - return mdsc->a_rtpmaps[index]->encoding_name; -} - -unsigned int -fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_rtpmaps_count)) - return 0; - return mdsc->a_rtpmaps[index]->clock_rate; -} - -const char * -fsdp_get_media_rtpmap_encoding_parameters (const fsdp_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_rtpmaps_count)) - return NULL; - return mdsc->a_rtpmaps[index]->parameters; -} - -unsigned int -fsdp_get_media_sdplang_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->a_sdplangs_count; -} - -const char * -fsdp_get_media_sdplang (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_sdplangs_count)) - return NULL; - return mdsc->a_sdplangs[index]; -} - -unsigned int -fsdp_get_media_lang_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->a_langs_count; -} - -const char * -fsdp_get_media_lang (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_langs_count)) - return NULL; - return mdsc->a_langs[index]; -} - -unsigned int -fsdp_get_media_control_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->a_controls_count; -} - -char * -fsdp_get_media_control (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_controls_count)) - return NULL; - return mdsc->a_controls[index]; -} - -char * -fsdp_get_media_range (const fsdp_media_description_t * mdsc) -{ - return mdsc->a_range; -} - -unsigned int -fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->a_fmtps_count; -} - -const char * -fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index >= mdsc->a_fmtps_count)) - return NULL; - return mdsc->a_fmtps[index]; -} - -fsdp_orient_t -fsdp_get_media_orient (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_ORIENT_UNDEFINED; - return dsc->a_orient; -} - -fsdp_sendrecv_mode_t -fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_SENDRECV_UNDEFINED; - return dsc->a_sendrecv_mode; -} - -float -fsdp_get_media_framerate (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_framerate; -} - -unsigned int -fsdp_get_media_quality (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_quality; -} - -unsigned int -fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return 0; - return dsc->a_rtcp_port; -} - -fsdp_network_type_t -fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_NETWORK_TYPE_UNDEFINED; - return dsc->a_rtcp_network_type; -} - -fsdp_address_type_t -fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return FSDP_ADDRESS_TYPE_UNDEFINED; - return dsc->a_rtcp_address_type; -} - -const char * -fsdp_get_media_rtcp_address (const fsdp_media_description_t * dsc) -{ - if (!dsc) - return NULL; - return dsc->a_rtcp_address; -} - -unsigned int -fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t - * mdsc) -{ - if (!mdsc) - return 0; - return mdsc->unidentified_attributes_count; -} - -const char * -fsdp_get_media_unidentified_attribute (const fsdp_media_description_t * mdsc, - unsigned int index) -{ - if (!mdsc || (index < mdsc->unidentified_attributes_count)) - return NULL; - return mdsc->unidentified_attributes[index]; -}
--- a/libmpdemux/freesdp/parser.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,728 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 - - Benjamin Zores, (C) 2006 - added support in parser for the a=control: lines. - added support in parser for the a=range: lines. -*/ - -/** - * @file parser.h - * @ingroup parser - * @short Specific public header for parsing module. - **/ - -#ifndef FSDP_PARSER_H -#define FSDP_PARSER_H - -#include "common.h" - -BEGIN_C_DECLS -/** - * @defgroup parser FreeSDP Parsing Module - * - * SDP descriptions parsing routines. - * @{ - **/ -/** - * Parse a SDP description in <code>description</code>, extracting the - * session properties into <code>dsc</code>. These properties can be - * obtained individually later using the <code>fsdp_get_xxxx<code> - * functions. - * - * @param description a multimedia session description formatted in - * SDP. - * @param dsc pointer that is updated to point to a fsdp_description_t - * object. This fsdp_description_t object should have been previously - * allocated using <code>fsdp_description_new()</code>; to free it, - * <code>fsdp_description_delete()</code> should be used. - * - * @return FSDPE_OK when parsing completes successfully. Otherwise, - * another error code is returned. - **/ -fsdp_error_t fsdp_parse (const char *description, fsdp_description_t * dsc); - -/** - * Get the SDP protocol version of the description. - * - * @return SDP protocol version number. - **/ -unsigned int fsdp_get_version (const fsdp_description_t * dsc); - -/** - * Get the username provided by the originator of the session. - * - * @param dsc SDP description object. - * @return username of the session owner - **/ -const char *fsdp_get_owner_username (const fsdp_description_t * dsc); - -/** - * Get the id for the session described in <code>dsc</code>. - * - * @param dsc SDP description object. - * @return id string for this session. - **/ -const char *fsdp_get_session_id (const fsdp_description_t * dsc); - -/** - * Get the announcement version for the session description in - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return announcement version string for this description. - **/ -const char *fsdp_get_announcement_version (const fsdp_description_t * dsc); - -/** - * Get the the type of network the owner of the session described in - * <code>dsc</code> is based on. - * - * @param dsc SDP description object. - * @return network type for the owner of this session. - **/ -fsdp_network_type_t -fsdp_get_owner_network_type (const fsdp_description_t * dsc); - -/** - * Get the the type of address the owner of the session described in - * <code>dsc</code> is based on. - * - * @param dsc SDP description object. - * @return network address type for the owner of this session. - **/ -fsdp_address_type_t -fsdp_get_owner_address_type (const fsdp_description_t * dsc); - -/** - * Get the network address of the owner of the session described in - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return network address for the owner this session. - **/ -const char *fsdp_get_owner_address (const fsdp_description_t * dsc); - -/** - * Get the name of the session described in <code>dsc</code>. - * - * @param dsc SDP description object. - * @return name of this session. - **/ -const char *fsdp_get_name (const fsdp_description_t * dsc); - -/** - * Get the information about the session provided in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return information of this session. - **/ -const char *fsdp_get_information (const fsdp_description_t * dsc); - -/** - * Get an URI about the session provided in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return string containing an URI about the session. NULL if the - * session uri is missing. - **/ -const char *fsdp_get_uri (const fsdp_description_t * dsc); - -/** - * Get the number of emails specified for the session in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return number of emails. - **/ -unsigned int fsdp_get_emails_count (const fsdp_description_t * dsc); - -/** - * Get the n-th email specified for the session in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @param index number of URI. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_emails_count() - 1. - * @return string containing an email about the session. NULL if there - * is no such index. - **/ -const char *fsdp_get_email (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the number of phones specified for the session in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @return number of emails. - **/ -unsigned int fsdp_get_phones_count (const fsdp_description_t * dsc); - -/** - * Get the n-th phone specified for the session in the description - * <code>dsc</code>. - * - * @param dsc SDP description object. - * @param index number of URI. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_phones_count() - 1. - * @return string containing a phone about the session. NULL if there - * is no such index. - **/ -const char *fsdp_get_phone (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the the global type of network of the multimedia session - * connection. - * - * @param dsc SDP description object. - * @return global network type for this - * connection. FSDP_NETWORK_TYPE_UNDEFINED if no global network - * address type is included in the description. - **/ -fsdp_network_type_t -fsdp_get_global_conn_network_type (const fsdp_description_t * dsc); - -/** - * Get the the global type of network address of the multimedia - * session connection. - * - * @param dsc SDP description object. - * @return global network address type for this connection. - * FSDP_ADDRESS_TYPE_UNDEFINED if no global network address type is - * included in the description. - **/ -fsdp_address_type_t -fsdp_get_global_conn_address_type (const fsdp_description_t * dsc); - -/** - * Get the the global address of the multimedia session connection. - * - * @param dsc SDP description object. - * @return global address for this connection. - **/ -const char *fsdp_get_global_conn_address (const fsdp_description_t * dsc); - -unsigned int -fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc); - -unsigned int -fsdp_get_global_conn_address_count (const fsdp_description_t * dsc); - -/** - * Get the number of bandwidth modifiers specified for this session. - * - * @param dsc SDP description object. - * @return number of bandwidth modifiers. - **/ -unsigned int fsdp_get_bw_modifier_count (const fsdp_description_t * dsc); - -/** - * Get the bandwidth modifier type for the session. - * - * @param dsc SDP description object. - * @param index number of bandwidth modifier. - * - * @return global bandwidth modifier type. - * @retval FSDP_BW_MOD_TYPE_UNDEFINED if no global bandwith modifier - * type is defined or invalid index. - * @retval FSDP_BW_MOD_TYPE_UNKNOWN if an unknown bandwith modifier is - * specified or an invalid index is provided. In this case - * fsdp_get_bw_modifer_type_unknown() can be called to get the - * modifier as a character string. - **/ -fsdp_bw_modifier_type_t -fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the textual bandwidth modifier type when it is unknown. - * - * @param dsc SDP description object. - * @param index number of bandwidth modifier. - * - * @return global bandwidth modifier type. - * @retval empty string if the provided bandwidth type is not unknown, - * the provided index is invalid or or there was a parse error. - **/ -const char *fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the value for the bandwidth modifier. - * - * @param dsc SDP description object. - * @param index number of bandwidth modifier. - * @return global bandwidth value. - * @retval 0 if no bandwidth is specified for this session or an - * invalid index has been provided. - **/ -unsigned long int -fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index); - -/** - * Get the number of time periods specified for this session - * - * @param dsc SDP description object. - * @return number of time periods - **/ -unsigned long int fsdp_get_period_count (const fsdp_description_t * dsc); - -/** - * Get the start time for the period selected by index. - * - * @param dsc SDP description object. - * @param index number of time period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @return start time - * @retval 0 if an invalid index is provided. - **/ -time_t -fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index); - -/** - * Get the stop time for the period selected by index. - * - * @param dsc SDP description object. - * @param index number of time period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @return stop time - * @retval 0 if an invalid index is provided. - **/ -time_t -fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index); - -/** - * Get the number of repeats for the period selected by index. - * - * @param dsc SDP description object. - * @param index number of the period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @return number of repeats - * @retval 0 if an invalid index is provided. - **/ -unsigned int -fsdp_get_period_repeats_count (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the interval time of the repeat selected by rindex for the - * period selected by index. - * - * @param dsc SDP description object. - * @param index number of time period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @param rindex number of repeat - * @return interval time - * @retval 0 if an invalid index is provided. - **/ -unsigned long int -fsdp_get_period_repeat_interval (const fsdp_description_t * dsc, - unsigned int index, unsigned int rindex); - -/** - * Get the duration of the repeat selected by rindex for the period - * selected by index. - * - * @param dsc SDP description object. - * @param index number of time period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @param rindex number of repeat - * @return duration - * @retval 0 if an invalid index is provided. - **/ -unsigned long int -fsdp_get_period_repeat_duration (const fsdp_description_t * dsc, - unsigned int index, unsigned int rindex); - -/** - * Get the offsets of the repeat selected by rindex for the period - * selected by index. - * - * @param dsc SDP description object. - * @param index number of time period. Note that this index follows the - * traditional C convention: from 0 to fsdp_get_period_count() - 1. - * @param rindex number of repeat - * @return array of offsets - * @retval NULL if an invalid index is provided. - **/ -const unsigned long int *fsdp_get_period_repeat_offsets (const - fsdp_description_t * - dsc, - unsigned int index, - unsigned int rindex); - -/** - * Get the encryption method defined for this session. - * - * @param dsc SDP description object. - * @return encryption method. FSDP_ENCRYPTION_METHOD_UNDEFINED if no - * encryption method is specified. - **/ -fsdp_encryption_method_t -fsdp_get_encryption_method (const fsdp_description_t * dsc); - -/** - * Get the encryption key or a URI pointing to the encryption key for - * this session. - * - * @param dsc SDP description object. - * @return encryption key unless FSDP_ENCRYPTION_METHOD_URI is - * specified, in which case a URI pointing to the key is returned. If - * the global encryption method is undefined, NULL is returned. - **/ -const char *fsdp_get_encryption_content (const fsdp_description_t * dsc); - -/** - * Get timezone adjustments. - * - * @param dsc SDP description object. - * @return string with list of timezone adjustments - * @retval NULL if no timezone adjustment list was specified or there - * was a parse error. - **/ -const char *fsdp_get_timezone_adj (const fsdp_description_t * dsc); - -/** - * - **/ -unsigned int -fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_unidentified_attribute (const fsdp_description_t * dsc, - unsigned int index); - -/** - * - **/ -unsigned int -fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc); - -/** - * - **/ -const char *fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t - * mdsc, unsigned int index); - -/** - * - **/ -const char *fsdp_get_media_rtpmap_encoding_name (const - fsdp_media_description_t * - mdsc, unsigned int index); - -/** - * - **/ -unsigned int -fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc, - unsigned int index); - -/** - * - **/ -const char *fsdp_get_media_rtpmap_encoding_parameters (const - fsdp_description_t * - mdsc, - unsigned int index); - -/** - * Get the value of the session attribute specified in - * <code>att</code>. This function works for all the session - * attributes whose value is a character string. These attributes are - * defined in the session_string_attribute_t enumerated type. - * - * @param dsc SDP description object. - * @param att attribute to get. - * - * @return value of the attribute <code>att</code>. - * @retval NULL if the attribute was not specified or there was a - * parse error or an invalid att is given. - **/ -const char *fsdp_get_str_att (const fsdp_description_t * dsc, - fsdp_session_str_att_t att); - -/** - * - **/ -unsigned int fsdp_get_sdplang_count (const fsdp_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_sdplang (const fsdp_description_t * dsc, - unsigned int index); - -/** - * Get the mode of the conference, specified with attributes sendrecv, - * sendonly, recvonly and inactive. - * - * @param dsc SDP description object. - * @return send/rec conference mode. - * @retval FSDP_SENDRECV_UNDEFINED if conference mode not provided. - **/ -fsdp_sendrecv_mode_t fsdp_get_sendrecv_mode (const fsdp_description_t * dsc); - -/** - * Get the type of conference, such as broadcast, meeting, moderated, - * test or H332. - * - * @param dsc SDP description object. - * @return conference type. - * @retval FSDP_SESSION_TYPE_UNDEFINED if conference type not provided. - **/ -fsdp_session_type_t fsdp_get_session_type (const fsdp_description_t * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_count (const fsdp_description_t * dsc); - -/** - * - **/ -const fsdp_media_description_t *fsdp_get_media (const fsdp_description_t * - dsc, unsigned int index); - -/** - * - **/ -fsdp_media_t fsdp_get_media_type (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_port (const fsdp_media_description_t * dsc); - -unsigned int fsdp_get_media_port_count (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_transport_protocol_t -fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_formats (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int -fsdp_get_media_formats_count (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_format (const fsdp_media_description_t * dsc, - unsigned int index); - -/** - * - **/ -const char *fsdp_get_media_title (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_network_type_t -fsdp_get_media_network_type (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_address_type_t -fsdp_get_media_address_type (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_address (const fsdp_media_description_t * dsc); - -unsigned int -fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc); - -unsigned int -fsdp_get_media_address_count (const fsdp_media_description_t * mdsc); - -/** - * - **/ -fsdp_bw_modifier_type_t -fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc, - unsigned int index); - -/** - * - **/ -const char *fsdp_get_media_bw_modifier_type_unknown (const - fsdp_media_description_t - * dsc, - unsigned int index); - -/** - * - **/ -unsigned long int -fsdp_get_media_bw_value (const fsdp_media_description_t * dsc, - unsigned int index); - -/** - * - **/ -fsdp_encryption_method_t -fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_encryption_content (const fsdp_media_description_t - * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_ptime (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_maxptime (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int -fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc); - -/** - * - **/ -const char *fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc, - unsigned int index); - -/** - * - **/ -unsigned int -fsdp_get_media_sdplang_count (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_sdplang (const fsdp_media_description_t * dsc, - unsigned int index); - -/** - * - **/ -unsigned int fsdp_get_media_lang_count (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_lang (const fsdp_media_description_t * dsc, - unsigned int index); - - -unsigned int fsdp_get_control_count (const fsdp_description_t * dsc); - -const char *fsdp_get_control (const fsdp_description_t * dsc, - unsigned int index); - -const char *fsdp_get_range (const fsdp_description_t * dsc); - -unsigned int -fsdp_get_media_control_count (const fsdp_media_description_t * mdsc); - -char *fsdp_get_media_control (const fsdp_media_description_t * mdsc, - unsigned int index); - -char *fsdp_get_media_range (const fsdp_media_description_t * mdsc); - -/** - * - **/ -fsdp_orient_t fsdp_get_media_orient (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_sendrecv_mode_t -fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc); - -/** - * - **/ -float fsdp_get_media_framerate (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_quality (const fsdp_media_description_t * dsc); - -/** - * - **/ -unsigned int fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_network_type_t -fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc); - -/** - * - **/ -fsdp_address_type_t -fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc); - -/** - * - **/ -const char *fsdp_get_media_rtcp_address (const fsdp_media_description_t * - dsc); - -/** - * - **/ -unsigned int -fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t - * mdsc); - -/** - * - **/ -const char *fsdp_get_media_unidentified_attribute (const - fsdp_media_description_t * - mdsc, unsigned int index); - - - /** @} *//* closes parser group */ - -END_C_DECLS -#endif /* FSDP_PARSER_H */
--- a/libmpdemux/freesdp/parserpriv.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@suidzer0.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 -*/ - -/** - * @file parserpriv.h - * - * @short Private header for parser module. - **/ - -#ifndef FSDP_PARSERPRIV_H -#define FSDP_PARSERPRIV_H - -#include "priv.h" -#include "parser.h" - -/** - * Parse a connection (c=<network type> <address type> <connection - * address>) line. If the textual description in <code>p</code> begins - * with a connection line, it is parsed. If not, nothing is done. - * - * @param p fraction of textual SDP description. - * @param ntype where to store the network type. - * @param atype where to store the address type. - * @param address where to store the connection address as a string. - * - * @return parse error code. - **/ -static fsdp_error_t -fsdp_parse_c (const char **p, fsdp_network_type_t * ntype, - fsdp_address_type_t * atype, - fsdp_connection_address_t * address); - -/** - * Parse b (b=<modifier>:<bandwidth-value>) consecutive lines. If the - * textual description in <code>p</code> begins with a bandwidth line, - * it is parsed as well as all b lines inmediately after it. If not, - * nothing is done. - * - * @param p fraction of textual SDP description. - * @param bw_modifiers pointer to empty array of bandwidth modifiers to fill. - * @param bw_modifiers_count where to set the number of bandwidth - * modifiers successfully parsed. - * - * @return parse error code. - **/ -static fsdp_error_t -fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers, - unsigned int *bw_modifiers_count); - -/** - * Parse a k (k=<method>) or (k=<method>:<encryption key>) line. If - * the textual description in <code>p</code> begins with an encryption - * line, it is parsed. If not, nothing is done. - * - * @param p fraction of textual SDP description. - * @param method where to store the encryption method. - * @param content where to store the encryption key if provided. - * - * @return parse error code. - **/ -static fsdp_error_t -fsdp_parse_k (const char **p, fsdp_encryption_method_t * method, - char **content); - - -/** - * Parses a string whose first token (first characters before the - * first space or end of string) is supposed to be a time in SDP - * syntax. Some examples of SDP times are: 2d, 5h, 3444, 7778s, - * - * @param time time in SDP syntax as a string. - * @param seconds where to store the value in seconds as an integer. - * - * @return parse error code. - **/ -static fsdp_error_t -fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds); - -static fsdp_error_t -fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter, - const char *value); - -/** - * Maximun default field len for "expected to be short" fields, like - * username, session_id or inet addresses. - * - * MDFLENS value must be MAXSHORTFIELDLEN - 1 - **/ -#define MAXSHORTFIELDLEN 96 -#define MSFLENS "95" - -/** - * Maximun default field len for "maybe very long" fields, like - * information, attribute values. This can also be used for lines - * where there is only a string field, like phone and email. - * - * MLFLENS value must be MAXLONGFIELDLEN - 1 - **/ -#define MAXLONGFIELDLEN 1024 -#define MLFLENS "1023" - -#endif /* FSDP_PARSERPRIV_H */
--- a/libmpdemux/freesdp/priv.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* - This file is part of FreeSDP - Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> - - FreeSDP is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU 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 - - Benjamin Zores, (C) 2006 - added support in parser for the a=control: lines. - added support in parser for the a=range: lines. -*/ - -/** - * @file priv.h - * - * @short Common private header for both formatting and parsing modules. - **/ - -#ifndef FSDP_PRIV_H -#define FSDP_PRIV_H - -#define _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "common.h" - -#define NTP_EPOCH_OFFSET 2208988800UL - -#define FSDP_MAX_LENGTH 2000 - -/* Tags for doxygen documentation */ - -/** - * @mainpage FreeSDP Library Reference Manual - * @section overview Overview (README) - * @verbinclude ../../README - * - **/ - -/** - * @example formatdemo.c - * - * A basic SDP descriptions formatter based on FreeSDP. - **/ - -/** - * @example parsedemo.c - * - * A basic SDP descriptions parser based on FreeSDP. - **/ - -/* Private routines declarations */ - -BEGIN_C_DECLS -/** - * @short bandwidth modifier - * - * Holds type of modifier and value. Also holds the literal bandwidth - * modifier if unknown. - **/ - typedef struct -{ - fsdp_bw_modifier_type_t b_mod_type; - unsigned long int b_value; - char *b_unknown_bw_modt; -} fsdp_bw_modifier_t; - -/** - * @short a=rtpmap: attribute - * - * Holds payload type, enconding name, RTP clock rate, and encofing - * parameters. - **/ -typedef struct -{ - char *pt; - char *encoding_name; - unsigned int clock_rate; - char *parameters; -} fsdp_rtpmap_t; - -/** - * @short Connection address specification - * - * Holds address (unicast or multicast) as well as TTL and number of - * ports, when it is an IP4 multicast address. - **/ -typedef struct fsdp_connection_address_t_s -{ - char *address; - unsigned int address_ttl; - unsigned int address_count; -} fsdp_connection_address_t; - -/** - * @short Struct for each media in a session description. - **/ -struct fsdp_media_description_t_s -{ - /* from `m=<media> <port> <transport> <fmt list>' line */ - fsdp_media_t media_type; - unsigned int port; - unsigned int port_count; - fsdp_transport_protocol_t transport; - char **formats; - unsigned int formats_count; - /* from i=<media title> */ - char *i_title; - /* from `c=<network type> <address type> <connection address>' line - (optional) */ - fsdp_network_type_t c_network_type; - fsdp_address_type_t c_address_type; - fsdp_connection_address_t c_address; - /* from `b=<modifier>:<bandwidth-value>' lines (optional) */ - fsdp_bw_modifier_t *bw_modifiers; - unsigned int bw_modifiers_count; - /* from `k=<method>' or `k=<method>:<encryption key>' line - (optional) */ - fsdp_encryption_method_t k_encryption_method; - char *k_encryption_content; - /* from `a=<attribute>' or `a=<attribute>:<value>' lines (opt) */ - unsigned long int a_ptime; - unsigned long int a_maxptime; - /* rtpmap */ - fsdp_rtpmap_t **a_rtpmaps; - unsigned int a_rtpmaps_count; - fsdp_orient_t a_orient; - fsdp_sendrecv_mode_t a_sendrecv_mode; - - char **a_sdplangs; - unsigned int a_sdplangs_count; - char **a_langs; - unsigned int a_langs_count; - - char **a_controls; - unsigned int a_controls_count; - - char *a_range; - - float a_framerate; - unsigned int a_quality; - char **a_fmtps; - unsigned int a_fmtps_count; - /* rtcp attribute */ - unsigned int a_rtcp_port; - fsdp_network_type_t a_rtcp_network_type; - fsdp_address_type_t a_rtcp_address_type; - char *a_rtcp_address; - /* media attributes that are not directly supported */ - char **unidentified_attributes; - unsigned int unidentified_attributes_count; -}; - -typedef struct fsdp_media_description_t_s fsdp_media_announcement_t; - -/** - * @short Information for a repeat (struct for r= lines) - **/ -typedef struct -{ - /* times in seconds */ - unsigned long int interval; - unsigned long int duration; - unsigned long int *offsets; - unsigned int offsets_count; -} fsdp_repeat_t; - -/** - * @short Information about a time period - * - * The start and stop times as well as the information from the r= - * lines for a t= line are stored in this structures. - **/ -typedef struct -{ - time_t start; - time_t stop; - fsdp_repeat_t **repeats; - unsigned int repeats_count; -} fsdp_time_period_t; - -/** - * @short Struct for session descriptions. - **/ -struct fsdp_description_t_s -{ - /* from v=... line */ - unsigned int version; - /* from o=... line */ - char *o_username; - char *o_session_id; - char *o_announcement_version; - fsdp_network_type_t o_network_type; - fsdp_address_type_t o_address_type; - char *o_address; - /* from s=... line */ - char *s_name; - /* from i=... line (opt) */ - char *i_information; - /* from u=... line (opt) */ - char *u_uri; - /* from e=... lines (0 or more) */ - const char **emails; - unsigned int emails_count; - /* from p=... lines (0 or more) */ - const char **phones; - unsigned int phones_count; - /* from `c=<network type> <address type> <connection address>' line */ - fsdp_network_type_t c_network_type; - fsdp_address_type_t c_address_type; - fsdp_connection_address_t c_address; - /* from `b=<modifier>:<bandwidth-value>' lines (optional) */ - fsdp_bw_modifier_t *bw_modifiers; - unsigned int bw_modifiers_count; - /* from `t=<start time> <stop time>' lines (1 or more) */ - /* from `r=<repeat interval> <active duration> <list of offsets from - start-time>' */ - fsdp_time_period_t **time_periods; - unsigned int time_periods_count; - /* from `z=<adjustment time> <offset> <adjustment time> <offset> - ....' lines */ - char *timezone_adj; - /* from `k=<method>' or `k=<method>:<encryption key>' line (opt) */ - fsdp_encryption_method_t k_encryption_method; - char *k_encryption_content; - /* from `a=<attribute>' or `a=<attribute>:<value>' lines (opt) */ - char *a_category; - char *a_keywords; - char *a_tool; - char *a_range; - /* rtpmap */ - fsdp_rtpmap_t **a_rtpmaps; - unsigned int a_rtpmaps_count; - fsdp_sendrecv_mode_t a_sendrecv_mode; - fsdp_session_type_t a_type; - char *a_charset; - - char **a_sdplangs; - unsigned int a_sdplangs_count; - char **a_langs; - unsigned int a_langs_count; - - char **a_controls; - unsigned int a_controls_count; - /* from `m=<media> <port>/<number of ports> <transport> <fmt list>' - lines [one or more] */ - fsdp_media_announcement_t **media_announcements; - unsigned int media_announcements_count; - /* session attributes that are not directly supported */ - char **unidentified_attributes; - unsigned int unidentified_attributes_count; -}; - -#define MEDIA_RTPMAPS_MAX_COUNT 5 -#define SDPLANGS_MAX_COUNT 5 -#define SDPCONTROLS_MAX_COUNT 10 -#define UNIDENTIFIED_ATTRIBUTES_MAX_COUNT 5 - -END_C_DECLS -#endif /* FSDP_PRIV_H */
--- a/libmpdemux/frequencies.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1169 +0,0 @@ -#include <stdlib.h> -#include <sys/time.h> - -#include "frequencies.h" - -/* --------------------------------------------------------------------- */ - -/* US broadcast */ -static const struct CHANLIST ntsc_bcast[] = { - { "2", 55250 }, - { "3", 61250 }, - { "4", 67250 }, - { "5", 77250 }, - { "6", 83250 }, - { "7", 175250 }, - { "8", 181250 }, - { "9", 187250 }, - { "10", 193250 }, - { "11", 199250 }, - { "12", 205250 }, - { "13", 211250 }, - { "14", 471250 }, - { "15", 477250 }, - { "16", 483250 }, - { "17", 489250 }, - { "18", 495250 }, - { "19", 501250 }, - { "20", 507250 }, - { "21", 513250 }, - { "22", 519250 }, - { "23", 525250 }, - { "24", 531250 }, - { "25", 537250 }, - { "26", 543250 }, - { "27", 549250 }, - { "28", 555250 }, - { "29", 561250 }, - { "30", 567250 }, - { "31", 573250 }, - { "32", 579250 }, - { "33", 585250 }, - { "34", 591250 }, - { "35", 597250 }, - { "36", 603250 }, - { "37", 609250 }, - { "38", 615250 }, - { "39", 621250 }, - { "40", 627250 }, - { "41", 633250 }, - { "42", 639250 }, - { "43", 645250 }, - { "44", 651250 }, - { "45", 657250 }, - { "46", 663250 }, - { "47", 669250 }, - { "48", 675250 }, - { "49", 681250 }, - { "50", 687250 }, - { "51", 693250 }, - { "52", 699250 }, - { "53", 705250 }, - { "54", 711250 }, - { "55", 717250 }, - { "56", 723250 }, - { "57", 729250 }, - { "58", 735250 }, - { "59", 741250 }, - { "60", 747250 }, - { "61", 753250 }, - { "62", 759250 }, - { "63", 765250 }, - { "64", 771250 }, - { "65", 777250 }, - { "66", 783250 }, - { "67", 789250 }, - { "68", 795250 }, - { "69", 801250 }, - - { "70", 807250 }, - { "71", 813250 }, - { "72", 819250 }, - { "73", 825250 }, - { "74", 831250 }, - { "75", 837250 }, - { "76", 843250 }, - { "77", 849250 }, - { "78", 855250 }, - { "79", 861250 }, - { "80", 867250 }, - { "81", 873250 }, - { "82", 879250 }, - { "83", 885250 }, -}; - -/* US cable */ -static const struct CHANLIST ntsc_cable[] = { - { "1", 73250 }, - { "2", 55250 }, - { "3", 61250 }, - { "4", 67250 }, - { "5", 77250 }, - { "6", 83250 }, - { "7", 175250 }, - { "8", 181250 }, - { "9", 187250 }, - { "10", 193250 }, - { "11", 199250 }, - { "12", 205250 }, - - { "13", 211250 }, - { "14", 121250 }, - { "15", 127250 }, - { "16", 133250 }, - { "17", 139250 }, - { "18", 145250 }, - { "19", 151250 }, - { "20", 157250 }, - - { "21", 163250 }, - { "22", 169250 }, - { "23", 217250 }, - { "24", 223250 }, - { "25", 229250 }, - { "26", 235250 }, - { "27", 241250 }, - { "28", 247250 }, - { "29", 253250 }, - { "30", 259250 }, - { "31", 265250 }, - { "32", 271250 }, - { "33", 277250 }, - { "34", 283250 }, - { "35", 289250 }, - { "36", 295250 }, - { "37", 301250 }, - { "38", 307250 }, - { "39", 313250 }, - { "40", 319250 }, - { "41", 325250 }, - { "42", 331250 }, - { "43", 337250 }, - { "44", 343250 }, - { "45", 349250 }, - { "46", 355250 }, - { "47", 361250 }, - { "48", 367250 }, - { "49", 373250 }, - { "50", 379250 }, - { "51", 385250 }, - { "52", 391250 }, - { "53", 397250 }, - { "54", 403250 }, - { "55", 409250 }, - { "56", 415250 }, - { "57", 421250 }, - { "58", 427250 }, - { "59", 433250 }, - { "60", 439250 }, - { "61", 445250 }, - { "62", 451250 }, - { "63", 457250 }, - { "64", 463250 }, - { "65", 469250 }, - { "66", 475250 }, - { "67", 481250 }, - { "68", 487250 }, - { "69", 493250 }, - - { "70", 499250 }, - { "71", 505250 }, - { "72", 511250 }, - { "73", 517250 }, - { "74", 523250 }, - { "75", 529250 }, - { "76", 535250 }, - { "77", 541250 }, - { "78", 547250 }, - { "79", 553250 }, - { "80", 559250 }, - { "81", 565250 }, - { "82", 571250 }, - { "83", 577250 }, - { "84", 583250 }, - { "85", 589250 }, - { "86", 595250 }, - { "87", 601250 }, - { "88", 607250 }, - { "89", 613250 }, - { "90", 619250 }, - { "91", 625250 }, - { "92", 631250 }, - { "93", 637250 }, - { "94", 643250 }, - { "95", 91250 }, - { "96", 97250 }, - { "97", 103250 }, - { "98", 109250 }, - { "99", 115250 }, - { "100", 649250 }, - { "101", 655250 }, - { "102", 661250 }, - { "103", 667250 }, - { "104", 673250 }, - { "105", 679250 }, - { "106", 685250 }, - { "107", 691250 }, - { "108", 697250 }, - { "109", 703250 }, - { "110", 709250 }, - { "111", 715250 }, - { "112", 721250 }, - { "113", 727250 }, - { "114", 733250 }, - { "115", 739250 }, - { "116", 745250 }, - { "117", 751250 }, - { "118", 757250 }, - { "119", 763250 }, - { "120", 769250 }, - { "121", 775250 }, - { "122", 781250 }, - { "123", 787250 }, - { "124", 793250 }, - { "125", 799250 }, - - { "T7", 8250 }, - { "T8", 14250 }, - { "T9", 20250 }, - { "T10", 26250 }, - { "T11", 32250 }, - { "T12", 38250 }, - { "T13", 44250 }, - { "T14", 50250 } -}; - -/* US HRC */ -static const struct CHANLIST ntsc_hrc[] = { - { "1", 72000 }, - { "2", 54000 }, - { "3", 60000 }, - { "4", 66000 }, - { "5", 78000 }, - { "6", 84000 }, - { "7", 174000 }, - { "8", 180000 }, - { "9", 186000 }, - { "10", 192000 }, - { "11", 198000 }, - { "12", 204000 }, - - { "13", 210000 }, - { "14", 120000 }, - { "15", 126000 }, - { "16", 132000 }, - { "17", 138000 }, - { "18", 144000 }, - { "19", 150000 }, - { "20", 156000 }, - - { "21", 162000 }, - { "22", 168000 }, - { "23", 216000 }, - { "24", 222000 }, - { "25", 228000 }, - { "26", 234000 }, - { "27", 240000 }, - { "28", 246000 }, - { "29", 252000 }, - { "30", 258000 }, - { "31", 264000 }, - { "32", 270000 }, - { "33", 276000 }, - { "34", 282000 }, - { "35", 288000 }, - { "36", 294000 }, - { "37", 300000 }, - { "38", 306000 }, - { "39", 312000 }, - { "40", 318000 }, - { "41", 324000 }, - { "42", 330000 }, - { "43", 336000 }, - { "44", 342000 }, - { "45", 348000 }, - { "46", 354000 }, - { "47", 360000 }, - { "48", 366000 }, - { "49", 372000 }, - { "50", 378000 }, - { "51", 384000 }, - { "52", 390000 }, - { "53", 396000 }, - { "54", 402000 }, - { "55", 408000 }, - { "56", 414000 }, - { "57", 420000 }, - { "58", 426000 }, - { "59", 432000 }, - { "60", 438000 }, - { "61", 444000 }, - { "62", 450000 }, - { "63", 456000 }, - { "64", 462000 }, - { "65", 468000 }, - { "66", 474000 }, - { "67", 480000 }, - { "68", 486000 }, - { "69", 492000 }, - - { "70", 498000 }, - { "71", 504000 }, - { "72", 510000 }, - { "73", 516000 }, - { "74", 522000 }, - { "75", 528000 }, - { "76", 534000 }, - { "77", 540000 }, - { "78", 546000 }, - { "79", 552000 }, - { "80", 558000 }, - { "81", 564000 }, - { "82", 570000 }, - { "83", 576000 }, - { "84", 582000 }, - { "85", 588000 }, - { "86", 594000 }, - { "87", 600000 }, - { "88", 606000 }, - { "89", 612000 }, - { "90", 618000 }, - { "91", 624000 }, - { "92", 630000 }, - { "93", 636000 }, - { "94", 642000 }, - { "95", 900000 }, - { "96", 960000 }, - { "97", 102000 }, - { "98", 108000 }, - { "99", 114000 }, - { "100", 648000 }, - { "101", 654000 }, - { "102", 660000 }, - { "103", 666000 }, - { "104", 672000 }, - { "105", 678000 }, - { "106", 684000 }, - { "107", 690000 }, - { "108", 696000 }, - { "109", 702000 }, - { "110", 708000 }, - { "111", 714000 }, - { "112", 720000 }, - { "113", 726000 }, - { "114", 732000 }, - { "115", 738000 }, - { "116", 744000 }, - { "117", 750000 }, - { "118", 756000 }, - { "119", 762000 }, - { "120", 768000 }, - { "121", 774000 }, - { "122", 780000 }, - { "123", 786000 }, - { "124", 792000 }, - { "125", 798000 }, - - { "T7", 7000 }, - { "T8", 13000 }, - { "T9", 19000 }, - { "T10", 25000 }, - { "T11", 31000 }, - { "T12", 37000 }, - { "T13", 43000 }, - { "T14", 49000 }, -}; - -/* --------------------------------------------------------------------- */ - -/* JP broadcast */ -static const struct CHANLIST ntsc_bcast_jp[] = { - { "1", 91250 }, - { "2", 97250 }, - { "3", 103250 }, - { "4", 171250 }, - { "5", 177250 }, - { "6", 183250 }, - { "7", 189250 }, - { "8", 193250 }, - { "9", 199250 }, - { "10", 205250 }, - { "11", 211250 }, - { "12", 217250 }, - - { "13", 471250 }, - { "14", 477250 }, - { "15", 483250 }, - { "16", 489250 }, - { "17", 495250 }, - { "18", 501250 }, - { "19", 507250 }, - { "20", 513250 }, - { "21", 519250 }, - { "22", 525250 }, - { "23", 531250 }, - { "24", 537250 }, - { "25", 543250 }, - { "26", 549250 }, - { "27", 555250 }, - { "28", 561250 }, - { "29", 567250 }, - { "30", 573250 }, - { "31", 579250 }, - { "32", 585250 }, - { "33", 591250 }, - { "34", 597250 }, - { "35", 603250 }, - { "36", 609250 }, - { "37", 615250 }, - { "38", 621250 }, - { "39", 627250 }, - { "40", 633250 }, - { "41", 639250 }, - { "42", 645250 }, - { "43", 651250 }, - { "44", 657250 }, - - { "45", 663250 }, - { "46", 669250 }, - { "47", 675250 }, - { "48", 681250 }, - { "49", 687250 }, - { "50", 693250 }, - { "51", 699250 }, - { "52", 705250 }, - { "53", 711250 }, - { "54", 717250 }, - { "55", 723250 }, - { "56", 729250 }, - { "57", 735250 }, - { "58", 741250 }, - { "59", 747250 }, - { "60", 753250 }, - { "61", 759250 }, - { "62", 765250 }, -}; - -/* JP cable */ -static const struct CHANLIST ntsc_cable_jp[] = { - { "13", 109250 }, - { "14", 115250 }, - { "15", 121250 }, - { "16", 127250 }, - { "17", 133250 }, - { "18", 139250 }, - { "19", 145250 }, - { "20", 151250 }, - - { "21", 157250 }, - { "22", 165250 }, - { "23", 223250 }, - { "24", 231250 }, - { "25", 237250 }, - { "26", 243250 }, - { "27", 249250 }, - { "28", 253250 }, - { "29", 259250 }, - { "30", 265250 }, - { "31", 271250 }, - { "32", 277250 }, - { "33", 283250 }, - { "34", 289250 }, - { "35", 295250 }, - { "36", 301250 }, - { "37", 307250 }, - { "38", 313250 }, - { "39", 319250 }, - { "40", 325250 }, - { "41", 331250 }, - { "42", 337250 }, - { "43", 343250 }, - { "44", 349250 }, - { "45", 355250 }, - { "46", 361250 }, - { "47", 367250 }, - { "48", 373250 }, - { "49", 379250 }, - { "50", 385250 }, - { "51", 391250 }, - { "52", 397250 }, - { "53", 403250 }, - { "54", 409250 }, - { "55", 415250 }, - { "56", 421250 }, - { "57", 427250 }, - { "58", 433250 }, - { "59", 439250 }, - { "60", 445250 }, - { "61", 451250 }, - { "62", 457250 }, - { "63", 463250 }, -}; - -/* --------------------------------------------------------------------- */ - -/* australia */ -static const struct CHANLIST pal_australia[] = { - { "0", 46250 }, - { "1", 57250 }, - { "2", 64250 }, - { "3", 86250 }, - { "4", 95250 }, - { "5", 102250 }, - { "5A", 138250 }, - { "6", 175250 }, - { "7", 182250 }, - { "8", 189250 }, - { "9", 196250 }, - { "10", 209250 }, - { "11", 216250 }, - { "28", 527250 }, - { "29", 534250 }, - { "30", 541250 }, - { "31", 548250 }, - { "32", 555250 }, - { "33", 562250 }, - { "34", 569250 }, - { "35", 576250 }, - { "36", 591250 }, - { "39", 604250 }, - { "40", 611250 }, - { "41", 618250 }, - { "42", 625250 }, - { "43", 632250 }, - { "44", 639250 }, - { "45", 646250 }, - { "46", 653250 }, - { "47", 660250 }, - { "48", 667250 }, - { "49", 674250 }, - { "50", 681250 }, - { "51", 688250 }, - { "52", 695250 }, - { "53", 702250 }, - { "54", 709250 }, - { "55", 716250 }, - { "56", 723250 }, - { "57", 730250 }, - { "58", 737250 }, - { "59", 744250 }, - { "60", 751250 }, - { "61", 758250 }, - { "62", 765250 }, - { "63", 772250 }, - { "64", 779250 }, - { "65", 786250 }, - { "66", 793250 }, - { "67", 800250 }, - { "68", 807250 }, - { "69", 814250 }, -}; - -/* --------------------------------------------------------------------- */ -/* europe */ - -/* CCIR frequencies */ - -#define FREQ_CCIR_I_III \ - { "E2", 48250 }, \ - { "E3", 55250 }, \ - { "E4", 62250 }, \ - \ - { "S01", 69250 }, \ - { "S02", 76250 }, \ - { "S03", 83250 }, \ - \ - { "E5", 175250 }, \ - { "E6", 182250 }, \ - { "E7", 189250 }, \ - { "E8", 196250 }, \ - { "E9", 203250 }, \ - { "E10", 210250 }, \ - { "E11", 217250 }, \ - { "E12", 224250 } - -#define FREQ_CCIR_SL_SH \ - { "SE1", 105250 }, \ - { "SE2", 112250 }, \ - { "SE3", 119250 }, \ - { "SE4", 126250 }, \ - { "SE5", 133250 }, \ - { "SE6", 140250 }, \ - { "SE7", 147250 }, \ - { "SE8", 154250 }, \ - { "SE9", 161250 }, \ - { "SE10", 168250 }, \ - \ - { "SE11", 231250 }, \ - { "SE12", 238250 }, \ - { "SE13", 245250 }, \ - { "SE14", 252250 }, \ - { "SE15", 259250 }, \ - { "SE16", 266250 }, \ - { "SE17", 273250 }, \ - { "SE18", 280250 }, \ - { "SE19", 287250 }, \ - { "SE20", 294250 } - -#define FREQ_CCIR_H \ - { "S21", 303250 }, \ - { "S22", 311250 }, \ - { "S23", 319250 }, \ - { "S24", 327250 }, \ - { "S25", 335250 }, \ - { "S26", 343250 }, \ - { "S27", 351250 }, \ - { "S28", 359250 }, \ - { "S29", 367250 }, \ - { "S30", 375250 }, \ - { "S31", 383250 }, \ - { "S32", 391250 }, \ - { "S33", 399250 }, \ - { "S34", 407250 }, \ - { "S35", 415250 }, \ - { "S36", 423250 }, \ - { "S37", 431250 }, \ - { "S38", 439250 }, \ - { "S39", 447250 }, \ - { "S40", 455250 }, \ - { "S41", 463250 } - -/* OIRT frequencies */ - -#define FREQ_OIRT_I_III \ - { "R1", 49750 }, \ - { "R2", 59250 }, \ - \ - { "R3", 77250 }, \ - { "R4", 85250 }, \ - { "R5", 93250 }, \ - \ - { "R6", 175250 }, \ - { "R7", 183250 }, \ - { "R8", 191250 }, \ - { "R9", 199250 }, \ - { "R10", 207250 }, \ - { "R11", 215250 }, \ - { "R12", 223250 } - -#define FREQ_OIRT_SL_SH \ - { "SR1", 111250 }, \ - { "SR2", 119250 }, \ - { "SR3", 127250 }, \ - { "SR4", 135250 }, \ - { "SR5", 143250 }, \ - { "SR6", 151250 }, \ - { "SR7", 159250 }, \ - { "SR8", 167250 }, \ - \ - { "SR11", 231250 }, \ - { "SR12", 239250 }, \ - { "SR13", 247250 }, \ - { "SR14", 255250 }, \ - { "SR15", 263250 }, \ - { "SR16", 271250 }, \ - { "SR17", 279250 }, \ - { "SR18", 287250 }, \ - { "SR19", 295250 } - -#define FREQ_UHF \ - { "21", 471250 }, \ - { "22", 479250 }, \ - { "23", 487250 }, \ - { "24", 495250 }, \ - { "25", 503250 }, \ - { "26", 511250 }, \ - { "27", 519250 }, \ - { "28", 527250 }, \ - { "29", 535250 }, \ - { "30", 543250 }, \ - { "31", 551250 }, \ - { "32", 559250 }, \ - { "33", 567250 }, \ - { "34", 575250 }, \ - { "35", 583250 }, \ - { "36", 591250 }, \ - { "37", 599250 }, \ - { "38", 607250 }, \ - { "39", 615250 }, \ - { "40", 623250 }, \ - { "41", 631250 }, \ - { "42", 639250 }, \ - { "43", 647250 }, \ - { "44", 655250 }, \ - { "45", 663250 }, \ - { "46", 671250 }, \ - { "47", 679250 }, \ - { "48", 687250 }, \ - { "49", 695250 }, \ - { "50", 703250 }, \ - { "51", 711250 }, \ - { "52", 719250 }, \ - { "53", 727250 }, \ - { "54", 735250 }, \ - { "55", 743250 }, \ - { "56", 751250 }, \ - { "57", 759250 }, \ - { "58", 767250 }, \ - { "59", 775250 }, \ - { "60", 783250 }, \ - { "61", 791250 }, \ - { "62", 799250 }, \ - { "63", 807250 }, \ - { "64", 815250 }, \ - { "65", 823250 }, \ - { "66", 831250 }, \ - { "67", 839250 }, \ - { "68", 847250 }, \ - { "69", 855250 } - -static const struct CHANLIST europe_west[] = { - FREQ_CCIR_I_III, - FREQ_CCIR_SL_SH, - FREQ_CCIR_H, - FREQ_UHF -}; - -static const struct CHANLIST europe_east[] = { - FREQ_OIRT_I_III, - FREQ_OIRT_SL_SH, - FREQ_CCIR_I_III, - FREQ_CCIR_SL_SH, - FREQ_CCIR_H, - FREQ_UHF -}; - -static const struct CHANLIST pal_italy[] = { - { "A", 53750 }, - { "B", 62250 }, - { "C", 82250 }, - { "D", 175250 }, - { "E", 183750 }, - { "F", 192250 }, - { "G", 201250 }, - { "H", 210250 }, - { "H1", 217250 }, - { "H2", 224250 }, - FREQ_UHF -}; - -static const struct CHANLIST pal_ireland[] = { - { "0", 45750 }, - { "1", 53750 }, - { "2", 61750 }, - { "3", 175250 }, - { "4", 183250 }, - { "5", 191250 }, - { "6", 199250 }, - { "7", 207250 }, - { "8", 215250 }, - FREQ_UHF, -}; - -static const struct CHANLIST secam_france[] = { - { "K01", 47750 }, - { "K02", 55750 }, - { "K03", 60500 }, - { "K04", 63750 }, - { "K05", 176000 }, - { "K06", 184000 }, - { "K07", 192000 }, - { "K08", 200000 }, - { "K09", 208000 }, - { "K10", 216000 }, - { "KB", 116750 }, - { "KC", 128750 }, - { "KD", 140750 }, - { "KE", 159750 }, - { "KF", 164750 }, - { "KG", 176750 }, - { "KH", 188750 }, - { "KI", 200750 }, - { "KJ", 212750 }, - { "KK", 224750 }, - { "KL", 236750 }, - { "KM", 248750 }, - { "KN", 260750 }, - { "KO", 272750 }, - { "KP", 284750 }, - { "KQ", 296750 }, - { "H01", 303250 }, - { "H02", 311250 }, - { "H03", 319250 }, - { "H04", 327250 }, - { "H05", 335250 }, - { "H06", 343250 }, - { "H07", 351250 }, - { "H08", 359250 }, - { "H09", 367250 }, - { "H10", 375250 }, - { "H11", 383250 }, - { "H12", 391250 }, - { "H13", 399250 }, - { "H14", 407250 }, - { "H15", 415250 }, - { "H16", 423250 }, - { "H17", 431250 }, - { "H18", 439250 }, - { "H19", 447250 }, - FREQ_UHF, -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST pal_newzealand[] = { - { "1", 45250 }, - { "2", 55250 }, - { "3", 62250 }, - { "4", 175250 }, - { "5", 182250 }, - { "6", 189250 }, - { "7", 196250 }, - { "8", 203250 }, - { "9", 210250 }, - { "10", 217250 }, - { "11", 224250 }, - FREQ_UHF, -}; - -/* --------------------------------------------------------------------- */ - -/* China broadcast */ -static const struct CHANLIST pal_bcast_cn[] = { - { "1", 49750 }, - { "2", 57750 }, - { "3", 65750 }, - { "4", 77250 }, - { "5", 85250 }, - { "6", 112250 }, - { "7", 120250 }, - { "8", 128250 }, - { "9", 136250 }, - { "10", 144250 }, - { "11", 152250 }, - { "12", 160250 }, - { "13", 168250 }, - { "14", 176250 }, - { "15", 184250 }, - { "16", 192250 }, - { "17", 200250 }, - { "18", 208250 }, - { "19", 216250 }, - { "20", 224250 }, - { "21", 232250 }, - { "22", 240250 }, - { "23", 248250 }, - { "24", 256250 }, - { "25", 264250 }, - { "26", 272250 }, - { "27", 280250 }, - { "28", 288250 }, - { "29", 296250 }, - { "30", 304250 }, - { "31", 312250 }, - { "32", 320250 }, - { "33", 328250 }, - { "34", 336250 }, - { "35", 344250 }, - { "36", 352250 }, - { "37", 360250 }, - { "38", 368250 }, - { "39", 376250 }, - { "40", 384250 }, - { "41", 392250 }, - { "42", 400250 }, - { "43", 408250 }, - { "44", 416250 }, - { "45", 424250 }, - { "46", 432250 }, - { "47", 440250 }, - { "48", 448250 }, - { "49", 456250 }, - { "50", 463250 }, - { "51", 471250 }, - { "52", 479250 }, - { "53", 487250 }, - { "54", 495250 }, - { "55", 503250 }, - { "56", 511250 }, - { "57", 519250 }, - { "58", 527250 }, - { "59", 535250 }, - { "60", 543250 }, - { "61", 551250 }, - { "62", 559250 }, - { "63", 607250 }, - { "64", 615250 }, - { "65", 623250 }, - { "66", 631250 }, - { "67", 639250 }, - { "68", 647250 }, - { "69", 655250 }, - { "70", 663250 }, - { "71", 671250 }, - { "72", 679250 }, - { "73", 687250 }, - { "74", 695250 }, - { "75", 703250 }, - { "76", 711250 }, - { "77", 719250 }, - { "78", 727250 }, - { "79", 735250 }, - { "80", 743250 }, - { "81", 751250 }, - { "82", 759250 }, - { "83", 767250 }, - { "84", 775250 }, - { "85", 783250 }, - { "86", 791250 }, - { "87", 799250 }, - { "88", 807250 }, - { "89", 815250 }, - { "90", 823250 }, - { "91", 831250 }, - { "92", 839250 }, - { "93", 847250 }, - { "94", 855250 }, -}; - -/* --------------------------------------------------------------------- */ -/* South Africa Broadcast */ - -static const struct CHANLIST pal_bcast_za[] ={ - { "1", 175250 }, - { "2", 183250 }, - { "3", 191250 }, - { "4", 199250 }, - { "5", 207250 }, - { "6", 215250 }, - { "7", 223250 }, - { "8", 231250 }, - FREQ_UHF -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST argentina[] = { - { "001", 56250 }, - { "002", 62250 }, - { "003", 68250 }, - { "004", 78250 }, - { "005", 84250 }, - { "006", 176250 }, - { "007", 182250 }, - { "008", 188250 }, - { "009", 194250 }, - { "010", 200250 }, - { "011", 206250 }, - { "012", 212250 }, - { "013", 122250 }, - { "014", 128250 }, - { "015", 134250 }, - { "016", 140250 }, - { "017", 146250 }, - { "018", 152250 }, - { "019", 158250 }, - { "020", 164250 }, - { "021", 170250 }, - { "022", 218250 }, - { "023", 224250 }, - { "024", 230250 }, - { "025", 236250 }, - { "026", 242250 }, - { "027", 248250 }, - { "028", 254250 }, - { "029", 260250 }, - { "030", 266250 }, - { "031", 272250 }, - { "032", 278250 }, - { "033", 284250 }, - { "034", 290250 }, - { "035", 296250 }, - { "036", 302250 }, - { "037", 308250 }, - { "038", 314250 }, - { "039", 320250 }, - { "040", 326250 }, - { "041", 332250 }, - { "042", 338250 }, - { "043", 344250 }, - { "044", 350250 }, - { "045", 356250 }, - { "046", 362250 }, - { "047", 368250 }, - { "048", 374250 }, - { "049", 380250 }, - { "050", 386250 }, - { "051", 392250 }, - { "052", 398250 }, - { "053", 404250 }, - { "054", 410250 }, - { "055", 416250 }, - { "056", 422250 }, - { "057", 428250 }, - { "058", 434250 }, - { "059", 440250 }, - { "060", 446250 }, - { "061", 452250 }, - { "062", 458250 }, - { "063", 464250 }, - { "064", 470250 }, - { "065", 476250 }, - { "066", 482250 }, - { "067", 488250 }, - { "068", 494250 }, - { "069", 500250 }, - { "070", 506250 }, - { "071", 512250 }, - { "072", 518250 }, - { "073", 524250 }, - { "074", 530250 }, - { "075", 536250 }, - { "076", 542250 }, - { "077", 548250 }, - { "078", 554250 }, - { "079", 560250 }, - { "080", 566250 }, - { "081", 572250 }, - { "082", 578250 }, - { "083", 584250 }, - { "084", 590250 }, - { "085", 596250 }, - { "086", 602250 }, - { "087", 608250 }, - { "088", 614250 }, - { "089", 620250 }, - { "090", 626250 }, - { "091", 632250 }, - { "092", 638250 }, - { "093", 644250 }, -}; - -/* --------------------------------------------------------------------- */ - -static const struct CHANLIST russia[] = { - {"1", 49750 }, - {"2", 59250 }, - {"3", 77250 }, - {"4", 85250 }, - {"5", 93250 }, - {"SK1", 111250 }, - {"SK2", 119250 }, - {"SK3", 127250 }, - {"SK4", 135250 }, - {"SK5", 143250 }, - {"SK6", 151250 }, - {"SK7", 159250 }, - {"SK8", 167250 }, - {"6", 175250 }, - {"7", 183250 }, - {"8", 191250 }, - {"9", 199250 }, - {"10", 207250 }, - {"11", 215250 }, - {"12", 223250 }, - {"SK11", 231250 }, - {"SK12", 239250 }, - {"SK13", 247250 }, - {"SK14", 255250 }, - {"SK15", 263250 }, - {"SK16", 271250 }, - {"SK17", 279250 }, - {"SK18", 287250 }, - {"S19", 295250 }, - {"S20", 303250 }, - {"S21", 311250 }, - {"S22", 319250 }, - {"S23", 327250 }, - {"S24", 335250 }, - {"S25", 343250 }, - {"S26", 351250 }, - {"S27", 359250 }, - {"S28", 367250 }, - {"S29", 375250 }, - {"S30", 383250 }, - {"S31", 391250 }, - {"S32", 399250 }, - {"S33", 407250 }, - {"S34", 415250 }, - {"S35", 423250 }, - {"S36", 431250 }, - {"S37", 439250 }, - {"S38", 447250 }, - {"S39", 455250 }, - {"S40", 463250 }, - {"21", 471250 }, - {"22", 479250 }, - {"23", 487250 }, - {"24", 495250 }, - {"25", 503250 }, - {"26", 511250 }, - {"27", 519250 }, - {"28", 527250 }, - {"29", 535250 }, - {"30", 543250 }, - {"31", 551250 }, - {"32", 559250 }, - {"33", 567250 }, - {"34", 575250 }, - {"35", 583250 }, - {"36", 591250 }, - {"37", 599250 }, - {"38", 607250 }, - {"39", 615250 }, - {"40", 623250 }, - {"41", 631250 }, - {"42", 639250 }, - {"43", 647250 }, - {"44", 655250 }, - {"45", 663250 }, - {"46", 671250 }, - {"47", 679250 }, - {"48", 687250 }, - {"49", 695250 }, - {"50", 703250 }, - {"51", 711250 }, - {"52", 719250 }, - {"53", 727250 }, - {"54", 735250 }, - {"55", 743250 }, - {"56", 751250 }, - {"57", 759250 }, - {"58", 767250 }, - {"59", 775250 }, - {"60", 783250 }, - {"61", 791250 }, - {"62", 799250 }, - {"63", 807250 }, - {"64", 815250 }, - {"65", 523250 }, - {"66", 831250 }, - {"67", 839250 }, - {"68", 847250 }, - {"69", 855250 }, -}; -/* --------------------------------------------------------------------- */ - -const struct CHANLISTS chanlists[] = { - { "us-bcast", ntsc_bcast, CHAN_COUNT(ntsc_bcast) }, - { "us-cable", ntsc_cable, CHAN_COUNT(ntsc_cable) }, - { "us-cable-hrc", ntsc_hrc, CHAN_COUNT(ntsc_hrc) }, - { "japan-bcast", ntsc_bcast_jp, CHAN_COUNT(ntsc_bcast_jp) }, - { "japan-cable", ntsc_cable_jp, CHAN_COUNT(ntsc_cable_jp) }, - { "europe-west", europe_west, CHAN_COUNT(europe_west) }, - { "europe-east", europe_east, CHAN_COUNT(europe_east) }, - { "italy", pal_italy, CHAN_COUNT(pal_italy) }, - { "newzealand", pal_newzealand, CHAN_COUNT(pal_newzealand) }, - { "australia", pal_australia, CHAN_COUNT(pal_australia) }, - { "ireland", pal_ireland, CHAN_COUNT(pal_ireland) }, - { "france", secam_france, CHAN_COUNT(secam_france) }, - { "china-bcast", pal_bcast_cn, CHAN_COUNT(pal_bcast_cn) }, - { "southafrica", pal_bcast_za, CHAN_COUNT(pal_bcast_za) }, - { "argentina", argentina, CHAN_COUNT(argentina) }, - { "russia", russia, CHAN_COUNT(russia) }, - { NULL, NULL, 0 } /* EOF */ -}; - -int chantab = 5; -const struct CHANLIST *chanlist = europe_west; -int chancount = CHAN_COUNT(europe_west);
--- a/libmpdemux/frequencies.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Worldwide channel/frequency list - * - * Nathan Laredo (laredo@broked.net) - * - * Frequencies are given in kHz - */ -#define NTSC_AUDIO_CARRIER 4500 -#define PAL_AUDIO_CARRIER_I 6000 -#define PAL_AUDIO_CARRIER_BGHN 5500 -#define PAL_AUDIO_CARRIER_MN 4500 -#define PAL_AUDIO_CARRIER_D 6500 -#define SEACAM_AUDIO_DKK1L 6500 -#define SEACAM_AUDIO_BG 5500 -/* NICAM 728 32-kHz, 14-bit digital stereo audio is transmitted in 1ms frames - containing 8 bits frame sync, 5 bits control, 11 bits additional data, and - 704 bits audio data. The bit rate is reduced by transmitting only 10 bits - plus parity of each 14 bit sample, the largest sample in a frame determines - which 10 bits are transmitted. The parity bits for audio samples also - specify the scaling factor used for that channel during that frame. The - companeded audio data is interleaved to reduce the influence of dropouts - and the whole frame except for sync bits is scrambled for spectrum shaping. - Data is modulated using QPSK, at below following subcarrier freqs */ -#define NICAM728_PAL_BGH 5850 -#define NICAM728_PAL_I 6552 - -/* COMPREHENSIVE LIST OF FORMAT BY COUNTRY - (M) NTSC used in: - Antigua, Aruba, Bahamas, Barbados, Belize, Bermuda, Bolivia, Burma, - Canada, Chile, Colombia, Costa Rica, Cuba, Curacao, Dominican Republic, - Ecuador, El Salvador, Guam Guatemala, Honduras, Jamaica, Japan, - South Korea, Mexico, Montserrat, Myanmar, Nicaragua, Panama, Peru, - Philippines, Puerto Rico, St Christopher and Nevis, Samoa, Suriname, - Taiwan, Trinidad/Tobago, United States, Venezuela, Virgin Islands - (B) PAL used in: - Albania, Algeria, Australia, Austria, Bahrain, Bangladesh, Belgium, - Bosnia-Herzegovinia, Brunei Darussalam, Cambodia, Cameroon, Croatia, - Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, Finland, Germany, - Ghana, Gibraltar, Greenland, Iceland, India, Indonesia, Israel, Italy, - Jordan, Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysa, Maldives, - Malta, Nepal, Netherlands, New Zeland, Nigeria, Norway, Oman, Pakistan, - Papua New Guinea, Portugal, Qatar, Sao Tome and Principe, Saudi Arabia, - Seychelles, Sierra Leone, Singapore, Slovenia, Somali, Spain, - Sri Lanka, Sudan, Swaziland, Sweden, Switzeland, Syria, Thailand, - Tunisia, Turkey, Uganda, United Arab Emirates, Yemen - (N) PAL used in: (Combination N = 4.5MHz audio carrier, 3.58MHz burst) - Argentina (Combination N), Paraguay, Uruguay - (M) PAL (525/60, 3.57MHz burst) used in: - Brazil - (G) PAL used in: - Albania, Algeria, Austria, Bahrain, Bosnia/Herzegovinia, Cambodia, - Cameroon, Croatia, Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, - Finland, Germany, Gibraltar, Greenland, Iceland, Israel, Italy, Jordan, - Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysia, Monaco, - Mozambique, Netherlands, New Zealand, Norway, Oman, Pakistan, - Papa New Guinea, Portugal, Qatar, Romania, Sierra Leone, Singapore, - Slovenia, Somalia, Spain, Sri Lanka, Sudan, Swaziland, Sweeden, - Switzerland, Syria, Thailand, Tunisia, Turkey, United Arab Emirates, - Yemen, Zambia, Zimbabwe - (D) PAL used in: - China, North Korea, Romania, Czech Republic - (H) PAL used in: - Belgium - (I) PAL used in: - Angola, Botswana, Gambia, Guinea-Bissau, Hong Kong, Ireland, Lesotho, - Malawi, Nambia, Nigeria, South Africa, Tanzania, United Kingdom, - Zanzibar - (B) SECAM used in: - Djibouti, Greece, Iran, Iraq, Lebanon, Mali, Mauritania, Mauritus, - Morocco - (D) SECAM used in: - Afghanistan, Armenia, Azerbaijan, Belarus, Bulgaria, - Estonia, Georgia, Hungary, Zazakhstan, Lithuania, Mongolia, Moldova, - Russia, Slovak Republic, Ukraine, Vietnam - (G) SECAM used in: - Greecem Iran, Iraq, Mali, Mauritus, Morocco, Saudi Arabia - (K) SECAM used in: - Armenia, Azerbaijan, Bulgaria, Estonia, Georgia, - Hungary, Kazakhstan, Lithuania, Madagascar, Moldova, Poland, Russia, - Slovak Republic, Ukraine, Vietnam - (K1) SECAM used in: - Benin, Burkina Faso, Burundi, Chad, Cape Verde, Central African - Republic, Comoros, Congo, Gabon, Madagascar, Niger, Rwanda, Senegal, - Togo, Zaire - (L) SECAM used in: - France -*/ - -/* --------------------------------------------------------------------- */ - -struct CHANLIST { - char name[8]; - int freq; -}; - -struct CHANLISTS { - const char *name; - const struct CHANLIST *list; - int count; -}; - -#define CHAN_COUNT(x) (sizeof(x)/sizeof(struct CHANLIST)) - -/* --------------------------------------------------------------------- */ - -extern const struct CHANLISTS chanlists[]; -//extern struct STRTAB chanlist_names[]; - -extern int chantab; -extern const struct CHANLIST *chanlist; -extern int chancount;
--- a/libmpdemux/http.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,948 +0,0 @@ -/* - * HTTP Helper - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#else -#include <winsock2.h> -#include <ws2tcpip.h> -#endif - -#include "http.h" -#include "url.h" -#include "mp_msg.h" - -#include "stream.h" -#include "demuxer.h" -#include "network.h" -#include "help_mp.h" - - -extern mime_struct_t mime_type_table[]; -extern int stream_cache_size; -extern int network_bandwidth; - -extern int http_seek(stream_t *stream, off_t pos); - -typedef struct { - unsigned metaint; - unsigned metapos; - int is_ultravox; -} scast_data_t; - -/** - * \brief first read any data from sc->buffer then from fd - * \param fd file descriptor to read data from - * \param buffer buffer to read into - * \param len how many bytes to read - * \param sc streaming control containing buffer to read from first - * \return len unless there is a read error or eof - */ -static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) { - unsigned pos = 0; - unsigned cp_len = sc->buffer_size - sc->buffer_pos; - if (cp_len > len) - cp_len = len; - memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len); - sc->buffer_pos += cp_len; - pos += cp_len; - while (pos < len) { - int ret = recv(fd, &buffer[pos], len - pos, 0); - if (ret <= 0) - break; - pos += ret; - } - return pos; -} - -/** - * \brief read and process (i.e. discard *g*) a block of ultravox metadata - * \param fd file descriptor to read from - * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd - * \return number of real data before next metadata block starts or 0 on error - */ -static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) { - unsigned metaint; - unsigned char info[6] = {0, 0, 0, 0, 0, 0}; - int info_read; - do { - info_read = my_read(fd, info, 1, sc); - if (info[0] == 0x00) - info_read = my_read(fd, info, 6, sc); - else - info_read += my_read(fd, &info[1], 5, sc); - if (info_read != 6) // read error or eof - return 0; - // sync byte and reserved flags - if (info[0] != 0x5a || (info[1] & 0xfc) != 0x00) { - mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n"); - return 0; - } - if (info[1] & 0x01) - mp_msg(MSGT_DEMUXER, MSGL_WARN, "Encrypted ultravox data\n"); - metaint = info[4] << 8 | info[5]; - if ((info[3] & 0xf) < 0x07) { // discard any metadata nonsense - char *metabuf = malloc(metaint); - my_read(fd, metabuf, metaint, sc); - free(metabuf); - } - } while ((info[3] & 0xf) < 0x07); - return metaint; -} - -/** - * \brief read one scast meta data entry and print it - * \param fd file descriptor to read from - * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd - */ -static void scast_meta_read(int fd, streaming_ctrl_t *sc) { - unsigned char tmp = 0; - unsigned metalen; - my_read(fd, &tmp, 1, sc); - metalen = tmp * 16; - if (metalen > 0) { - char *info = malloc(metalen + 1); - unsigned nlen = my_read(fd, info, metalen, sc); - info[nlen] = 0; - mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info); - free(info); - } -} - -/** - * \brief read data from scast/ultravox stream without any metadata - * \param fd file descriptor to read from - * \param buffer buffer to read data into - * \param size number of bytes to read - * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd - */ -static int scast_streaming_read(int fd, char *buffer, int size, - streaming_ctrl_t *sc) { - scast_data_t *sd = (scast_data_t *)sc->data; - unsigned block, ret; - unsigned done = 0; - - // first read remaining data up to next metadata - block = sd->metaint - sd->metapos; - if (block > size) - block = size; - ret = my_read(fd, buffer, block, sc); - sd->metapos += ret; - done += ret; - if (ret != block) // read problems or eof - size = done; - - while (done < size) { // now comes the metadata - if (sd->is_ultravox) - { - sd->metaint = uvox_meta_read(fd, sc); - if (!sd->metaint) - size = done; - } - else - scast_meta_read(fd, sc); // read and display metadata - sd->metapos = 0; - block = size - done; - if (block > sd->metaint) - block = sd->metaint; - ret = my_read(fd, &buffer[done], block, sc); - sd->metapos += ret; - done += ret; - if (ret != block) // read problems or eof - size = done; - } - return done; -} - -static int scast_streaming_start(stream_t *stream) { - int metaint; - scast_data_t *scast_data; - HTTP_header_t *http_hdr = stream->streaming_ctrl->data; - int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; - if (!stream || stream->fd < 0 || !http_hdr) - return -1; - if (is_ultravox) - metaint = 0; - else { - metaint = atoi(http_get_field(http_hdr, "Icy-MetaInt")); - if (metaint <= 0) - return -1; - } - stream->streaming_ctrl->buffer = malloc(http_hdr->body_size); - stream->streaming_ctrl->buffer_size = http_hdr->body_size; - stream->streaming_ctrl->buffer_pos = 0; - memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size); - scast_data = malloc(sizeof(scast_data_t)); - scast_data->metaint = metaint; - scast_data->metapos = 0; - scast_data->is_ultravox = is_ultravox; - http_free(http_hdr); - stream->streaming_ctrl->data = scast_data; - stream->streaming_ctrl->streaming_read = scast_streaming_read; - stream->streaming_ctrl->streaming_seek = NULL; - stream->streaming_ctrl->prebuffer_size = 64 * 1024; // 64 KBytes - stream->streaming_ctrl->buffering = 1; - stream->streaming_ctrl->status = streaming_playing_e; - return 0; -} - -static int nop_streaming_start( stream_t *stream ) { - HTTP_header_t *http_hdr = NULL; - char *next_url=NULL; - URL_t *rd_url=NULL; - int fd,ret; - if( stream==NULL ) return -1; - - fd = stream->fd; - if( fd<0 ) { - fd = http_send_request( stream->streaming_ctrl->url, 0 ); - if( fd<0 ) return -1; - http_hdr = http_read_response( fd ); - if( http_hdr==NULL ) return -1; - - switch( http_hdr->status_code ) { - case 200: // OK - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); - if( http_hdr->body_size>0 ) { - if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { - http_free( http_hdr ); - return -1; - } - } - break; - // Redirect - case 301: // Permanently - case 302: // Temporarily - ret=-1; - next_url = http_get_field( http_hdr, "Location" ); - - if (next_url != NULL) - rd_url=url_new(next_url); - - if (next_url != NULL && rd_url != NULL) { - mp_msg(MSGT_NETWORK,MSGL_STATUS,"Redirected: Using this url instead %s\n",next_url); - stream->streaming_ctrl->url=check4proxies(rd_url); - ret=nop_streaming_start(stream); //recursively get streaming started - } else { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n"); - closesocket( fd ); - fd = -1; - } - return ret; - break; - case 401: //Authorization required - case 403: //Forbidden - case 404: //Not found - case 500: //Server Error - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); - closesocket( fd ); - fd = -1; - return -1; - break; - } - stream->fd = fd; - } else { - http_hdr = (HTTP_header_t*)stream->streaming_ctrl->data; - if( http_hdr->body_size>0 ) { - if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { - http_free( http_hdr ); - stream->streaming_ctrl->data = NULL; - return -1; - } - } - } - - if( http_hdr ) { - http_free( http_hdr ); - stream->streaming_ctrl->data = NULL; - } - - stream->streaming_ctrl->streaming_read = nop_streaming_read; - stream->streaming_ctrl->streaming_seek = nop_streaming_seek; - stream->streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes - stream->streaming_ctrl->buffering = 1; - stream->streaming_ctrl->status = streaming_playing_e; - return 0; -} - -HTTP_header_t * -http_new_header(void) { - HTTP_header_t *http_hdr; - - http_hdr = malloc(sizeof(HTTP_header_t)); - if( http_hdr==NULL ) return NULL; - memset( http_hdr, 0, sizeof(HTTP_header_t) ); - - return http_hdr; -} - -void -http_free( HTTP_header_t *http_hdr ) { - HTTP_field_t *field, *field2free; - if( http_hdr==NULL ) return; - if( http_hdr->protocol!=NULL ) free( http_hdr->protocol ); - if( http_hdr->uri!=NULL ) free( http_hdr->uri ); - if( http_hdr->reason_phrase!=NULL ) free( http_hdr->reason_phrase ); - if( http_hdr->field_search!=NULL ) free( http_hdr->field_search ); - if( http_hdr->method!=NULL ) free( http_hdr->method ); - if( http_hdr->buffer!=NULL ) free( http_hdr->buffer ); - field = http_hdr->first_field; - while( field!=NULL ) { - field2free = field; - if (field->field_name) - free(field->field_name); - field = field->next; - free( field2free ); - } - free( http_hdr ); - http_hdr = NULL; -} - -int -http_response_append( HTTP_header_t *http_hdr, char *response, int length ) { - if( http_hdr==NULL || response==NULL || length<0 ) return -1; - - if( (unsigned)length > SIZE_MAX - http_hdr->buffer_size - 1) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Bad size in memory (re)allocation\n"); - return -1; - } - http_hdr->buffer = (char*)realloc( http_hdr->buffer, http_hdr->buffer_size+length+1 ); - if( http_hdr->buffer==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory (re)allocation failed\n"); - return -1; - } - memcpy( http_hdr->buffer+http_hdr->buffer_size, response, length ); - http_hdr->buffer_size += length; - http_hdr->buffer[http_hdr->buffer_size]=0; // close the string! - return http_hdr->buffer_size; -} - -int -http_is_header_entire( HTTP_header_t *http_hdr ) { - if( http_hdr==NULL ) return -1; - if( http_hdr->buffer==NULL ) return 0; // empty - - if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL && - strstr(http_hdr->buffer, "\n\n")==NULL ) return 0; - return 1; -} - -int -http_response_parse( HTTP_header_t *http_hdr ) { - char *hdr_ptr, *ptr; - char *field=NULL; - int pos_hdr_sep, hdr_sep_len; - size_t len; - if( http_hdr==NULL ) return -1; - if( http_hdr->is_parsed ) return 0; - - // Get the protocol - hdr_ptr = strstr( http_hdr->buffer, " " ); - if( hdr_ptr==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. No space separator found.\n"); - return -1; - } - len = hdr_ptr-http_hdr->buffer; - http_hdr->protocol = malloc(len+1); - if( http_hdr->protocol==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return -1; - } - strncpy( http_hdr->protocol, http_hdr->buffer, len ); - http_hdr->protocol[len]='\0'; - if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) { - if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get HTTP minor version.\n"); - return -1; - } - } - - // Get the status code - if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get status code.\n"); - return -1; - } - hdr_ptr += 4; - - // Get the reason phrase - ptr = strstr( hdr_ptr, "\n" ); - if( hdr_ptr==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get the reason phrase.\n"); - return -1; - } - len = ptr-hdr_ptr; - http_hdr->reason_phrase = malloc(len+1); - if( http_hdr->reason_phrase==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return -1; - } - strncpy( http_hdr->reason_phrase, hdr_ptr, len ); - if( http_hdr->reason_phrase[len-1]=='\r' ) { - len--; - } - http_hdr->reason_phrase[len]='\0'; - - // Set the position of the header separator: \r\n\r\n - hdr_sep_len = 4; - ptr = strstr( http_hdr->buffer, "\r\n\r\n" ); - if( ptr==NULL ) { - ptr = strstr( http_hdr->buffer, "\n\n" ); - if( ptr==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Header may be incomplete. No CRLF CRLF found.\n"); - return -1; - } - hdr_sep_len = 2; - } - pos_hdr_sep = ptr-http_hdr->buffer; - - // Point to the first line after the method line. - hdr_ptr = strstr( http_hdr->buffer, "\n" )+1; - do { - ptr = hdr_ptr; - while( *ptr!='\r' && *ptr!='\n' ) ptr++; - len = ptr-hdr_ptr; - if( len==0 ) break; - field = (char*)realloc(field, len+1); - if( field==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); - return -1; - } - strncpy( field, hdr_ptr, len ); - field[len]='\0'; - http_set_field( http_hdr, field ); - hdr_ptr = ptr+((*ptr=='\r')?2:1); - } while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) ); - - if( field!=NULL ) free( field ); - - if( pos_hdr_sep+hdr_sep_len<http_hdr->buffer_size ) { - // Response has data! - http_hdr->body = http_hdr->buffer+pos_hdr_sep+hdr_sep_len; - http_hdr->body_size = http_hdr->buffer_size-(pos_hdr_sep+hdr_sep_len); - } - - http_hdr->is_parsed = 1; - return 0; -} - -char * -http_build_request( HTTP_header_t *http_hdr ) { - char *ptr, *uri=NULL; - int len; - HTTP_field_t *field; - if( http_hdr==NULL ) return NULL; - - if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET"); - if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/"); - else { - uri = malloc(strlen(http_hdr->uri) + 1); - if( uri==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); - return NULL; - } - strcpy(uri,http_hdr->uri); - } - - //**** Compute the request length - // Add the Method line - len = strlen(http_hdr->method)+strlen(uri)+12; - // Add the fields - field = http_hdr->first_field; - while( field!=NULL ) { - len += strlen(field->field_name)+2; - field = field->next; - } - // Add the CRLF - len += 2; - // Add the body - if( http_hdr->body!=NULL ) { - len += http_hdr->body_size; - } - // Free the buffer if it was previously used - if( http_hdr->buffer!=NULL ) { - free( http_hdr->buffer ); - http_hdr->buffer = NULL; - } - http_hdr->buffer = malloc(len+1); - if( http_hdr->buffer==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); - return NULL; - } - http_hdr->buffer_size = len; - - //*** Building the request - ptr = http_hdr->buffer; - // Add the method line - ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, uri, http_hdr->http_minor_version ); - field = http_hdr->first_field; - // Add the field - while( field!=NULL ) { - ptr += sprintf( ptr, "%s\r\n", field->field_name ); - field = field->next; - } - ptr += sprintf( ptr, "\r\n" ); - // Add the body - if( http_hdr->body!=NULL ) { - memcpy( ptr, http_hdr->body, http_hdr->body_size ); - } - - if( uri ) free( uri ); - return http_hdr->buffer; -} - -char * -http_get_field( HTTP_header_t *http_hdr, const char *field_name ) { - if( http_hdr==NULL || field_name==NULL ) return NULL; - http_hdr->field_search_pos = http_hdr->first_field; - http_hdr->field_search = (char*)realloc( http_hdr->field_search, strlen(field_name)+1 ); - if( http_hdr->field_search==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return NULL; - } - strcpy( http_hdr->field_search, field_name ); - return http_get_next_field( http_hdr ); -} - -char * -http_get_next_field( HTTP_header_t *http_hdr ) { - char *ptr; - HTTP_field_t *field; - if( http_hdr==NULL ) return NULL; - - field = http_hdr->field_search_pos; - while( field!=NULL ) { - ptr = strstr( field->field_name, ":" ); - if( ptr==NULL ) return NULL; - if( !strncasecmp( field->field_name, http_hdr->field_search, ptr-(field->field_name) ) ) { - ptr++; // Skip the column - while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some - http_hdr->field_search_pos = field->next; - return ptr; // return the value without the field name - } - field = field->next; - } - return NULL; -} - -void -http_set_field( HTTP_header_t *http_hdr, const char *field_name ) { - HTTP_field_t *new_field; - if( http_hdr==NULL || field_name==NULL ) return; - - new_field = malloc(sizeof(HTTP_field_t)); - if( new_field==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return; - } - new_field->next = NULL; - new_field->field_name = malloc(strlen(field_name)+1); - if( new_field->field_name==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return; - } - strcpy( new_field->field_name, field_name ); - - if( http_hdr->last_field==NULL ) { - http_hdr->first_field = new_field; - } else { - http_hdr->last_field->next = new_field; - } - http_hdr->last_field = new_field; - http_hdr->field_nb++; -} - -void -http_set_method( HTTP_header_t *http_hdr, const char *method ) { - if( http_hdr==NULL || method==NULL ) return; - - http_hdr->method = malloc(strlen(method)+1); - if( http_hdr->method==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return; - } - strcpy( http_hdr->method, method ); -} - -void -http_set_uri( HTTP_header_t *http_hdr, const char *uri ) { - if( http_hdr==NULL || uri==NULL ) return; - - http_hdr->uri = malloc(strlen(uri)+1); - if( http_hdr->uri==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - return; - } - strcpy( http_hdr->uri, uri ); -} - -int -http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ) { - char *auth = NULL, *usr_pass = NULL, *b64_usr_pass = NULL; - int encoded_len, pass_len=0, out_len; - int res = -1; - if( http_hdr==NULL || username==NULL ) return -1; - - if( password!=NULL ) { - pass_len = strlen(password); - } - - usr_pass = malloc(strlen(username)+pass_len+2); - if( usr_pass==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - goto out; - } - - sprintf( usr_pass, "%s:%s", username, (password==NULL)?"":password ); - - // Base 64 encode with at least 33% more data than the original size - encoded_len = strlen(usr_pass)*2; - b64_usr_pass = malloc(encoded_len); - if( b64_usr_pass==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - goto out; - } - - out_len = base64_encode( usr_pass, strlen(usr_pass), b64_usr_pass, encoded_len); - if( out_len<0 ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Base64 out overflow\n"); - goto out; - } - - b64_usr_pass[out_len]='\0'; - - auth = malloc(encoded_len+22); - if( auth==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); - goto out; - } - - sprintf( auth, "Authorization: Basic %s", b64_usr_pass); - http_set_field( http_hdr, auth ); - res = 0; - -out: - free( usr_pass ); - free( b64_usr_pass ); - free( auth ); - - return res; -} - -void -http_debug_hdr( HTTP_header_t *http_hdr ) { - HTTP_field_t *field; - int i = 0; - if( http_hdr==NULL ) return; - - mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- START ---\n"); - mp_msg(MSGT_NETWORK,MSGL_V,"protocol: [%s]\n", http_hdr->protocol ); - mp_msg(MSGT_NETWORK,MSGL_V,"http minor version: [%d]\n", http_hdr->http_minor_version ); - mp_msg(MSGT_NETWORK,MSGL_V,"uri: [%s]\n", http_hdr->uri ); - mp_msg(MSGT_NETWORK,MSGL_V,"method: [%s]\n", http_hdr->method ); - mp_msg(MSGT_NETWORK,MSGL_V,"status code: [%d]\n", http_hdr->status_code ); - mp_msg(MSGT_NETWORK,MSGL_V,"reason phrase: [%s]\n", http_hdr->reason_phrase ); - mp_msg(MSGT_NETWORK,MSGL_V,"body size: [%d]\n", http_hdr->body_size ); - - mp_msg(MSGT_NETWORK,MSGL_V,"Fields:\n"); - field = http_hdr->first_field; - while( field!=NULL ) { - mp_msg(MSGT_NETWORK,MSGL_V," %d - %s\n", i++, field->field_name ); - field = field->next; - } - mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- END ---\n"); -} - -int -base64_encode(const void *enc, int encLen, char *out, int outMax) { - static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - unsigned char *encBuf; - int outLen; - unsigned int bits; - unsigned int shift; - - encBuf = (unsigned char*)enc; - outLen = 0; - bits = 0; - shift = 0; - outMax &= ~3; - - while( outLen<outMax ) { - if( encLen>0 ) { - // Shift in byte - bits <<= 8; - bits |= *encBuf; - shift += 8; - // Next byte - encBuf++; - encLen--; - } else if( shift>0 ) { - // Pad last bits to 6 bits - will end next loop - bits <<= 6 - shift; - shift = 6; - } else { - // As per RFC 2045, section 6.8, - // pad output as necessary: 0 to 2 '=' chars. - while( outLen & 3 ){ - *out++ = '='; - outLen++; - } - - return outLen; - } - - // Encode 6 bit segments - while( shift>=6 ) { - shift -= 6; - *out = b64[ (bits >> shift) & 0x3F ]; - out++; - outLen++; - } - } - - // Output overflow - return -1; -} - -static int http_streaming_start(stream_t *stream, int* file_format) { - HTTP_header_t *http_hdr; - unsigned int i; - int fd=-1; - int redirect = 0; - int auth_retry=0; - int seekable=0; - char *content_type; - char *next_url; - URL_t *url = stream->streaming_ctrl->url; - - do - { - fd = http_send_request( url, 0 ); - if( fd<0 ) { - return -1; - } - - http_hdr = http_read_response( fd ); - if( http_hdr==NULL ) { - closesocket( fd ); - http_free( http_hdr ); - return -1; - } - - stream->fd=fd; - if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { - http_debug_hdr( http_hdr ); - } - - stream->streaming_ctrl->data = (void*)http_hdr; - - // Check if we can make partial content requests and thus seek in http-streams - if( http_hdr!=NULL && http_hdr->status_code==200 ) { - char *accept_ranges; - if( (accept_ranges = http_get_field(http_hdr,"Accept-Ranges")) != NULL ) - seekable = strncmp(accept_ranges,"bytes",5)==0; - } - - // Check if the response is an ICY status_code reason_phrase - if( !strcasecmp(http_hdr->protocol, "ICY") ) { - switch( http_hdr->status_code ) { - case 200: { // OK - char *field_data = NULL; - // note: I skip icy-notice1 and 2, as they contain html <BR> - // and are IMHO useless info ::atmos - if( (field_data = http_get_field(http_hdr, "icy-name")) != NULL ) - mp_msg(MSGT_NETWORK,MSGL_INFO,"Name : %s\n", field_data); field_data = NULL; - if( (field_data = http_get_field(http_hdr, "icy-genre")) != NULL ) - mp_msg(MSGT_NETWORK,MSGL_INFO,"Genre : %s\n", field_data); field_data = NULL; - if( (field_data = http_get_field(http_hdr, "icy-url")) != NULL ) - mp_msg(MSGT_NETWORK,MSGL_INFO,"Website: %s\n", field_data); field_data = NULL; - // XXX: does this really mean public server? ::atmos - if( (field_data = http_get_field(http_hdr, "icy-pub")) != NULL ) - mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no"); field_data = NULL; - if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL ) - mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data); field_data = NULL; - - // If content-type == video/nsv we most likely have a winamp video stream - // otherwise it should be mp3. if there are more types consider adding mime type - // handling like later - if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox"))) - *file_format = DEMUXER_TYPE_NSV; - else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac"))) - *file_format = DEMUXER_TYPE_AAC; - else - *file_format = DEMUXER_TYPE_AUDIO; - return 0; - } - case 400: // Server Full - mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server is full, skipping!\n"); - return -1; - case 401: // Service Unavailable - mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return service unavailable, skipping!\n"); - return -1; - case 403: // Service Forbidden - mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return 'Service Forbidden'\n"); - return -1; - case 404: // Resource Not Found - mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server couldn't find requested stream, skipping!\n"); - return -1; - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: unhandled ICY-Errorcode, contact MPlayer developers!\n"); - return -1; - } - } - - // Assume standard http if not ICY - switch( http_hdr->status_code ) { - case 200: // OK - // Look if we can use the Content-Type - content_type = http_get_field( http_hdr, "Content-Type" ); - if( content_type!=NULL ) { - char *content_length = NULL; - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); - if( (content_length = http_get_field(http_hdr, "Content-Length")) != NULL) - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length")); - // Check in the mime type table for a demuxer type - i = 0; - while(mime_type_table[i].mime_type != NULL) { - if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { - *file_format = mime_type_table[i].demuxer_type; - return seekable; - } - i++; - } - } - // Not found in the mime type table, don't fail, - // we should try raw HTTP - return seekable; - // Redirect - case 301: // Permanently - case 302: // Temporarily - // TODO: RFC 2616, recommand to detect infinite redirection loops - next_url = http_get_field( http_hdr, "Location" ); - if( next_url!=NULL ) { - closesocket( fd ); - url_free( url ); - stream->streaming_ctrl->url = url = url_new( next_url ); - http_free( http_hdr ); - redirect = 1; - } - break; - case 401: // Authentication required - if( http_authenticate(http_hdr, url, &auth_retry)<0 ) return STREAM_UNSUPORTED; - redirect = 1; - break; - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); - return -1; - } - } while( redirect ); - - return -1; -} - -static int fixup_open(stream_t *stream,int seekable) { - HTTP_header_t *http_hdr = stream->streaming_ctrl->data; - int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt"); - int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; - - stream->type = STREAMTYPE_STREAM; - if(!is_icy && !is_ultravox && seekable) - { - stream->flags |= STREAM_SEEK; - stream->seek = http_seek; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - if ((!is_icy && !is_ultravox) || scast_streaming_start(stream)) - if(nop_streaming_start( stream )) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n"); - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - fixup_network_stream_cache(stream); - return STREAM_OK; -} - -static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) { - int seekable=0; - URL_t *url; - - stream->streaming_ctrl = streaming_ctrl_new(); - if( stream->streaming_ctrl==NULL ) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - url_free(url); - - mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_HTTP(1), URL: %s\n", stream->url); - seekable = http_streaming_start(stream, file_format); - if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) { - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - return fixup_open(stream, seekable); -} - -static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) { - int seekable=0; - URL_t *url; - - stream->streaming_ctrl = streaming_ctrl_new(); - if( stream->streaming_ctrl==NULL ) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - url_free(url); - - mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_HTTP(2), URL: %s\n", stream->url); - seekable = http_streaming_start(stream, file_format); - if(seekable < 0) { - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - return fixup_open(stream, seekable); -} - - -stream_info_t stream_info_http1 = { - "http streaming", - "null", - "Bertrand, Albeau, Reimar Doeffinger, Arpi?", - "plain http", - open_s1, - {"http", "http_proxy", "unsv", NULL}, - NULL, - 0 // Urls are an option string -}; - -stream_info_t stream_info_http2 = { - "http streaming", - "null", - "Bertrand, Albeu, Arpi? who?", - "plain http, also used as fallback for many other protocols", - open_s2, - {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback - NULL, - 0 // Urls are an option string -};
--- a/libmpdemux/http.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * HTTP Helper - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - */ - -#ifndef __HTTP_H -#define __HTTP_H - -typedef struct HTTP_field_type { - char *field_name; - struct HTTP_field_type *next; -} HTTP_field_t; - -typedef struct { - char *protocol; - char *method; - char *uri; - unsigned int status_code; - char *reason_phrase; - unsigned int http_minor_version; - // Field variables - HTTP_field_t *first_field; - HTTP_field_t *last_field; - unsigned int field_nb; - char *field_search; - HTTP_field_t *field_search_pos; - // Body variables - char *body; - size_t body_size; - char *buffer; - size_t buffer_size; - unsigned int is_parsed; -} HTTP_header_t; - -HTTP_header_t* http_new_header(void); -void http_free( HTTP_header_t *http_hdr ); -int http_response_append( HTTP_header_t *http_hdr, char *data, int length ); -int http_response_parse( HTTP_header_t *http_hdr ); -int http_is_header_entire( HTTP_header_t *http_hdr ); -char* http_build_request( HTTP_header_t *http_hdr ); -char* http_get_field( HTTP_header_t *http_hdr, const char *field_name ); -char* http_get_next_field( HTTP_header_t *http_hdr ); -void http_set_field( HTTP_header_t *http_hdr, const char *field_name ); -void http_set_method( HTTP_header_t *http_hdr, const char *method ); -void http_set_uri( HTTP_header_t *http_hdr, const char *uri ); -int http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ); - -void http_debug_hdr( HTTP_header_t *http_hdr ); - -int base64_encode(const void *enc, int encLen, char *out, int outMax); -#endif // __HTTP_H
--- a/libmpdemux/librtsp/rtsp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,804 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rtsp.c,v 1.9 2003/04/10 02:30:48 - */ - -/* - * Copyright (C) 2000-2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * a minimalistic implementation of rtsp protocol, - * *not* RFC 2326 compilant yet. - * - * 2006, Benjamin Zores and Vincent Mussard - * fixed a lot of RFC compliance issues. - */ - -#include <unistd.h> -#include <stdio.h> -#include <assert.h> -#include "config.h" -#ifndef HAVE_WINSOCK2 -#define closesocket close -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#else -#include <winsock2.h> -#endif -#include <string.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <time.h> -#include <sys/time.h> -#include <sys/types.h> -#include <inttypes.h> - -#include "mp_msg.h" -#include "rtsp.h" -#include "rtsp_session.h" -#include "osdep/timer.h" - -/* -#define LOG -*/ - -#define BUF_SIZE 4096 -#define HEADER_SIZE 1024 -#define MAX_FIELDS 256 - -struct rtsp_s { - - int s; - - char *host; - int port; - char *path; - char *param; - char *mrl; - char *user_agent; - - char *server; - unsigned int server_state; - uint32_t server_caps; - - unsigned int cseq; - char *session; - - char *answers[MAX_FIELDS]; /* data of last message */ - char *scheduled[MAX_FIELDS]; /* will be sent with next message */ -}; - -/* - * constants - */ - -#define RTSP_PROTOCOL_VERSION "RTSP/1.0" - -/* server states */ -#define RTSP_CONNECTED 1 -#define RTSP_INIT 2 -#define RTSP_READY 4 -#define RTSP_PLAYING 8 -#define RTSP_RECORDING 16 - -/* server capabilities */ -#define RTSP_OPTIONS 0x001 -#define RTSP_DESCRIBE 0x002 -#define RTSP_ANNOUNCE 0x004 -#define RTSP_SETUP 0x008 -#define RTSP_GET_PARAMETER 0x010 -#define RTSP_SET_PARAMETER 0x020 -#define RTSP_TEARDOWN 0x040 -#define RTSP_PLAY 0x080 -#define RTSP_RECORD 0x100 - -/* - * network utilities - */ - -static int write_stream(int s, const char *buf, int len) { - int total, timeout; - - total = 0; timeout = 30; - while (total < len){ - int n; - - n = send (s, &buf[total], len - total, 0); - - if (n > 0) - total += n; - else if (n < 0) { -#ifndef HAVE_WINSOCK2 - if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { -#else - if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { -#endif - usec_sleep (1000000); timeout--; - } else - return -1; - } - } - - return total; -} - -static ssize_t read_stream(int fd, void *buf, size_t count) { - - ssize_t ret, total; - - total = 0; - - while (total < count) { - - ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); - - if (ret<0) { - if(errno == EAGAIN) { - fd_set rset; - struct timeval timeout; - - FD_ZERO (&rset); - FD_SET (fd, &rset); - - timeout.tv_sec = 30; - timeout.tv_usec = 0; - - if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { - return -1; - } - continue; - } - - mp_msg(MSGT_OPEN, MSGL_ERR, "rtsp: read error.\n"); - return ret; - } else - total += ret; - - /* end of stream */ - if (!ret) break; - } - - return total; -} - -/* - * rtsp_get gets a line from stream - * and returns a null terminated string. - */ - -static char *rtsp_get(rtsp_t *s) { - - int n=1; - char *buffer = malloc(BUF_SIZE); - char *string = NULL; - - read_stream(s->s, buffer, 1); - while (n<BUF_SIZE) { - read_stream(s->s, &(buffer[n]), 1); - if ((buffer[n-1]==0x0d)&&(buffer[n]==0x0a)) break; - n++; - } - - if (n>=BUF_SIZE) { - mp_msg(MSGT_OPEN, MSGL_FATAL, "librtsp: buffer overflow in rtsp_get\n"); - exit(1); - } - string=malloc(n); - memcpy(string,buffer,n-1); - string[n-1]=0; - -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: << '%s'\n", string); -#endif - - - free(buffer); - return string; -} - -/* - * rtsp_put puts a line on stream - */ - -static void rtsp_put(rtsp_t *s, const char *string) { - - int len=strlen(string); - char *buf=malloc(len+2); - -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: >> '%s'", string); -#endif - - memcpy(buf,string,len); - buf[len]=0x0d; - buf[len+1]=0x0a; - - write_stream(s->s, buf, len+2); - -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, " done.\n"); -#endif - - free(buf); -} - -/* - * extract server status code - */ - -static int rtsp_get_code(const char *string) { - - char buf[4]; - int code=0; - - if (!strncmp(string, RTSP_PROTOCOL_VERSION, strlen(RTSP_PROTOCOL_VERSION))) - { - memcpy(buf, string+strlen(RTSP_PROTOCOL_VERSION)+1, 3); - buf[3]=0; - code=atoi(buf); - } else if (!strncmp(string, RTSP_METHOD_SET_PARAMETER,8)) - { - return RTSP_STATUS_SET_PARAMETER; - } - - if(code != RTSP_STATUS_OK) mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: server responds: '%s'\n",string); - - return code; -} - -/* - * send a request - */ - -static void rtsp_send_request(rtsp_t *s, const char *type, const char *what) { - - char **payload=s->scheduled; - char *buf; - - buf = malloc(strlen(type)+strlen(what)+strlen(RTSP_PROTOCOL_VERSION)+3); - - sprintf(buf,"%s %s %s",type, what, RTSP_PROTOCOL_VERSION); - rtsp_put(s,buf); - free(buf); - if (payload) - while (*payload) { - rtsp_put(s,*payload); - payload++; - } - rtsp_put(s,""); - rtsp_unschedule_all(s); -} - -/* - * schedule standard fields - */ - -static void rtsp_schedule_standard(rtsp_t *s) { - - char tmp[17]; - - snprintf(tmp, 17, "CSeq: %u", s->cseq); - rtsp_schedule_field(s, tmp); - - if (s->session) { - char *buf; - buf = malloc(strlen(s->session)+15); - sprintf(buf, "Session: %s", s->session); - rtsp_schedule_field(s, buf); - free(buf); - } -} -/* - * get the answers, if server responses with something != 200, return NULL - */ - -static int rtsp_get_answers(rtsp_t *s) { - - char *answer=NULL; - unsigned int answer_seq; - char **answer_ptr=s->answers; - int code; - int ans_count = 0; - - answer=rtsp_get(s); - if (!answer) - return 0; - code=rtsp_get_code(answer); - free(answer); - - rtsp_free_answers(s); - - do { /* while we get answer lines */ - - answer=rtsp_get(s); - if (!answer) - return 0; - - if (!strncasecmp(answer,"CSeq:",5)) { - sscanf(answer,"%*s %u",&answer_seq); - if (s->cseq != answer_seq) { -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_WARN, "librtsp: warning: CSeq mismatch. got %u, assumed %u", answer_seq, s->cseq); -#endif - s->cseq=answer_seq; - } - } - if (!strncasecmp(answer,"Server:",7)) { - char *buf = malloc(strlen(answer)); - sscanf(answer,"%*s %s",buf); - if (s->server) free(s->server); - s->server=strdup(buf); - free(buf); - } - if (!strncasecmp(answer,"Session:",8)) { - char *buf = calloc(1, strlen(answer)); - sscanf(answer,"%*s %s",buf); - if (s->session) { - if (strcmp(buf, s->session)) { - mp_msg(MSGT_OPEN, MSGL_WARN, "rtsp: warning: setting NEW session: %s\n", buf); - free(s->session); - s->session=strdup(buf); - } - } else - { -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "rtsp: setting session id to: %s\n", buf); -#endif - s->session=strdup(buf); - } - free(buf); - } - *answer_ptr=answer; - answer_ptr++; - } while ((strlen(answer)!=0) && (++ans_count < MAX_FIELDS)); - - s->cseq++; - - *answer_ptr=NULL; - rtsp_schedule_standard(s); - - return code; -} - -/* - * send an ok message - */ - -int rtsp_send_ok(rtsp_t *s) { - char cseq[16]; - - rtsp_put(s, "RTSP/1.0 200 OK"); - sprintf(cseq,"CSeq: %u", s->cseq); - rtsp_put(s, cseq); - rtsp_put(s, ""); - return 0; -} - -/* - * implementation of must-have rtsp requests; functions return - * server status code. - */ - -int rtsp_request_options(rtsp_t *s, const char *what) { - - char *buf; - - if (what) { - buf=strdup(what); - } else - { - buf=malloc(strlen(s->host)+16); - sprintf(buf,"rtsp://%s:%i", s->host, s->port); - } - rtsp_send_request(s,RTSP_METHOD_OPTIONS,buf); - free(buf); - - return rtsp_get_answers(s); -} - -int rtsp_request_describe(rtsp_t *s, const char *what) { - - char *buf; - - if (what) { - buf=strdup(what); - } else - { - buf=malloc(strlen(s->host)+strlen(s->path)+16); - sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); - } - rtsp_send_request(s,RTSP_METHOD_DESCRIBE,buf); - free(buf); - - return rtsp_get_answers(s); -} - -int rtsp_request_setup(rtsp_t *s, const char *what, char *control) { - - char *buf = NULL; - - if (what) - buf = strdup (what); - else - { - int len = strlen (s->host) + strlen (s->path) + 16; - if (control) - len += strlen (control) + 1; - - buf = malloc (len); - sprintf (buf, "rtsp://%s:%i/%s%s%s", s->host, s->port, s->path, - control ? "/" : "", control ? control : ""); - } - - rtsp_send_request (s, RTSP_METHOD_SETUP, buf); - free (buf); - return rtsp_get_answers (s); -} - -int rtsp_request_setparameter(rtsp_t *s, const char *what) { - - char *buf; - - if (what) { - buf=strdup(what); - } else - { - buf=malloc(strlen(s->host)+strlen(s->path)+16); - sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); - } - rtsp_send_request(s,RTSP_METHOD_SET_PARAMETER,buf); - free(buf); - - return rtsp_get_answers(s); -} - -int rtsp_request_play(rtsp_t *s, const char *what) { - - char *buf; - int ret; - - if (what) { - buf=strdup(what); - } else - { - buf=malloc(strlen(s->host)+strlen(s->path)+16); - sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); - } - rtsp_send_request(s,RTSP_METHOD_PLAY,buf); - free(buf); - - ret = rtsp_get_answers (s); - if (ret == RTSP_STATUS_OK) - s->server_state = RTSP_PLAYING; - - return ret; -} - -int rtsp_request_teardown(rtsp_t *s, const char *what) { - - char *buf; - - if (what) - buf = strdup (what); - else - { - buf = - malloc (strlen (s->host) + strlen (s->path) + 16); - sprintf (buf, "rtsp://%s:%i/%s", s->host, s->port, s->path); - } - rtsp_send_request (s, RTSP_METHOD_TEARDOWN, buf); - free (buf); - - /* after teardown we're done with RTSP streaming, no need to get answer as - reading more will only result to garbage and buffer overflow */ - return RTSP_STATUS_OK; -} - -/* - * read opaque data from stream - */ - -int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size) { - - int i,seq; - - if (size>=4) { - i=read_stream(s->s, buffer, 4); - if (i<4) return i; - if (((buffer[0]=='S')&&(buffer[1]=='E')&&(buffer[2]=='T')&&(buffer[3]=='_')) || - ((buffer[0]=='O')&&(buffer[1]=='P')&&(buffer[2]=='T')&&(buffer[3]=='I'))) // OPTIONS - { - char *rest=rtsp_get(s); - if (!rest) - return -1; - - seq=-1; - do { - free(rest); - rest=rtsp_get(s); - if (!rest) - return -1; - if (!strncasecmp(rest,"CSeq:",5)) - sscanf(rest,"%*s %u",&seq); - } while (strlen(rest)!=0); - free(rest); - if (seq<0) { -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_WARN, "rtsp: warning: CSeq not recognized!\n"); -#endif - seq=1; - } - /* let's make the server happy */ - rtsp_put(s, "RTSP/1.0 451 Parameter Not Understood"); - rest=malloc(17); - sprintf(rest,"CSeq: %u", seq); - rtsp_put(s, rest); - free(rest); - rtsp_put(s, ""); - i=read_stream(s->s, buffer, size); - } else - { - i=read_stream(s->s, buffer+4, size-4); - i+=4; - } - } else - i=read_stream(s->s, buffer, size); -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: << %d of %d bytes\n", i, size); -#endif - - return i; -} - -/* - * connect to a rtsp server - */ - -//rtsp_t *rtsp_connect(const char *mrl, const char *user_agent) { -rtsp_t *rtsp_connect(int fd, char* mrl, char *path, char *host, int port, char *user_agent) { - - rtsp_t *s=malloc(sizeof(rtsp_t)); - int i; - - for (i=0; i<MAX_FIELDS; i++) { - s->answers[i]=NULL; - s->scheduled[i]=NULL; - } - - s->server=NULL; - s->server_state=0; - s->server_caps=0; - - s->cseq=0; - s->session=NULL; - - if (user_agent) - s->user_agent=strdup(user_agent); - else - s->user_agent=strdup("User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)"); - - s->mrl = strdup(mrl); - s->host = strdup(host); - s->port = port; - s->path = strdup(path); - while (*path == '/') - path++; - if ((s->param = strchr(s->path, '?')) != NULL) - s->param++; - //mp_msg(MSGT_OPEN, MSGL_INFO, "path=%s\n", s->path); - //mp_msg(MSGT_OPEN, MSGL_INFO, "param=%s\n", s->param ? s->param : "NULL"); - s->s = fd; - - if (s->s < 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, "rtsp: failed to connect to '%s'\n", s->host); - rtsp_close(s); - return NULL; - } - - s->server_state=RTSP_CONNECTED; - - /* now let's send an options request. */ - rtsp_schedule_field(s, "CSeq: 1"); - rtsp_schedule_field(s, s->user_agent); - rtsp_schedule_field(s, "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7"); - rtsp_schedule_field(s, "PlayerStarttime: [28/03/2003:22:50:23 00:00]"); - rtsp_schedule_field(s, "CompanyID: KnKV4M4I/B2FjJ1TToLycw=="); - rtsp_schedule_field(s, "GUID: 00000000-0000-0000-0000-000000000000"); - rtsp_schedule_field(s, "RegionData: 0"); - rtsp_schedule_field(s, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); - /*rtsp_schedule_field(s, "Pragma: initiate-session");*/ - rtsp_request_options(s, NULL); - - return s; -} - - -/* - * closes an rtsp connection - */ - -void rtsp_close(rtsp_t *s) { - - if (s->server_state) - { - if (s->server_state == RTSP_PLAYING) - rtsp_request_teardown (s, NULL); - closesocket (s->s); - } - - if (s->path) free(s->path); - if (s->host) free(s->host); - if (s->mrl) free(s->mrl); - if (s->session) free(s->session); - if (s->user_agent) free(s->user_agent); - rtsp_free_answers(s); - rtsp_unschedule_all(s); - free(s); -} - -/* - * search in answers for tags. returns a pointer to the content - * after the first matched tag. returns NULL if no match found. - */ - -char *rtsp_search_answers(rtsp_t *s, const char *tag) { - - char **answer; - char *ptr; - - if (!s->answers) return NULL; - answer=s->answers; - - while (*answer) { - if (!strncasecmp(*answer,tag,strlen(tag))) { - ptr=strchr(*answer,':'); - if (!ptr) return NULL; - ptr++; - while(*ptr==' ') ptr++; - return ptr; - } - answer++; - } - - return NULL; -} - -/* - * session id management - */ - -void rtsp_set_session(rtsp_t *s, const char *id) { - - if (s->session) free(s->session); - - s->session=strdup(id); - -} - -char *rtsp_get_session(rtsp_t *s) { - - return s->session; - -} - -char *rtsp_get_mrl(rtsp_t *s) { - - return s->mrl; - -} - -char *rtsp_get_param(rtsp_t *s, const char *p) { - int len; - char *param; - if (!s->param) - return NULL; - if (!p) - return strdup(s->param); - len = strlen(p); - param = s->param; - while (param && *param) { - char *nparam = strchr(param, '&'); - if (strncmp(param, p, len) == 0 && param[len] == '=') { - param += len + 1; - len = nparam ? nparam - param : strlen(param); - nparam = malloc(len + 1); - memcpy(nparam, param, len); - nparam[len] = 0; - return nparam; - } - param = nparam ? nparam + 1 : NULL; - } - return NULL; -} - -/* - * schedules a field for transmission - */ - -void rtsp_schedule_field(rtsp_t *s, const char *string) { - - int i=0; - - if (!string) return; - - while(s->scheduled[i]) { - i++; - } - s->scheduled[i]=strdup(string); -} - -/* - * removes the first scheduled field which prefix matches string. - */ - -void rtsp_unschedule_field(rtsp_t *s, const char *string) { - - char **ptr=s->scheduled; - - if (!string) return; - - while(*ptr) { - if (!strncmp(*ptr, string, strlen(string))) - break; - else - ptr++; - } - if (*ptr) free(*ptr); - ptr++; - do { - *(ptr-1)=*ptr; - } while(*ptr); -} - -/* - * unschedule all fields - */ - -void rtsp_unschedule_all(rtsp_t *s) { - - char **ptr; - - if (!s->scheduled) return; - ptr=s->scheduled; - - while (*ptr) { - free(*ptr); - *ptr=NULL; - ptr++; - } -} -/* - * free answers - */ - -void rtsp_free_answers(rtsp_t *s) { - - char **answer; - - if (!s->answers) return; - answer=s->answers; - - while (*answer) { - free(*answer); - *answer=NULL; - answer++; - } -}
--- a/libmpdemux/librtsp/rtsp.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rtsp.h,v 1.2 2002/12/16 21:50:55 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * a minimalistic implementation of rtsp protocol, - * *not* RFC 2326 compilant yet. - * - * 2006, Benjamin Zores and Vincent Mussard - * fixed a lot of RFC compliance issues. - */ - -#ifndef HAVE_RTSP_H -#define HAVE_RTSP_H - - -/* some codes returned by rtsp_request_* functions */ - -#define RTSP_STATUS_SET_PARAMETER 10 -#define RTSP_STATUS_OK 200 - -#define RTSP_METHOD_OPTIONS "OPTIONS" -#define RTSP_METHOD_DESCRIBE "DESCRIBE" -#define RTSP_METHOD_SETUP "SETUP" -#define RTSP_METHOD_PLAY "PLAY" -#define RTSP_METHOD_TEARDOWN "TEARDOWN" -#define RTSP_METHOD_SET_PARAMETER "SET_PARAMETER" - -typedef struct rtsp_s rtsp_t; - -rtsp_t* rtsp_connect (int fd, char *mrl, char *path, char *host, int port, char *user_agent); - -int rtsp_request_options(rtsp_t *s, const char *what); -int rtsp_request_describe(rtsp_t *s, const char *what); -int rtsp_request_setup(rtsp_t *s, const char *what, char *control); -int rtsp_request_setparameter(rtsp_t *s, const char *what); -int rtsp_request_play(rtsp_t *s, const char *what); -int rtsp_request_teardown(rtsp_t *s, const char *what); - -int rtsp_send_ok(rtsp_t *s); - -int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size); - -char* rtsp_search_answers(rtsp_t *s, const char *tag); -void rtsp_add_to_payload(char **payload, const char *string); - -void rtsp_free_answers(rtsp_t *this); - -int rtsp_read (rtsp_t *this, char *data, int len); -void rtsp_close (rtsp_t *this); - -void rtsp_set_session(rtsp_t *s, const char *id); -char *rtsp_get_session(rtsp_t *s); - -char *rtsp_get_mrl(rtsp_t *s); -char *rtsp_get_param(rtsp_t *s, const char *param); - -/*int rtsp_peek_header (rtsp_t *this, char *data); */ - -void rtsp_schedule_field(rtsp_t *s, const char *string); -void rtsp_unschedule_field(rtsp_t *s, const char *string); -void rtsp_unschedule_all(rtsp_t *s); - -#endif -
--- a/libmpdemux/librtsp/rtsp_rtp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,700 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Zores - * based on the Freebox patch for xine by Vincent Mussard - * but with many enhancements for better RTSP RFC compliance. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/types.h> -#include <inttypes.h> - -#include "config.h" - -#ifndef HAVE_WINSOCK2 -#include <netdb.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#else -#include <winsock2.h> -#include <ws2tcpip.h> -#endif - -#include "mp_msg.h" -#include "rtsp.h" -#include "rtsp_rtp.h" -#include "rtsp_session.h" -#include "../freesdp/common.h" -#include "../freesdp/parser.h" - -#define RTSP_DEFAULT_PORT 31336 -#define MAX_LENGTH 256 - -#define RTSP_ACCEPT_SDP "Accept: application/sdp" -#define RTSP_CONTENT_LENGTH "Content-length" -#define RTSP_CONTENT_TYPE "Content-Type" -#define RTSP_APPLICATION_SDP "application/sdp" -#define RTSP_RANGE "Range: " -#define RTSP_NPT_NOW "npt=now-" -#define RTSP_MEDIA_CONTAINER_MPEG_TS "33" -#define RTSP_TRANSPORT_REQUEST "Transport: RTP/AVP;%s;%s%i-%i;mode=\"PLAY\"" - -#define RTSP_TRANSPORT_MULTICAST "multicast" -#define RTSP_TRANSPORT_UNICAST "unicast" - -#define RTSP_MULTICAST_PORT "port=" -#define RTSP_UNICAST_CLIENT_PORT "client_port=" -#define RTSP_UNICAST_SERVER_PORT "server_port=" -#define RTSP_SETUP_DESTINATION "destination=" - -#define RTSP_SESSION "Session" -#define RTSP_TRANSPORT "Transport" - -/* hardcoded RTCP RR - this is _NOT_ RFC compliant */ -#define RTCP_RR_SIZE 32 -#define RTCP_RR "\201\311\0\7(.JD\31+\306\343\0\0\0\0\0\0/E\0\0\2&\0\0\0\0\0\0\0\0\201" -#define RTCP_SEND_FREQUENCY 1024 - -int rtsp_port = 0; -char *rtsp_destination = NULL; - -void -rtcp_send_rr (rtsp_t *s, struct rtp_rtsp_session_t *st) -{ - if (st->rtcp_socket == -1) - return; - - /* send RTCP RR every RTCP_SEND_FREQUENCY packets - * FIXME : NOT CORRECT, HARDCODED, BUT MAKES SOME SERVERS HAPPY - * not rfc compliant - * http://www.faqs.org/rfcs/rfc1889.html chapter 6 for RTCP - */ - - if (st->count == RTCP_SEND_FREQUENCY) - { - char rtcp_content[RTCP_RR_SIZE]; - strcpy (rtcp_content, RTCP_RR); - send (st->rtcp_socket, rtcp_content, RTCP_RR_SIZE, 0); - - /* ping RTSP server to keep connection alive. - we use OPTIONS instead of PING as not all servers support it */ - rtsp_request_options (s, "*"); - st->count = 0; - } - else - st->count++; -} - -static struct rtp_rtsp_session_t * -rtp_session_new (void) -{ - struct rtp_rtsp_session_t *st = NULL; - - st = malloc (sizeof (struct rtp_rtsp_session_t)); - - st->rtp_socket = -1; - st->rtcp_socket = -1; - st->control_url = NULL; - st->count = 0; - - return st; -} - -void -rtp_session_free (struct rtp_rtsp_session_t *st) -{ - if (!st) - return; - - if (st->rtp_socket != -1) - close (st->rtp_socket); - if (st->rtcp_socket != -1) - close (st->rtcp_socket); - - if (st->control_url) - free (st->control_url); - free (st); -} - -static void -rtp_session_set_fd (struct rtp_rtsp_session_t *st, - int rtp_sock, int rtcp_sock) -{ - if (!st) - return; - - st->rtp_socket = rtp_sock; - st->rtcp_socket = rtcp_sock; -} - -static int -parse_port (const char *line, const char *param, - int *rtp_port, int *rtcp_port) -{ - char *parse1; - char *parse2; - char *parse3; - - char *line_copy = strdup (line); - - parse1 = strstr (line_copy, param); - - if (parse1) - { - parse2 = strstr (parse1, "-"); - - if (parse2) - { - parse3 = strstr (parse2, ";"); - - if (parse3) - parse3[0] = 0; - - parse2[0] = 0; - } - else - { - free (line_copy); - return 0; - } - } - else - { - free (line_copy); - return 0; - } - - *rtp_port = atoi (parse1 + strlen (param)); - *rtcp_port = atoi (parse2 + 1); - - free (line_copy); - - return 1; -} - -static char * -parse_destination (const char *line) -{ - char *parse1; - char *parse2; - - char *dest = NULL; - char *line_copy = strdup (line); - int len; - - parse1 = strstr (line_copy, RTSP_SETUP_DESTINATION); - if (!parse1) - { - free (line_copy); - return NULL; - } - - parse2 = strstr (parse1, ";"); - if (!parse2) - { - free (line_copy); - return NULL; - } - - len = strlen (parse1) - strlen (parse2) - - strlen (RTSP_SETUP_DESTINATION) + 1; - dest = (char *) malloc (len + 1); - snprintf (dest, len, parse1 + strlen (RTSP_SETUP_DESTINATION)); - free (line_copy); - - return dest; -} - -static int -rtcp_connect (int client_port, int server_port, const char* server_hostname) -{ - struct sockaddr_in sin; - struct hostent *hp; - int s; - - if (client_port <= 1023) - return -1; - - s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (s == -1) - return -1; - - hp = gethostbyname (server_hostname); - if (!hp) - { - close (s); - return -1; - } - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons (client_port); - - if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) - { -#ifndef HAVE_WINSOCK2 - if (errno != EINPROGRESS) -#else - if (WSAGetLastError() != WSAEINPROGRESS) -#endif - { - close (s); - return -1; - } - } - - sin.sin_family = AF_INET; - memcpy (&(sin.sin_addr.s_addr), hp->h_addr, sizeof (hp->h_addr)); - sin.sin_port = htons (server_port); - - /* datagram socket */ - if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) - { - close (s); - return -1; - } - - return s; -} - -static int -rtp_connect (char *hostname, int port) -{ - struct sockaddr_in sin; - struct timeval tv; - int err, err_len; - int rxsockbufsz; - int s; - fd_set set; - - if (port <= 1023) - return -1; - - s = socket (PF_INET, SOCK_DGRAM, 0); - if (s == -1) - return -1; - - sin.sin_family = AF_INET; - if (!hostname || !strcmp (hostname, "0.0.0.0")) - sin.sin_addr.s_addr = htonl (INADDR_ANY); - else -#ifndef HAVE_WINSOCK2 -#ifdef USE_ATON - inet_aton (hostname, &sin.sin_addr); -#else - inet_pton (AF_INET, hostname, &sin.sin_addr); -#endif -#else - sin.sin_addr.s_addr = htonl (INADDR_ANY); -#endif - sin.sin_port = htons (port); - - /* Increase the socket rx buffer size to maximum -- this is UDP */ - rxsockbufsz = 240 * 1024; - if (setsockopt (s, SOL_SOCKET, SO_RCVBUF, - &rxsockbufsz, sizeof (rxsockbufsz))) - mp_msg (MSGT_OPEN, MSGL_ERR, "Couldn't set receive socket buffer size\n"); - - /* if multicast address, add membership */ - if ((ntohl (sin.sin_addr.s_addr) >> 28) == 0xe) - { - struct ip_mreq mcast; - mcast.imr_multiaddr.s_addr = sin.sin_addr.s_addr; - mcast.imr_interface.s_addr = 0; - - if (setsockopt (s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof (mcast))) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "IP_ADD_MEMBERSHIP failed\n"); - close (s); - return -1; - } - } - - /* datagram socket */ - if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) - { -#ifndef HAVE_WINSOCK2 - if (errno != EINPROGRESS) -#else - if (WSAGetLastError() != WSAEINPROGRESS) -#endif - { - mp_msg (MSGT_OPEN, MSGL_ERR, "bind: %s\n", strerror (errno)); - close (s); - return -1; - } - } - - tv.tv_sec = 0; - tv.tv_usec = (1 * 1000000); /* 1 second timeout */ - - FD_ZERO (&set); - FD_SET (s, &set); - - err = select (s + 1, &set, NULL, NULL, &tv); - if (err < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "Select failed: %s\n", strerror (errno)); - close (s); - return -1; - } - else if (err == 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "Timeout! No data from host %s\n", hostname); - close (s); - return -1; - } - - err_len = sizeof (err); - getsockopt (s, SOL_SOCKET, SO_ERROR, &err, (socklen_t *) &err_len); - if (err) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "Socket error: %d\n", err); - close (s); - return -1; - } - - return s; -} - -static int -is_multicast_address (char *addr) -{ - struct sockaddr_in sin; - - if (!addr) - return -1; - - sin.sin_family = AF_INET; - -#ifndef HAVE_WINSOCK2 -#ifdef USE_ATON - inet_aton (addr, &sin.sin_addr); -#else - inet_pton (AF_INET, addr, &sin.sin_addr); -#endif -#else - sin.sin_addr.s_addr = htonl (INADDR_ANY); -#endif - - if ((ntohl (sin.sin_addr.s_addr) >> 28) == 0xe) - return 1; - - return 0; -} - -struct rtp_rtsp_session_t * -rtp_setup_and_play (rtsp_t *rtsp_session) -{ - struct rtp_rtsp_session_t* rtp_session = NULL; - const fsdp_media_description_t *med_dsc = NULL; - char temp_buf[MAX_LENGTH + 1]; - char npt[256]; - - char* answer; - char* sdp; - char *server_addr = NULL; - char *destination = NULL; - - int statut; - int content_length = 0; - int is_multicast = 0; - - fsdp_description_t *dsc = NULL; - fsdp_error_t result; - - int client_rtp_port = -1; - int client_rtcp_port = -1; - int server_rtp_port = -1; - int server_rtcp_port = -1; - int rtp_sock = -1; - int rtcp_sock = -1; - - /* 1. send a RTSP DESCRIBE request to server */ - rtsp_schedule_field (rtsp_session, RTSP_ACCEPT_SDP); - statut = rtsp_request_describe (rtsp_session, NULL); - if (statut < 200 || statut > 299) - return NULL; - - answer = rtsp_search_answers (rtsp_session, RTSP_CONTENT_LENGTH); - if (answer) - content_length = atoi (answer); - else - return NULL; - - answer = rtsp_search_answers (rtsp_session, RTSP_CONTENT_TYPE); - if (!answer || !strstr (answer, RTSP_APPLICATION_SDP)) - return NULL; - - /* 2. read SDP message from server */ - sdp = (char *) malloc (content_length + 1); - if (rtsp_read_data (rtsp_session, sdp, content_length) <= 0) - { - free (sdp); - return NULL; - } - sdp[content_length] = 0; - - /* 3. parse SDP message */ - dsc = fsdp_description_new (); - result = fsdp_parse (sdp, dsc); - if (result != FSDPE_OK) - { - free (sdp); - fsdp_description_delete (dsc); - return NULL; - } - mp_msg (MSGT_OPEN, MSGL_V, "SDP:\n%s\n", sdp); - free (sdp); - - /* 4. check for number of media streams: only one is supported */ - if (fsdp_get_media_count (dsc) != 1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "A single media stream only is supported atm.\n"); - fsdp_description_delete (dsc); - return NULL; - } - - /* 5. set the Normal Play Time parameter - * use range provided by server in SDP or start now if empty */ - sprintf (npt, RTSP_RANGE); - if (fsdp_get_range (dsc)) - strcat (npt, fsdp_get_range (dsc)); - else - strcat (npt, RTSP_NPT_NOW); - - /* 5. check for a valid media stream */ - med_dsc = fsdp_get_media (dsc, 0); - if (!med_dsc) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* 6. parse the `m=<media> <port> <transport> <fmt list>' line */ - - /* check for an A/V media */ - if (fsdp_get_media_type (med_dsc) != FSDP_MEDIA_VIDEO && - fsdp_get_media_type (med_dsc) != FSDP_MEDIA_AUDIO) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* only RTP/AVP transport method is supported right now */ - if (fsdp_get_media_transport_protocol (med_dsc) != FSDP_TP_RTP_AVP) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* only MPEG-TS is supported at the moment */ - if (!strstr (fsdp_get_media_format (med_dsc, 0), - RTSP_MEDIA_CONTAINER_MPEG_TS)) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* get client port (if any) advised by server */ - client_rtp_port = fsdp_get_media_port (med_dsc); - if (client_rtp_port == -1) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* if client_rtp_port = 0 => let client randomly pick one */ - if (client_rtp_port == 0) - { - /* TODO: we should check if the port is in use first */ - if (rtsp_port) - client_rtp_port = rtsp_port; - else - client_rtp_port = RTSP_DEFAULT_PORT; - } - - /* RTCP port generally is RTP port + 1 */ - client_rtcp_port = client_rtp_port + 1; - - mp_msg (MSGT_OPEN, MSGL_V, - "RTP Port from SDP appears to be: %d\n", client_rtp_port); - mp_msg (MSGT_OPEN, MSGL_V, - "RTCP Port from SDP appears to be: %d\n", client_rtcp_port); - - /* 7. parse the `c=<network type> <addr type> <connection address>' line */ - - /* check for a valid media network type (inet) */ - if (fsdp_get_media_network_type (med_dsc) != FSDP_NETWORK_TYPE_INET) - { - /* no control for media: try global one instead */ - if (fsdp_get_global_conn_network_type (dsc) != FSDP_NETWORK_TYPE_INET) - { - fsdp_description_delete (dsc); - return NULL; - } - } - - /* only IPv4 is supported atm. */ - if (fsdp_get_media_address_type (med_dsc) != FSDP_ADDRESS_TYPE_IPV4) - { - /* no control for media: try global one instead */ - if (fsdp_get_global_conn_address_type (dsc) != FSDP_ADDRESS_TYPE_IPV4) - { - fsdp_description_delete (dsc); - return NULL; - } - } - - /* get the media server address to connect to */ - if (fsdp_get_media_address (med_dsc)) - server_addr = strdup (fsdp_get_media_address (med_dsc)); - else if (fsdp_get_global_conn_address (dsc)) - { - /* no control for media: try global one instead */ - server_addr = strdup (fsdp_get_global_conn_address (dsc)); - } - - if (!server_addr) - { - fsdp_description_delete (dsc); - return NULL; - } - - /* check for a UNICAST or MULTICAST address to connect to */ - is_multicast = is_multicast_address (server_addr); - - /* 8. initiate an RTP session */ - rtp_session = rtp_session_new (); - if (!rtp_session) - { - free (server_addr); - fsdp_description_delete (dsc); - return NULL; - } - - /* get the media control URL */ - if (fsdp_get_media_control (med_dsc, 0)) - rtp_session->control_url = strdup (fsdp_get_media_control (med_dsc, 0)); - fsdp_description_delete (dsc); - if (!rtp_session->control_url) - { - free (server_addr); - rtp_session_free (rtp_session); - return NULL; - } - - /* 9. create the payload for RTSP SETUP request */ - memset (temp_buf, '\0', MAX_LENGTH); - snprintf (temp_buf, MAX_LENGTH, - RTSP_TRANSPORT_REQUEST, - is_multicast ? RTSP_TRANSPORT_MULTICAST : RTSP_TRANSPORT_UNICAST, - is_multicast ? RTSP_MULTICAST_PORT : RTSP_UNICAST_CLIENT_PORT, - client_rtp_port, client_rtcp_port); - mp_msg (MSGT_OPEN, MSGL_V, "RTSP Transport: %s\n", temp_buf); - - rtsp_unschedule_field (rtsp_session, RTSP_SESSION); - rtsp_schedule_field (rtsp_session, temp_buf); - - /* 10. check for the media control URL type and initiate RTSP SETUP */ - if (!strncmp (rtp_session->control_url, "rtsp://", 7)) /* absolute URL */ - statut = rtsp_request_setup (rtsp_session, - rtp_session->control_url, NULL); - else /* relative URL */ - statut = rtsp_request_setup (rtsp_session, - NULL, rtp_session->control_url); - - if (statut < 200 || statut > 299) - { - free (server_addr); - rtp_session_free (rtp_session); - return NULL; - } - - /* 11. parse RTSP SETUP response: we need it to actually determine - * the real address and port to connect to */ - answer = rtsp_search_answers (rtsp_session, RTSP_TRANSPORT); - if (!answer) - { - free (server_addr); - rtp_session_free (rtp_session); - return NULL; - } - - /* check for RTP and RTCP ports to bind according to how request was done */ - is_multicast = 0; - if (strstr (answer, RTSP_TRANSPORT_MULTICAST)) - is_multicast = 1; - - if (is_multicast) - parse_port (answer, RTSP_MULTICAST_PORT, - &client_rtp_port, &client_rtcp_port); - else - { - parse_port (answer, RTSP_UNICAST_CLIENT_PORT, - &client_rtp_port, &client_rtcp_port); - parse_port (answer, RTSP_UNICAST_SERVER_PORT, - &server_rtp_port, &server_rtcp_port); - } - - /* now check network settings as determined by server */ - if (rtsp_destination) - destination = strdup (rtsp_destination); - else - destination = parse_destination (answer); - if (!destination) - destination = strdup (server_addr); - free (server_addr); - - mp_msg (MSGT_OPEN, MSGL_V, "RTSP Destination: %s\n", destination); - mp_msg (MSGT_OPEN, MSGL_V, "Client RTP port : %d\n", client_rtp_port); - mp_msg (MSGT_OPEN, MSGL_V, "Client RTCP port : %d\n", client_rtcp_port); - mp_msg (MSGT_OPEN, MSGL_V, "Server RTP port : %d\n", server_rtp_port); - mp_msg (MSGT_OPEN, MSGL_V, "Server RTCP port : %d\n", server_rtcp_port); - - /* 12. performs RTSP PLAY request */ - rtsp_schedule_field (rtsp_session, npt); - statut = rtsp_request_play (rtsp_session, NULL); - if (statut < 200 || statut > 299) - { - free (destination); - rtp_session_free (rtp_session); - return NULL; - } - - /* 13. create RTP and RTCP connections */ - rtp_sock = rtp_connect (destination, client_rtp_port); - rtcp_sock = rtcp_connect (client_rtcp_port, server_rtcp_port, destination); - rtp_session_set_fd (rtp_session, rtp_sock, rtcp_sock); - free (destination); - - mp_msg (MSGT_OPEN, MSGL_V, "RTP Sock : %d\nRTCP Sock : %d\n", - rtp_session->rtp_socket, rtp_session->rtcp_socket); - - if (rtp_session->rtp_socket == -1) - { - rtp_session_free (rtp_session); - return NULL; - } - - return rtp_session; -}
--- a/libmpdemux/librtsp/rtsp_rtp.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Zores - * heavily base on the Freebox patch for xine by Vincent Mussard - * but with many enhancements for better RTSP RFC compliance. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _HAVE_RTSP_RTP_H_ -#define _HAVE_RTSP_RTP_H_ - -#include "rtsp.h" - -#define MAX_PREVIEW_SIZE 4096 - -struct rtp_rtsp_session_t { - int rtp_socket; - int rtcp_socket; - char *control_url; - int count; -}; - -struct rtp_rtsp_session_t *rtp_setup_and_play (rtsp_t* rtsp_session); -off_t rtp_read (struct rtp_rtsp_session_t* st, char *buf, off_t length); -void rtp_session_free (struct rtp_rtsp_session_t *st); -void rtcp_send_rr (rtsp_t *s, struct rtp_rtsp_session_t *st); - -#endif /* _HAVE_RTSP_RTP_H_ */ -
--- a/libmpdemux/librtsp/rtsp_session.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rtsp_session.c,v 1.9 2003/02/11 16:20:40 - */ - -/* - * Copyright (C) 2000-2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * high level interface to rtsp servers. - * - * 2006, Benjamin Zores and Vincent Mussard - * Support for MPEG-TS streaming through RFC compliant RTSP servers - */ - -#include <sys/types.h> -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#else -#include <winsock2.h> -#endif -#include <unistd.h> -#include <stdio.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> - -#include "mp_msg.h" -#include "../rtp.h" -#include "rtsp.h" -#include "rtsp_rtp.h" -#include "rtsp_session.h" -#include "../realrtsp/real.h" -#include "../realrtsp/rmff.h" -#include "../realrtsp/asmrp.h" -#include "../realrtsp/xbuffer.h" - -/* -#define LOG -*/ - -#define RTSP_OPTIONS_PUBLIC "Public" -#define RTSP_OPTIONS_SERVER "Server" -#define RTSP_OPTIONS_LOCATION "Location" -#define RTSP_OPTIONS_REAL "RealChallenge1" -#define RTSP_SERVER_TYPE_REAL "Real" -#define RTSP_SERVER_TYPE_HELIX "Helix" -#define RTSP_SERVER_TYPE_UNKNOWN "unknown" - -struct rtsp_session_s { - rtsp_t *s; - struct real_rtsp_session_t* real_session; - struct rtp_rtsp_session_t* rtp_session; -}; - -//rtsp_session_t *rtsp_session_start(char *mrl) { -rtsp_session_t *rtsp_session_start(int fd, char **mrl, char *path, char *host, int port, int *redir, uint32_t bandwidth) { - - rtsp_session_t *rtsp_session = NULL; - char *server; - char *mrl_line = NULL; - rmff_header_t *h; - - rtsp_session = malloc (sizeof (rtsp_session_t)); - rtsp_session->s = NULL; - rtsp_session->real_session = NULL; - rtsp_session->rtp_session = NULL; - -//connect: - *redir = 0; - - /* connect to server */ - rtsp_session->s=rtsp_connect(fd,*mrl,path,host,port,NULL); - if (!rtsp_session->s) - { - mp_msg (MSGT_OPEN, MSGL_ERR,"rtsp_session: failed to connect to server %s\n", path); - free(rtsp_session); - return NULL; - } - - /* looking for server type */ - if (rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_SERVER)) - server=strdup(rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_SERVER)); - else { - if (rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_REAL)) - server=strdup(RTSP_SERVER_TYPE_REAL); - else - server=strdup(RTSP_SERVER_TYPE_UNKNOWN); - } - if (strstr(server,RTSP_SERVER_TYPE_REAL) || strstr(server,RTSP_SERVER_TYPE_HELIX)) - { - /* we are talking to a real server ... */ - - h=real_setup_and_get_header(rtsp_session->s, bandwidth); - if (!h) { - /* got an redirect? */ - if (rtsp_search_answers(rtsp_session->s, RTSP_OPTIONS_LOCATION)) - { - free(mrl_line); - mrl_line=strdup(rtsp_search_answers(rtsp_session->s, RTSP_OPTIONS_LOCATION)); - mp_msg (MSGT_OPEN, MSGL_INFO,"rtsp_session: redirected to %s\n", mrl_line); - rtsp_close(rtsp_session->s); - free(server); - free(*mrl); - free(rtsp_session); - /* tell the caller to redirect, return url to redirect to in mrl */ - *mrl = mrl_line; - *redir = 1; - return NULL; -// goto connect; /* *shudder* i made a design mistake somewhere */ - } else - { - mp_msg (MSGT_OPEN, MSGL_ERR,"rtsp_session: session can not be established.\n"); - rtsp_close(rtsp_session->s); - free (server); - free(rtsp_session); - return NULL; - } - } - - rtsp_session->real_session = init_real_rtsp_session (); - rtsp_session->real_session->header_len = - rmff_dump_header (h, (char *) rtsp_session->real_session->header, 1024); - - rtsp_session->real_session->recv = - xbuffer_copyin (rtsp_session->real_session->recv, 0, - rtsp_session->real_session->header, - rtsp_session->real_session->header_len); - - rtsp_session->real_session->recv_size = - rtsp_session->real_session->header_len; - rtsp_session->real_session->recv_read = 0; - } else /* not a Real server : try RTP instead */ - { - char *public = NULL; - - /* look for the Public: field in response to RTSP OPTIONS */ - public = strdup (rtsp_search_answers (rtsp_session->s, - RTSP_OPTIONS_PUBLIC)); - if (!public) - { - rtsp_close (rtsp_session->s); - free (server); - free (mrl_line); - free (rtsp_session); - return NULL; - } - - /* check for minimalistic RTSP RFC compliance */ - if (!strstr (public, RTSP_METHOD_DESCRIBE) - || !strstr (public, RTSP_METHOD_SETUP) - || !strstr (public, RTSP_METHOD_PLAY) - || !strstr (public, RTSP_METHOD_TEARDOWN)) - { - free (public); - mp_msg (MSGT_OPEN, MSGL_ERR, - "Remote server does not meet minimal RTSP 1.0 compliance.\n"); - rtsp_close (rtsp_session->s); - free (server); - free (mrl_line); - free (rtsp_session); - return NULL; - } - - free (public); - rtsp_session->rtp_session = rtp_setup_and_play (rtsp_session->s); - - /* neither a Real or an RTP server */ - if (!rtsp_session->rtp_session) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "rtsp_session: unsupported RTSP server. "); - mp_msg (MSGT_OPEN, MSGL_ERR, "Server type is '%s'.\n", server); - rtsp_close (rtsp_session->s); - free (server); - free (mrl_line); - free (rtsp_session); - return NULL; - } - } - free(server); - - return rtsp_session; -} - -int rtsp_session_read (rtsp_session_t *this, char *data, int len) { - - if (this->real_session) { - int to_copy=len; - char *dest=data; - char *source = - (char *) (this->real_session->recv + this->real_session->recv_read); - int fill = this->real_session->recv_size - this->real_session->recv_read; - - if (len < 0) return 0; - while (to_copy > fill) { - - memcpy(dest, source, fill); - to_copy -= fill; - dest += fill; - this->real_session->recv_read = 0; - this->real_session->recv_size = - real_get_rdt_chunk (this->s, (char **)&(this->real_session->recv)); - if (this->real_session->recv_size < 0) - return -1; - source = (char *) this->real_session->recv; - fill = this->real_session->recv_size; - - if (this->real_session->recv_size == 0) { -#ifdef LOG - mp_msg (MSGT_OPEN, MSGL_INFO, "librtsp: %d of %d bytes provided\n", len-to_copy, len); -#endif - return len-to_copy; - } - } - - memcpy(dest, source, to_copy); - this->real_session->recv_read += to_copy; - -#ifdef LOG - mp_msg (MSGT_OPEN, MSGL_INFO, "librtsp: %d bytes provided\n", len); -#endif - - return len; - } - else if (this->rtp_session) - { - int l = 0; - - l = read_rtp_from_server (this->rtp_session->rtp_socket, data, len); - /* send RTSP and RTCP keepalive */ - rtcp_send_rr (this->s, this->rtp_session); - - if (l == 0) - rtsp_session_end (this); - - return l; - } - - return 0; -} - -void rtsp_session_end(rtsp_session_t *session) { - - rtsp_close(session->s); - if (session->real_session) - free_real_rtsp_session (session->real_session); - if (session->rtp_session) - rtp_session_free (session->rtp_session); - free(session); -}
--- a/libmpdemux/librtsp/rtsp_session.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rtsp_session.h,v 1.4 2003/01/31 14:06:18 - */ - -/* - * Copyright (C) 2000-2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * high level interface to rtsp servers. - * - * 2006, Benjamin Zores and Vincent Mussard - * Support for MPEG-TS streaming through RFC compliant RTSP servers - */ - -#ifndef HAVE_RTSP_SESSION_H -#define HAVE_RTSP_SESSION_H - -typedef struct rtsp_session_s rtsp_session_t; - -rtsp_session_t *rtsp_session_start(int fd, char **mrl, char *path, char *host, int port, int *redir, uint32_t bandwidth); - -int rtsp_session_read(rtsp_session_t *session, char *data, int len); - -void rtsp_session_end(rtsp_session_t *session); - -#endif
--- a/libmpdemux/mf.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ - -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "config.h" - -#ifdef HAVE_GLOB -#include <glob.h> -#else -#include "osdep/glob.h" -#endif - -#include "mp_msg.h" -#include "help_mp.h" -#include "stream.h" - -#include "mf.h" - -int mf_w = 0; //352; // let codecs to detect it -int mf_h = 0; //288; -float mf_fps = 25.0; -char * mf_type = NULL; //"jpg"; - -mf_t* open_mf(char * filename){ -#if defined(HAVE_GLOB) || defined(__MINGW32__) - glob_t gg; - struct stat fs; - int i; - char * fname; - mf_t * mf; - int error_count = 0; - int count = 0; - - mf=calloc( 1,sizeof( mf_t ) ); - - if( filename[0] == '@' ) - { - FILE *lst_f=fopen(filename + 1,"r"); - if ( lst_f ) - { - fname=malloc( 255 ); - while ( fgets( fname,255,lst_f ) ) - { - /* remove spaces from end of fname */ - char *t=fname + strlen( fname ) - 1; - while ( t > fname && isspace( *t ) ) *(t--)=0; - if ( stat( fname,&fs ) ) - { - mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); - } - else - { - mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); - mf->names[mf->nr_of_files]=strdup( fname ); - mf->nr_of_files++; - } - } - fclose( lst_f ); - - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); - goto exit_mf; - } - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] %s is not indirect filelist\n",filename+1 ); - } - - if( strchr( filename,',') ) - { - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] filelist: %s\n",filename ); - - while ( ( fname=strsep( &filename,"," ) ) ) - { - if ( stat( fname,&fs ) ) - { - mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); - } - else - { - mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); - mf->names[mf->nr_of_files]=strdup( fname ); -// mp_msg( MSGT_STREAM,MSGL_V,"[mf] added file %d.: %s\n",mf->nr_of_files,mf->names[mf->nr_of_files] ); - mf->nr_of_files++; - } - } - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); - - goto exit_mf; - } - - fname=malloc( strlen( filename ) + 32 ); - - if ( !strchr( filename,'%' ) ) - { - strcpy( fname,filename ); - if ( !strchr( filename,'*' ) ) strcat( fname,"*" ); - - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] search expr: %s\n",fname ); - - if ( glob( fname,0,NULL,&gg ) ) - { free( mf ); free( fname ); return NULL; } - - mf->nr_of_files=gg.gl_pathc; - mf->names=calloc( gg.gl_pathc, sizeof( char* ) ); - - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d (%d)\n",mf->nr_of_files, gg.gl_pathc * sizeof( char* ) ); - - for( i=0;i < gg.gl_pathc;i++ ) - { - stat( gg.gl_pathv[i],&fs ); - if( S_ISDIR( fs.st_mode ) ) continue; - mf->names[i]=strdup( gg.gl_pathv[i] ); -// mp_msg( MSGT_STREAM,MSGL_DBG2,"[mf] added file %d.: %s\n",i,mf->names[i] ); - } - globfree( &gg ); - goto exit_mf; - } - - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] search expr: %s\n",filename ); - - while ( error_count < 5 ) - { - sprintf( fname,filename,count++ ); - if ( stat( fname,&fs ) ) - { - error_count++; - mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); - } - else - { - mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); - mf->names[mf->nr_of_files]=strdup( fname ); -// mp_msg( MSGT_STREAM,MSGL_V,"[mf] added file %d.: %s\n",mf->nr_of_files,mf->names[mf->nr_of_files] ); - mf->nr_of_files++; - } - } - - mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); - -exit_mf: - free( fname ); - return mf; -#else - mp_msg(MSGT_STREAM,MSGL_FATAL,"[mf] mf support is disabled on your os\n"); - return 0; -#endif -} -
--- a/libmpdemux/mf.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ - -#ifndef _MF_H -#define _MF_H - -extern int mf_w; -extern int mf_h; -extern float mf_fps; -extern char * mf_type; - -typedef struct -{ - int curr_frame; - int nr_of_files; - char ** names; -} mf_t; - -mf_t* open_mf(char * filename); - -#endif
--- a/libmpdemux/netstream.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,136 +0,0 @@ - -/* - * Common stuff for netstream - * Packets and so on are defined here along with a few helpers - * wich are used by both the client and the server - * - * Data is always low endian - */ - -typedef struct mp_net_stream_packet_st { - uint16_t len; - uint8_t cmd; - char data[0]; -} __attribute__ ((packed)) mp_net_stream_packet_t; - -#define PACKET_MAX_SIZE 4096 - -// Commands sent by the client -#define NET_STREAM_OPEN 0 -// data is the url -#define NET_STREAM_FILL_BUFFER 1 -// data is an uint16 wich is the max len of the data to return -#define NET_STREAM_SEEK 3 -// data is an uint64 wich the pos where to seek -#define NET_STREAM_CLOSE 4 -// no data -#define NET_STREAM_RESET 5 -// no data - -// Server response -#define NET_STREAM_OK 128 -// Data returned if open is successful -typedef struct mp_net_stream_opened_st { - uint32_t file_format; - uint32_t flags; - uint32_t sector_size; - uint64_t start_pos; - uint64_t end_pos; -} __attribute__ ((packed)) mp_net_stream_opened_t; -// FILL_BUFFER return the data -// CLOSE return nothing -#define NET_STREAM_ERROR 129 -// Data is the error message (if any ;) - -static int net_read(int fd, char* buf, int len) { - int r = 0; - while(len) { - r = recv(fd,buf,len,0); - if(r <= 0) { - if(errno == EINTR) continue; - if(r < 0) - mp_msg(MSGT_NETST,MSGL_ERR,"Read failed: %s\n",strerror(errno)); - return 0; - } - len -= r; - buf += r; - } - return 1; -} - -static mp_net_stream_packet_t* read_packet(int fd) { - uint16_t len; - mp_net_stream_packet_t* pack = - (mp_net_stream_packet_t*)malloc(sizeof(mp_net_stream_packet_t)); - - if(!net_read(fd,(char*)pack,sizeof(mp_net_stream_packet_t))) { - free(pack); - return NULL; - } - pack->len = le2me_16(pack->len); - - if(pack->len < sizeof(mp_net_stream_packet_t)) { - mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid packet (too small: %d)\n",pack->len); - free(pack); - return NULL; - } - if(pack->len > PACKET_MAX_SIZE) { - mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid packet (too big: %d)\n",pack->len); - free(pack); - return NULL; - } - len = pack->len; - if(len > sizeof(mp_net_stream_packet_t)) { - pack = realloc(pack,len); - if(!pack) { - mp_msg(MSGT_NETST,MSGL_ERR,"Failed to get memory for the packet (%d bytes)\n",len); - return NULL; - } - if(!net_read(fd,pack->data,len - sizeof(mp_net_stream_packet_t))) - return NULL; - } - // printf ("Read packet %d %d %d\n",fd,pack->cmd,pack->len); - return pack; -} - -static int net_write(int fd, char* buf, int len) { - int w; - while(len) { - w = send(fd,buf,len,0); - if(w <= 0) { - if(errno == EINTR) continue; - if(w < 0) - mp_msg(MSGT_NETST,MSGL_ERR,"Write failed: %s\n",strerror(errno)); - return 0; - } - len -= w; - buf += w; - } - return 1; -} - -static int write_packet(int fd, uint8_t cmd,char* data,int len) { - mp_net_stream_packet_t* pack = malloc(len + sizeof(mp_net_stream_packet_t)); - - if(len > 0 && data) - memcpy(pack->data,data,len); - pack->len = len + sizeof(mp_net_stream_packet_t); - pack->cmd = cmd; - - // printf("Write packet %d %d (%p) %d\n",fd,cmd,data,len); - pack->len = le2me_16(pack->len); - if(net_write(fd,(char*)pack,pack->len)) { - free(pack); - return 1; - } - free(pack); - return 0; -} - -static void net_stream_opened_2_me(mp_net_stream_opened_t* o) { - o->file_format = le2me_32(o->file_format); - o->flags = le2me_32(o->flags); - o->sector_size = le2me_32(o->sector_size); - o->start_pos = le2me_64(o->start_pos); - o->end_pos = le2me_64(o->end_pos); -}
--- a/libmpdemux/network.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,657 +0,0 @@ -/* - * Network layer for MPlayer - * by Bertrand BAUDET <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - */ - -//#define DUMP2FILE - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <errno.h> -#include <ctype.h> - -#include "config.h" - -#include "mp_msg.h" -#include "help_mp.h" - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#else -#include <winsock2.h> -#include <ws2tcpip.h> -#endif - -#include "stream.h" -#include "demuxer.h" -#include "m_config.h" - -#include "network.h" -#include "http.h" -#include "cookies.h" -#include "url.h" - -#include "version.h" - -extern int stream_cache_size; - -extern int mp_input_check_interrupt(int time); - -/* Variables for the command line option -user, -passwd, -bandwidth, - -user-agent and -nocookies */ - -char *network_username=NULL; -char *network_password=NULL; -int network_bandwidth=0; -int network_cookies_enabled = 0; -char *network_useragent=NULL; - -/* IPv6 options */ -int network_prefer_ipv4 = 0; -int network_ipv4_only_proxy = 0; - - -mime_struct_t mime_type_table[] = { - // MP3 streaming, some MP3 streaming server answer with audio/mpeg - { "audio/mpeg", DEMUXER_TYPE_AUDIO }, - // MPEG streaming - { "video/mpeg", DEMUXER_TYPE_UNKNOWN }, - { "video/x-mpeg", DEMUXER_TYPE_UNKNOWN }, - { "video/x-mpeg2", DEMUXER_TYPE_UNKNOWN }, - // AVI ??? => video/x-msvideo - { "video/x-msvideo", DEMUXER_TYPE_AVI }, - // MOV => video/quicktime - { "video/quicktime", DEMUXER_TYPE_MOV }, - // ASF - { "audio/x-ms-wax", DEMUXER_TYPE_ASF }, - { "audio/x-ms-wma", DEMUXER_TYPE_ASF }, - { "video/x-ms-asf", DEMUXER_TYPE_ASF }, - { "video/x-ms-afs", DEMUXER_TYPE_ASF }, - { "video/x-ms-wvx", DEMUXER_TYPE_ASF }, - { "video/x-ms-wmv", DEMUXER_TYPE_ASF }, - { "video/x-ms-wma", DEMUXER_TYPE_ASF }, - { "application/x-mms-framed", DEMUXER_TYPE_ASF }, - { "application/vnd.ms.wms-hdr.asfv1", DEMUXER_TYPE_ASF }, - { "application/octet-stream", DEMUXER_TYPE_ASF }, - // Playlists - { "video/x-ms-wmx", DEMUXER_TYPE_PLAYLIST }, - { "audio/x-scpls", DEMUXER_TYPE_PLAYLIST }, - { "audio/x-mpegurl", DEMUXER_TYPE_PLAYLIST }, - { "audio/x-pls", DEMUXER_TYPE_PLAYLIST }, - // Real Media -// { "audio/x-pn-realaudio", DEMUXER_TYPE_REAL }, - // OGG Streaming - { "application/x-ogg", DEMUXER_TYPE_OGG }, - // NullSoft Streaming Video - { "video/nsv", DEMUXER_TYPE_NSV}, - { "misc/ultravox", DEMUXER_TYPE_NSV}, - { NULL, DEMUXER_TYPE_UNKNOWN}, -}; - - -streaming_ctrl_t * -streaming_ctrl_new(void) { - streaming_ctrl_t *streaming_ctrl; - streaming_ctrl = malloc(sizeof(streaming_ctrl_t)); - if( streaming_ctrl==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return NULL; - } - memset( streaming_ctrl, 0, sizeof(streaming_ctrl_t) ); - return streaming_ctrl; -} - -void -streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) { - if( streaming_ctrl==NULL ) return; - if( streaming_ctrl->url ) url_free( streaming_ctrl->url ); - if( streaming_ctrl->buffer ) free( streaming_ctrl->buffer ); - if( streaming_ctrl->data ) free( streaming_ctrl->data ); - free( streaming_ctrl ); -} - - -// Converts an address family constant to a string - -const char *af2String(int af) { - switch (af) { - case AF_INET: return "AF_INET"; - -#ifdef HAVE_AF_INET6 - case AF_INET6: return "AF_INET6"; -#endif - default: return "Unknown address family!"; - } -} - - - -// Connect to a server using a TCP connection, with specified address family -// return -2 for fatal error, like unable to resolve name, connection timeout... -// return -1 is unable to connect to a particular port - -int -connect2Server_with_af(char *host, int port, int af,int verb) { - int socket_server_fd; - int err, err_len; - int ret,count = 0; - fd_set set; - struct timeval tv; - union { - struct sockaddr_in four; -#ifdef HAVE_AF_INET6 - struct sockaddr_in6 six; -#endif - } server_address; - size_t server_address_size; - void *our_s_addr; // Pointer to sin_addr or sin6_addr - struct hostent *hp=NULL; - char buf[255]; - -#ifdef HAVE_WINSOCK2 - u_long val; -#endif - - socket_server_fd = socket(af, SOCK_STREAM, 0); - - - if( socket_server_fd==-1 ) { -// mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af)); - return -2; - } - - switch (af) { - case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break; -#ifdef HAVE_AF_INET6 - case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break; -#endif - default: - mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); - return -2; - } - - - memset(&server_address, 0, sizeof(server_address)); - -#ifndef HAVE_WINSOCK2 -#ifdef USE_ATON - if (inet_aton(host, our_s_addr)!=1) -#else - if (inet_pton(af, host, our_s_addr)!=1) -#endif -#else - if ( inet_addr(host)==INADDR_NONE ) -#endif - { - if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af)); - -#ifdef HAVE_GETHOSTBYNAME2 - hp=(struct hostent*)gethostbyname2( host, af ); -#else - hp=(struct hostent*)gethostbyname( host ); -#endif - if( hp==NULL ) { - if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host); - return -2; - } - - memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length ); - } -#ifdef HAVE_WINSOCK2 - else { - unsigned long addr = inet_addr(host); - memcpy( our_s_addr, (void*)&addr, sizeof(addr) ); - } -#endif - - switch (af) { - case AF_INET: - server_address.four.sin_family=af; - server_address.four.sin_port=htons(port); - server_address_size = sizeof(server_address.four); - break; -#ifdef HAVE_AF_INET6 - case AF_INET6: - server_address.six.sin6_family=af; - server_address.six.sin6_port=htons(port); - server_address_size = sizeof(server_address.six); - break; -#endif - default: - mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); - return -2; - } - -#if defined(USE_ATON) || defined(HAVE_WINSOCK2) - strncpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255); -#else - inet_ntop(af, our_s_addr, buf, 255); -#endif - if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port ); - - // Turn the socket as non blocking so we can timeout on the connection -#ifndef HAVE_WINSOCK2 - fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); -#else - val = 1; - ioctlsocket( socket_server_fd, FIONBIO, &val ); -#endif - if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) { -#ifndef HAVE_WINSOCK2 - if( errno!=EINPROGRESS ) { -#else - if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) { -#endif - if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af)); - closesocket(socket_server_fd); - return -1; - } - } - tv.tv_sec = 0; - tv.tv_usec = 500000; - FD_ZERO( &set ); - FD_SET( socket_server_fd, &set ); - // When the connection will be made, we will have a writable fd - while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) { - if( ret<0 ) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed); - else if(ret > 0) break; - else if(count > 30 || mp_input_check_interrupt(500)) { - if(count > 30) - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout); - else - mp_msg(MSGT_NETWORK,MSGL_V,"Connection interuppted by user\n"); - return -3; - } - count++; - FD_ZERO( &set ); - FD_SET( socket_server_fd, &set ); - tv.tv_sec = 0; - tv.tv_usec = 500000; - } - - // Turn back the socket as blocking -#ifndef HAVE_WINSOCK2 - fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK ); -#else - val = 0; - ioctlsocket( socket_server_fd, FIONBIO, &val ); -#endif - // Check if there were any error - err_len = sizeof(int); - ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len); - if(ret < 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno)); - return -2; - } - if(err > 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err)); - return -1; - } - - return socket_server_fd; -} - -// Connect to a server using a TCP connection -// return -2 for fatal error, like unable to resolve name, connection timeout... -// return -1 is unable to connect to a particular port - - -int -connect2Server(char *host, int port, int verb) { -#ifdef HAVE_AF_INET6 - int r; - int s = -2; - - r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb); - if (r > -1) return r; - - s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb); - if (s == -2) return r; - return s; -#else - return connect2Server_with_af(host, port, AF_INET,verb); -#endif - - -} - -URL_t* -check4proxies( URL_t *url ) { - URL_t *url_out = NULL; - if( url==NULL ) return NULL; - url_out = url_new( url->url ); - if( !strcasecmp(url->protocol, "http_proxy") ) { - mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: http://%s:%d\n", url->hostname, url->port ); - return url_out; - } - // Check if the http_proxy environment variable is set. - if( !strcasecmp(url->protocol, "http") ) { - char *proxy; - proxy = getenv("http_proxy"); - if( proxy!=NULL ) { - // We got a proxy, build the URL to use it - int len; - char *new_url; - URL_t *tmp_url; - URL_t *proxy_url = url_new( proxy ); - - if( proxy_url==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_WARN, - MSGTR_MPDEMUX_NW_InvalidProxySettingTryingWithout); - return url_out; - } - -#ifdef HAVE_AF_INET6 - if (network_ipv4_only_proxy && (gethostbyname(url->hostname)==NULL)) { - mp_msg(MSGT_NETWORK,MSGL_WARN, - MSGTR_MPDEMUX_NW_CantResolvTryingWithoutProxy); - url_free(proxy_url); - return url_out; - } -#endif - - mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: %s\n", proxy_url->url ); - len = strlen( proxy_url->hostname ) + strlen( url->url ) + 20; // 20 = http_proxy:// + port - new_url = malloc( len+1 ); - if( new_url==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - url_free(proxy_url); - return url_out; - } - sprintf(new_url, "http_proxy://%s:%d/%s", proxy_url->hostname, proxy_url->port, url->url ); - tmp_url = url_new( new_url ); - if( tmp_url==NULL ) { - free( new_url ); - url_free( proxy_url ); - return url_out; - } - url_free( url_out ); - url_out = tmp_url; - free( new_url ); - url_free( proxy_url ); - } - } - return url_out; -} - -int -http_send_request( URL_t *url, off_t pos ) { - HTTP_header_t *http_hdr; - URL_t *server_url; - char str[256]; - int fd; - int ret; - int proxy = 0; // Boolean - - http_hdr = http_new_header(); - - if( !strcasecmp(url->protocol, "http_proxy") ) { - proxy = 1; - server_url = url_new( (url->file)+1 ); - http_set_uri( http_hdr, server_url->url ); - } else { - server_url = url; - http_set_uri( http_hdr, server_url->file ); - } - if (server_url->port && server_url->port != 80) - snprintf(str, 256, "Host: %s:%d", server_url->hostname, server_url->port ); - else - snprintf(str, 256, "Host: %s", server_url->hostname ); - http_set_field( http_hdr, str); - if (network_useragent) - { - snprintf(str, 256, "User-Agent: %s", network_useragent); - http_set_field(http_hdr, str); - } - else - http_set_field( http_hdr, "User-Agent: MPlayer/"VERSION); - - http_set_field(http_hdr, "Icy-MetaData: 1"); - - if(pos>0) { - // Extend http_send_request with possibility to do partial content retrieval - snprintf(str, 256, "Range: bytes=%"PRId64"-", (int64_t)pos); - http_set_field(http_hdr, str); - } - - if (network_cookies_enabled) cookies_set( http_hdr, server_url->hostname, server_url->url ); - - http_set_field( http_hdr, "Connection: close"); - http_add_basic_authentication( http_hdr, url->username, url->password ); - if( http_build_request( http_hdr )==NULL ) { - goto err_out; - } - - if( proxy ) { - if( url->port==0 ) url->port = 8080; // Default port for the proxy server - fd = connect2Server( url->hostname, url->port,1 ); - url_free( server_url ); - server_url = NULL; - } else { - if( server_url->port==0 ) server_url->port = 80; // Default port for the web server - fd = connect2Server( server_url->hostname, server_url->port,1 ); - } - if( fd<0 ) { - goto err_out; - } - mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request: [%s]\n", http_hdr->buffer ); - - ret = send( fd, http_hdr->buffer, http_hdr->buffer_size, 0 ); - if( ret!=(int)http_hdr->buffer_size ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrSendingHTTPRequest); - goto err_out; - } - - http_free( http_hdr ); - - return fd; -err_out: - http_free(http_hdr); - if (proxy && server_url) - url_free(server_url); - return -1; -} - -HTTP_header_t * -http_read_response( int fd ) { - HTTP_header_t *http_hdr; - char response[BUFFER_SIZE]; - int i; - - http_hdr = http_new_header(); - if( http_hdr==NULL ) { - return NULL; - } - - do { - i = recv( fd, response, BUFFER_SIZE, 0 ); - if( i<0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ReadFailed); - http_free( http_hdr ); - return NULL; - } - if( i==0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_Read0CouldBeEOF); - http_free( http_hdr ); - return NULL; - } - http_response_append( http_hdr, response, i ); - } while( !http_is_header_entire( http_hdr ) ); - http_response_parse( http_hdr ); - return http_hdr; -} - -int -http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry) { - char *aut; - - if( *auth_retry==1 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_AuthFailed); - return -1; - } - if( *auth_retry>0 ) { - if( url->username ) { - free( url->username ); - url->username = NULL; - } - if( url->password ) { - free( url->password ); - url->password = NULL; - } - } - - aut = http_get_field(http_hdr, "WWW-Authenticate"); - if( aut!=NULL ) { - char *aut_space; - aut_space = strstr(aut, "realm="); - if( aut_space!=NULL ) aut_space += 6; - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_AuthRequiredFor, aut_space); - } else { - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_AuthRequired); - } - if( network_username ) { - url->username = strdup(network_username); - if( url->username==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return -1; - } - } else { - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_AuthFailed); - return -1; - } - if( network_password ) { - url->password = strdup(network_password); - if( url->password==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return -1; - } - } else { - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_NoPasswdProvidedTryingBlank); - } - (*auth_retry)++; - return 0; -} - -int -http_seek( stream_t *stream, off_t pos ) { - HTTP_header_t *http_hdr = NULL; - int fd; - if( stream==NULL ) return 0; - - if( stream->fd>0 ) closesocket(stream->fd); // need to reconnect to seek in http-stream - fd = http_send_request( stream->streaming_ctrl->url, pos ); - if( fd<0 ) return 0; - - http_hdr = http_read_response( fd ); - - if( http_hdr==NULL ) return 0; - - switch( http_hdr->status_code ) { - case 200: - case 206: // OK - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); - mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); - if( http_hdr->body_size>0 ) { - if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { - http_free( http_hdr ); - return -1; - } - } - break; - default: - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrServerReturned, http_hdr->status_code, http_hdr->reason_phrase ); - close( fd ); - fd = -1; - } - stream->fd = fd; - - if( http_hdr ) { - http_free( http_hdr ); - stream->streaming_ctrl->data = NULL; - } - - stream->pos=pos; - - return 1; -} - - -int -streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size) { -//printf("streaming_bufferize\n"); - streaming_ctrl->buffer = malloc(size); - if( streaming_ctrl->buffer==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - return -1; - } - memcpy( streaming_ctrl->buffer, buffer, size ); - streaming_ctrl->buffer_size = size; - return size; -} - -int -nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { - int len=0; -//printf("nop_streaming_read\n"); - if( stream_ctrl->buffer_size!=0 ) { - int buffer_len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos; -//printf("%d bytes in buffer\n", stream_ctrl->buffer_size); - len = (size<buffer_len)?size:buffer_len; - memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len ); - stream_ctrl->buffer_pos += len; -//printf("buffer_pos = %d\n", stream_ctrl->buffer_pos ); - if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) { - free( stream_ctrl->buffer ); - stream_ctrl->buffer = NULL; - stream_ctrl->buffer_size = 0; - stream_ctrl->buffer_pos = 0; -//printf("buffer cleaned\n"); - } -//printf("read %d bytes from buffer\n", len ); - } - - if( len<size ) { - int ret; - ret = recv( fd, buffer+len, size-len, 0 ); - if( ret<0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : %s\n",strerror(errno)); - } - len += ret; -//printf("read %d bytes from network\n", len ); - } - - return len; -} - -int -nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl ) { - return -1; - // To shut up gcc warning - fd++; - pos++; - stream_ctrl=NULL; -} - - -void fixup_network_stream_cache(stream_t *stream) { - if(stream->streaming_ctrl->buffering) { - if(stream_cache_size<0) { - // cache option not set, will use our computed value. - // buffer in KBytes, *5 because the prefill is 20% of the buffer. - stream_cache_size = (stream->streaming_ctrl->prebuffer_size/1024)*5; - if( stream_cache_size<64 ) stream_cache_size = 64; // 16KBytes min buffer - } - mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_CacheSizeSetTo, stream_cache_size); - } -} - - -int -streaming_stop( stream_t *stream ) { - stream->streaming_ctrl->status = streaming_stopped_e; - return 0; -}
--- a/libmpdemux/network.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Network layer for MPlayer - * by Bertrand BAUDET <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - */ - -#ifndef __NETWORK_H -#define __NETWORK_H - -#include <fcntl.h> -#include <sys/time.h> -#include <sys/types.h> - -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <netdb.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#endif - -#include "url.h" -#include "http.h" -#include "stream.h" - -#define BUFFER_SIZE 2048 - -typedef struct { - const char *mime_type; - int demuxer_type; -} mime_struct_t; - -typedef enum { - streaming_stopped_e, - streaming_playing_e -} streaming_status; - -typedef struct streaming_control { - URL_t *url; - streaming_status status; - int buffering; // boolean - unsigned int prebuffer_size; - char *buffer; - unsigned int buffer_size; - unsigned int buffer_pos; - unsigned int bandwidth; // The downstream available - int (*streaming_read)( int fd, char *buffer, int buffer_size, struct streaming_control *stream_ctrl ); - int (*streaming_seek)( int fd, off_t pos, struct streaming_control *stream_ctrl ); - void *data; -} streaming_ctrl_t; - -//int streaming_start( stream_t *stream, int *demuxer_type, URL_t *url ); -streaming_ctrl_t *streaming_ctrl_new(void); -int streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size); - -int nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ); -int nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl ); -void streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ); - -int connect2Server(char *host, int port,int verb); - -int http_send_request(URL_t *url, off_t pos); -HTTP_header_t *http_read_response(int fd); - -int http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry); -URL_t* check4proxies(URL_t *url); - -#endif
--- a/libmpdemux/open.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ - -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include "config.h" -#include "mp_msg.h" -#include "help_mp.h" - -#ifdef __FreeBSD__ -#include <sys/cdrio.h> -#endif - -#include "m_option.h" -#include "stream.h" -#include "demuxer.h" -#include "mf.h" - - -/// We keep these 2 for the gui atm, but they will be removed. -int vcd_track=0; -char* cdrom_device=NULL; -int dvd_chapter=1; -int dvd_last_chapter=0; -char* dvd_device=NULL; -int dvd_title=0; - -// Open a new stream (stdin/file/vcd/url) - -stream_t* open_stream(char* filename,char** options, int* file_format){ - // Check if playlist or unknown - if (*file_format != DEMUXER_TYPE_PLAYLIST){ - *file_format=DEMUXER_TYPE_UNKNOWN; - } - -if(!filename) { - mp_msg(MSGT_OPEN,MSGL_ERR,"NULL filename, report this bug\n"); - return NULL; -} - -//============ Open STDIN or plain FILE ============ - - return open_stream_full(filename,STREAM_READ,options,file_format); -} -
--- a/libmpdemux/pnm.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,921 +0,0 @@ -/* - * Copyright (C) 2000-2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * $Id$ - * - * pnm protocol implementation - * based upon code from joschka - */ - -#include "config.h" - -#include <unistd.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/time.h> -#include <inttypes.h> -#ifndef HAVE_WINSOCK2 -#define closesocket close -#include <sys/socket.h> -//#include <netinet/in.h> -//#include <netdb.h> -#else -#include <winsock2.h> -#endif - -#include "stream.h" -#include "demuxer.h" -#include "help_mp.h" -#include "osdep/timer.h" - -#include "pnm.h" -//#include "libreal/rmff.h" - -extern int network_bandwidth; - -#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ - (((long)(unsigned char)(ch3) ) | \ - ( (long)(unsigned char)(ch2) << 8 ) | \ - ( (long)(unsigned char)(ch1) << 16 ) | \ - ( (long)(unsigned char)(ch0) << 24 ) ) - - -#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') -#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') -#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') -#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') -#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') -#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') -#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) - -/* -#define LOG -*/ - -#define BUF_SIZE 4096 -#define HEADER_SIZE 4096 - -struct pnm_s { - - int s; - -// char *host; -// int port; - char *path; -// char *url; - - char buffer[BUF_SIZE]; /* scratch buffer */ - - /* receive buffer */ - uint8_t recv[BUF_SIZE]; - int recv_size; - int recv_read; - - uint8_t header[HEADER_SIZE]; - int header_len; - int header_read; - unsigned int seq_num[4]; /* two streams with two indices */ - unsigned int seq_current[2]; /* seqs of last stream chunk read */ - uint32_t ts_current; /* timestamp of current chunk */ - uint32_t ts_last[2]; /* timestamps of last chunks */ - unsigned int packet; /* number of last recieved packet */ -}; - -/* - * utility macros - */ - -#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) -#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ - (((uint8_t*)(x))[1] << 16) | \ - (((uint8_t*)(x))[2] << 8) | \ - ((uint8_t*)(x))[3]) - -/* D means direct (no pointer) */ -#define BE_16D(x) ((x & 0xff00) >> 8)|((x & 0x00ff) << 8) - -/* sizes */ -#define PREAMBLE_SIZE 8 -#define CHECKSUM_SIZE 3 - - -/* header of rm files */ -#define RM_HEADER_SIZE 0x12 -static const unsigned char rm_header[]={ - 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */ - 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */ - 0x00, 0x00, /* object_version 0x00 */ - 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */ - 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */ -}; - -/* data chunk header */ -#define PNM_DATA_HEADER_SIZE 18 -static const unsigned char pnm_data_header[]={ - 'D','A','T','A', - 0,0,0,0, /* data chunk size */ - 0,0, /* object version */ - 0,0,0,0, /* num packets */ - 0,0,0,0}; /* next data header */ - -/* pnm request chunk ids */ - -#define PNA_CLIENT_CAPS 0x03 -#define PNA_CLIENT_CHALLANGE 0x04 -#define PNA_BANDWIDTH 0x05 -#define PNA_GUID 0x13 -#define PNA_TIMESTAMP 0x17 -#define PNA_TWENTYFOUR 0x18 - -#define PNA_CLIENT_STRING 0x63 -#define PNA_PATH_REQUEST 0x52 - -static const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56"; -static const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]"; -static const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0"; -static const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf"; -static const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l"; - -#define PNM_HEADER_SIZE 11 -static const unsigned char pnm_header[] = { - 'P','N','A', - 0x00, 0x0a, - 0x00, 0x14, - 0x00, 0x02, - 0x00, 0x01 }; - -#define PNM_CLIENT_CAPS_SIZE 126 -static const unsigned char pnm_client_caps[] = { - 0x07, 0x8a, 'p','n','r','v', - 0, 0x90, 'p','n','r','v', - 0, 0x64, 'd','n','e','t', - 0, 0x46, 'p','n','r','v', - 0, 0x32, 'd','n','e','t', - 0, 0x2b, 'p','n','r','v', - 0, 0x28, 'd','n','e','t', - 0, 0x24, 'p','n','r','v', - 0, 0x19, 'd','n','e','t', - 0, 0x18, 'p','n','r','v', - 0, 0x14, 's','i','p','r', - 0, 0x14, 'd','n','e','t', - 0, 0x24, '2','8','_','8', - 0, 0x12, 'p','n','r','v', - 0, 0x0f, 'd','n','e','t', - 0, 0x0a, 's','i','p','r', - 0, 0x0a, 'd','n','e','t', - 0, 0x08, 's','i','p','r', - 0, 0x06, 's','i','p','r', - 0, 0x12, 'l','p','c','J', - 0, 0x07, '0','5','_','6' }; - -static const uint32_t pnm_default_bandwidth=10485800; -static const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600, - 115200,262200,393216,524300,1544000,10485800}; - -#define PNM_TWENTYFOUR_SIZE 16 -static unsigned char pnm_twentyfour[]={ - 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24, - 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 }; - -/* now other data follows. marked with 0x0000 at the beginning */ -static int after_chunks_length=6; -static unsigned char after_chunks[]={ - 0x00, 0x00, /* mark */ - - 0x50, 0x84, /* seems to be fixated */ - 0x1f, 0x3a /* varies on each request (checksum ?)*/ - }; - -static void hexdump (char *buf, int length); - -static int rm_write(int s, const char *buf, int len) { - int total, timeout; - - total = 0; timeout = 30; - while (total < len){ - int n; - - n = send (s, &buf[total], len - total, 0); - - if (n > 0) - total += n; - else if (n < 0) { -#ifndef HAVE_WINSOCK2 - if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { -#else - if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { -#endif - usec_sleep (1000000); timeout--; - } else - return -1; - } - } - - return total; -} - -static ssize_t rm_read(int fd, void *buf, size_t count) { - - ssize_t ret, total; - - total = 0; - - while (total < count) { - - fd_set rset; - struct timeval timeout; - - FD_ZERO (&rset); - FD_SET (fd, &rset); - - timeout.tv_sec = 3; - timeout.tv_usec = 0; - - if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { - return -1; - } - - ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); - - if (ret<=0) { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: read error.\n"); - return ret; - } else - total += ret; - } - - return total; -} - -/* - * debugging utilities - */ - -static void hexdump (char *buf, int length) { - - int i; - - mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: ascii>"); - for (i = 0; i < length; i++) { - unsigned char c = buf[i]; - - if ((c >= 32) && (c <= 128)) - mp_msg(MSGT_OPEN, MSGL_INFO, "%c", c); - else - mp_msg(MSGT_OPEN, MSGL_INFO, "."); - } - mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); - - mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: hexdump> "); - for (i = 0; i < length; i++) { - unsigned char c = buf[i]; - - mp_msg(MSGT_OPEN, MSGL_INFO, "%02x", c); - - if ((i % 16) == 15) - mp_msg(MSGT_OPEN, MSGL_INFO, "\npnm: "); - - if ((i % 2) == 1) - mp_msg(MSGT_OPEN, MSGL_INFO, " "); - - } - mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); -} - -/* - * pnm_get_chunk gets a chunk from stream - * and returns number of bytes read - */ - -static int pnm_get_chunk(pnm_t *p, - unsigned int max, - unsigned int *chunk_type, - char *data, int *need_response) { - - unsigned int chunk_size; - unsigned int n; - char *ptr; - - if (max < PREAMBLE_SIZE) - return -1; - - /* get first PREAMBLE_SIZE bytes and ignore checksum */ - rm_read (p->s, data, CHECKSUM_SIZE); - if (data[0] == 0x72) - rm_read (p->s, data, PREAMBLE_SIZE); - else - rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); - - max -= PREAMBLE_SIZE; - - *chunk_type = BE_32(data); - chunk_size = BE_32(data+4); - - switch (*chunk_type) { - case PNA_TAG: - *need_response=0; - ptr=data+PREAMBLE_SIZE; - if (max < 1) - return -1; - rm_read (p->s, ptr++, 1); - max -= 1; - - while(1) { - /* expecting following chunk format: 0x4f <chunk size> <data...> */ - - if (max < 2) - return -1; - rm_read (p->s, ptr, 2); - max -= 2; - if (*ptr == 'X') /* checking for server message */ - { - mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got a message from server:\n"); - if (max < 1) - return -1; - rm_read (p->s, ptr+2, 1); - max = -1; - n=BE_16(ptr+1); - if (max < n) - return -1; - rm_read (p->s, ptr+3, n); - max -= n; - ptr[3+n]=0; - mp_msg(MSGT_OPEN, MSGL_WARN, "%s\n",ptr+3); - return -1; - } - - if (*ptr == 'F') /* checking for server error */ - { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); - return -1; - } - if (*ptr == 'i') - { - ptr+=2; - *need_response=1; - continue; - } - if (*ptr != 0x4f) break; - n=ptr[1]; - if (max < n) - return -1; - rm_read (p->s, ptr+2, n); - max -= n; - ptr+=(n+2); - } - /* the checksum of the next chunk is ignored here */ - if (max < 1) - return -1; - rm_read (p->s, ptr+2, 1); - ptr+=3; - chunk_size=ptr-data; - break; - case RMF_TAG: - case DATA_TAG: - case PROP_TAG: - case MDPR_TAG: - case CONT_TAG: - if (chunk_size > max || chunk_size < PREAMBLE_SIZE) { - mp_msg(MSGT_OPEN, MSGL_ERR, "error: max chunk size exceded (max was 0x%04x)\n", max); -#ifdef LOG - n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); - hexdump(data,n+PREAMBLE_SIZE); -#endif - return -1; - } - rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); - break; - default: - *chunk_type = 0; - chunk_size = PREAMBLE_SIZE; - break; - } - - return chunk_size; -} - -/* - * writes a chunk to a buffer, returns number of bytes written - */ - -static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, - const char *chunk, char *data) { - - data[0]=(chunk_id>>8)%0xff; - data[1]=chunk_id%0xff; - data[2]=(length>>8)%0xff; - data[3]=length%0xff; - memcpy(&data[4],chunk,length); - - return length+4; -} - -/* - * constructs a request and sends it - */ - -static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { - - uint16_t i16; - int c=PNM_HEADER_SIZE; - char fixme[]={0,1}; - - memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); - c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), - pnm_challenge,&p->buffer[c]); - c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, - pnm_client_caps,&p->buffer[c]); - c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); - c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), - pnm_timestamp,&p->buffer[c]); - c+=pnm_write_chunk(PNA_BANDWIDTH,4, - (const char *)&pnm_default_bandwidth,&p->buffer[c]); - c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); - c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), - pnm_guid,&p->buffer[c]); - c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, - pnm_twentyfour,&p->buffer[c]); - - /* data after chunks */ - memcpy(&p->buffer[c],after_chunks,after_chunks_length); - c+=after_chunks_length; - - /* client id string */ - p->buffer[c]=PNA_CLIENT_STRING; - i16=BE_16D((strlen(client_string)-1)); /* don't know why do we have -1 here */ - memcpy(&p->buffer[c+1],&i16,2); - memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); - c=c+3+strlen(client_string)+1; - - /* file path */ - p->buffer[c]=0; - p->buffer[c+1]=PNA_PATH_REQUEST; - i16=BE_16D(strlen(p->path)); - memcpy(&p->buffer[c+2],&i16,2); - memcpy(&p->buffer[c+4],p->path,strlen(p->path)); - c=c+4+strlen(p->path); - - /* some trailing bytes */ - p->buffer[c]='y'; - p->buffer[c+1]='B'; - - rm_write(p->s,p->buffer,c+2); -} - -/* - * pnm_send_response sends a response of a challenge - */ - -static void pnm_send_response(pnm_t *p, const char *response) { - - int size=strlen(response); - - p->buffer[0]=0x23; - p->buffer[1]=0; - p->buffer[2]=(unsigned char) size; - - memcpy(&p->buffer[3], response, size); - - rm_write (p->s, p->buffer, size+3); - -} - -/* - * get headers and challenge and fix headers - * write headers to p->header - * write challenge to p->buffer - * - * return 0 on error. != 0 on success - */ - -static int pnm_get_headers(pnm_t *p, int *need_response) { - - uint32_t chunk_type; - uint8_t *ptr=p->header; - uint8_t *prop_hdr=NULL; - int chunk_size,size=0; - int nr; -/* rmff_header_t *h; */ - - *need_response=0; - - while(1) { - if (HEADER_SIZE-size<=0) - { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: header buffer overflow. exiting\n"); - return 0; - } - chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); - if (chunk_size < 0) return 0; - if (chunk_type == 0) break; - if (chunk_type == PNA_TAG) - { - memcpy(ptr, rm_header, RM_HEADER_SIZE); - chunk_size=RM_HEADER_SIZE; - *need_response=nr; - } - if (chunk_type == DATA_TAG) - chunk_size=0; - if (chunk_type == RMF_TAG) - chunk_size=0; - if (chunk_type == PROP_TAG) - prop_hdr=ptr; - size+=chunk_size; - ptr+=chunk_size; - } - - if (!prop_hdr) { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: error while parsing headers.\n"); - return 0; - } - - /* set data offset */ - size--; - prop_hdr[42]=(size>>24)%0xff; - prop_hdr[43]=(size>>16)%0xff; - prop_hdr[44]=(size>>8)%0xff; - prop_hdr[45]=(size)%0xff; - size++; - - /* read challenge */ - memcpy (p->buffer, ptr, PREAMBLE_SIZE); - rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); - - /* now write a data header */ - memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); - size+=PNM_DATA_HEADER_SIZE; -/* - h=rmff_scan_header(p->header); - rmff_fix_header(h); - p->header_len=rmff_get_header_size(h); - rmff_dump_header(h, p->header, HEADER_SIZE); -*/ - p->header_len=size; - - return 1; -} - -/* - * determine correct stream number by looking at indices - */ - -static int pnm_calc_stream(pnm_t *p) { - - char str0=0,str1=0; - - /* looking at the first index to - * find possible stream types - */ - if (p->seq_current[0]==p->seq_num[0]) str0=1; - if (p->seq_current[0]==p->seq_num[2]) str1=1; - - switch (str0+str1) { - case 1: /* one is possible, good. */ - if (str0) - { - p->seq_num[0]++; - p->seq_num[1]=p->seq_current[1]+1; - return 0; - } else - { - p->seq_num[2]++; - p->seq_num[3]=p->seq_current[1]+1; - return 1; - } - break; - case 0: - case 2: /* both types or none possible, not so good */ - /* try to figure out by second index */ - if ( (p->seq_current[1] == p->seq_num[1]) - &&(p->seq_current[1] != p->seq_num[3])) - { - /* ok, only stream0 matches */ - p->seq_num[0]=p->seq_current[0]+1; - p->seq_num[1]++; - return 0; - } - if ( (p->seq_current[1] == p->seq_num[3]) - &&(p->seq_current[1] != p->seq_num[1])) - { - /* ok, only stream1 matches */ - p->seq_num[2]=p->seq_current[0]+1; - p->seq_num[3]++; - return 1; - } - /* wow, both streams match, or not. */ - /* now we try to decide by timestamps */ - if (p->ts_current < p->ts_last[1]) - return 0; - if (p->ts_current < p->ts_last[0]) - return 1; - /* does not help, we guess type 0 */ -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "guessing stream# 0\n"); -#endif - p->seq_num[0]=p->seq_current[0]+1; - p->seq_num[1]=p->seq_current[1]+1; - return 0; - break; - } - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); - return 2; -} - -/* - * gets a stream chunk and writes it to a recieve buffer - */ - -static int pnm_get_stream_chunk(pnm_t *p) { - - int n; - char keepalive='!'; - unsigned int fof1, fof2, stream; - - /* send a keepalive */ - /* realplayer seems to do that every 43th package */ - if ((p->packet%43) == 42) - { - rm_write(p->s,&keepalive,1); - } - - /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> - * where <o> is the offset to next stream chunk, - * <i1> is a 16 bit index - * <i2> is a 8 bit index which counts from 0x10 to somewhere - */ - - n = rm_read (p->s, p->buffer, 8); - if (n<0) return -1; - if (n<8) return 0; - - /* skip 8 bytes if 0x62 is read */ - if (p->buffer[0] == 0x62) - { - n = rm_read (p->s, p->buffer, 8); - if (n<8) return 0; -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek 8 bytes on 0x62\n"); -#endif - } - - /* a server message */ - if (p->buffer[0] == 'X') - { - int size=BE_16(&p->buffer[1]); - - rm_read (p->s, &p->buffer[8], size-5); - p->buffer[size+3]=0; - mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); - return -1; - } - if (p->buffer[0] == 'F') - { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); - return -1; - } - - /* skip bytewise to next chunk. - * seems, that we don't need that, if we send enough - * keepalives - */ - n=0; - while (p->buffer[0] != 0x5a) { - int i; - for (i=1; i<8; i++) { - p->buffer[i-1]=p->buffer[i]; - } - rm_read (p->s, &p->buffer[7], 1); - n++; - } - -#ifdef LOG - if (n) mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek %i bytes to next chunk\n", n); -#endif - - /* check for 'Z's */ - if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) - { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: bad boundaries\n"); - hexdump(p->buffer, 8); - return 0; - } - - /* check offsets */ - fof1=BE_16(&p->buffer[1]); - fof2=BE_16(&p->buffer[3]); - if (fof1 != fof2) - { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); - return 0; - } - - /* get first index */ - p->seq_current[0]=BE_16(&p->buffer[5]); - - /* now read the rest of stream chunk */ - n = rm_read (p->s, &p->recv[5], fof1-5); - if (n<(fof1-5)) return 0; - - /* get second index */ - p->seq_current[1]=p->recv[5]; - - /* get timestamp */ - p->ts_current=BE_32(&p->recv[6]); - - /* get stream number */ - stream=pnm_calc_stream(p); - - /* saving timestamp */ - p->ts_last[stream]=p->ts_current; - - /* constructing a data packet header */ - - p->recv[0]=0; /* object version */ - p->recv[1]=0; - - fof2=BE_16(&fof2); - memcpy(&p->recv[2], &fof2, 2); - /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ - /*p->recv[3]=(fof2)%0xff;*/ - - p->recv[4]=0; /* stream number */ - p->recv[5]=stream; - - p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ - - p->packet++; - - p->recv_size=fof1; - - return fof1; -} - -// pnm_t *pnm_connect(const char *mrl) { -static pnm_t *pnm_connect(int fd, char *path) { - - pnm_t *p=malloc(sizeof(pnm_t)); - int need_response=0; - - p->path=strdup(path); - p->s=fd; - - pnm_send_request(p,pnm_available_bandwidths[10]); - if (!pnm_get_headers(p, &need_response)) { - mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: failed to set up stream\n"); - free(p->path); - free(p); - return NULL; - } - if (need_response) - pnm_send_response(p, pnm_response); - p->ts_last[0]=0; - p->ts_last[1]=0; - - /* copy header to recv */ - - memcpy(p->recv, p->header, p->header_len); - p->recv_size = p->header_len; - p->recv_read = 0; - - return p; -} - -static int pnm_read (pnm_t *this, char *data, int len) { - - int to_copy=len; - char *dest=data; - char *source=this->recv + this->recv_read; - int fill=this->recv_size - this->recv_read; - int retval; - - if (len < 0) return 0; - while (to_copy > fill) { - - memcpy(dest, source, fill); - to_copy -= fill; - dest += fill; - this->recv_read=0; - - if ((retval = pnm_get_stream_chunk (this)) <= 0) { -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d of %d bytes provided\n", len-to_copy, len); -#endif - if (retval < 0) - return retval; - else - return len-to_copy; - } - source = this->recv; - fill = this->recv_size - this->recv_read; - } - - memcpy(dest, source, to_copy); - this->recv_read += to_copy; - -#ifdef LOG - mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d bytes provided\n", len); -#endif - - return len; -} - -static int pnm_peek_header (pnm_t *this, char *data) { - - memcpy (data, this->header, this->header_len); - return this->header_len; -} - -static void pnm_close(pnm_t *p) { - - if (p->s >= 0) closesocket(p->s); - free(p->path); - free(p); -} - -static int pnm_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { - return pnm_read(stream_ctrl->data, buffer, size); -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - int fd; - pnm_t *pnm; - URL_t *url; - - mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_PNM, URL: %s\n", stream->url); - stream->streaming_ctrl = streaming_ctrl_new(); - if(stream->streaming_ctrl==NULL) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - //url_free(url); - - fd = connect2Server( stream->streaming_ctrl->url->hostname, - stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 ); - - if(fd<0) - goto fail; - - pnm = pnm_connect(fd,stream->streaming_ctrl->url->file); - if(!pnm) - goto fail; - stream->type = STREAMTYPE_STREAM; - stream->fd=fd; - stream->streaming_ctrl->data=pnm; - stream->streaming_ctrl->streaming_read = pnm_streaming_read; - //stream->streaming_ctrl->streaming_seek = nop_streaming_seek; - stream->streaming_ctrl->prebuffer_size = 8*1024; // 8 KBytes - stream->streaming_ctrl->buffering = 1; - stream->streaming_ctrl->status = streaming_playing_e; - *file_format = DEMUXER_TYPE_REAL; - fixup_network_stream_cache(stream); - return STREAM_OK; - -fail: - streaming_ctrl_free(stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; -} - - -stream_info_t stream_info_pnm = { - "RealNetworks pnm", - "pnm", - "Arpi, xine team", - "ported from xine", - open_s, - {"pnm", NULL}, //pnm as fallback - NULL, - 0 // Urls are an option string -};
--- a/libmpdemux/realrtsp/asmrp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,677 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS asmrp.c,v 1.2 2002/12/17 16:49:48 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * a parser for real's asm rules - * - * grammar for these rules: - * - - rule_book = { rule } - rule = ( '#' condition { ',' assignment } | [ assignment {',' assignment} ]) ';' - assignment = id '=' const - const = ( number | string ) - condition = comp_expr { ( '&&' | '||' ) comp_expr } - comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } - operand = ( '$' id | num | '(' condition ')' ) - - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -/* -#define LOG -*/ - -#define ASMRP_SYM_NONE 0 -#define ASMRP_SYM_EOF 1 - -#define ASMRP_SYM_NUM 2 -#define ASMRP_SYM_ID 3 -#define ASMRP_SYM_STRING 4 - -#define ASMRP_SYM_HASH 10 -#define ASMRP_SYM_SEMICOLON 11 -#define ASMRP_SYM_COMMA 12 -#define ASMRP_SYM_EQUALS 13 -#define ASMRP_SYM_AND 14 -#define ASMRP_SYM_OR 15 -#define ASMRP_SYM_LESS 16 -#define ASMRP_SYM_LEQ 17 -#define ASMRP_SYM_GEQ 18 -#define ASMRP_SYM_GREATER 19 -#define ASMRP_SYM_DOLLAR 20 -#define ASMRP_SYM_LPAREN 21 -#define ASMRP_SYM_RPAREN 22 - -#define ASMRP_MAX_ID 1024 - -#define ASMRP_MAX_SYMTAB 10 - -typedef struct { - char *id; - int v; -} asmrp_sym_t; - -typedef struct { - - /* public part */ - - int sym; - int num; - - char str[ASMRP_MAX_ID]; - - /* private part */ - - char *buf; - int pos; - char ch; - - asmrp_sym_t sym_tab[ASMRP_MAX_SYMTAB]; - int sym_tab_num; - -} asmrp_t; - -static asmrp_t *asmrp_new (void) { - - asmrp_t *p; - - p = malloc (sizeof (asmrp_t)); - - p->sym_tab_num = 0; - p->sym = ASMRP_SYM_NONE; - - return p; -} - -static void asmrp_dispose (asmrp_t *p) { - - int i; - - for (i=0; i<p->sym_tab_num; i++) - free (p->sym_tab[i].id); - - free (p); -} - -static void asmrp_getch (asmrp_t *p) { - p->ch = p->buf[p->pos]; - p->pos++; - -#ifdef LOG - printf ("%c\n", p->ch); -#endif - -} - -static void asmrp_init (asmrp_t *p, const char *str) { - - p->buf = strdup (str); - p->pos = 0; - - asmrp_getch (p); -} - -static void asmrp_number (asmrp_t *p) { - - int num; - - num = 0; - while ( (p->ch>='0') && (p->ch<='9') ) { - - num = num*10 + (p->ch - '0'); - - asmrp_getch (p); - } - - p->sym = ASMRP_SYM_NUM; - p->num = num; -} - -static void asmrp_string (asmrp_t *p) { - - int l; - - l = 0; - - while ( (p->ch!='"') && (p->ch>=32) ) { - - p->str[l] = p->ch; - - l++; - asmrp_getch (p); - } - p->str[l]=0; - - if (p->ch=='"') - asmrp_getch (p); - - p->sym = ASMRP_SYM_STRING; -} - -static void asmrp_identifier (asmrp_t *p) { - - int l; - - l = 0; - - while ( ((p->ch>='A') && (p->ch<='z')) - || ((p->ch>='0') && (p->ch<='9'))) { - - p->str[l] = p->ch; - - l++; - asmrp_getch (p); - } - p->str[l]=0; - - p->sym = ASMRP_SYM_ID; -} - -#ifdef LOG -static void asmrp_print_sym (asmrp_t *p) { - - printf ("symbol: "); - - switch (p->sym) { - - case ASMRP_SYM_NONE: - printf ("NONE\n"); - break; - - case ASMRP_SYM_EOF: - printf ("EOF\n"); - break; - - case ASMRP_SYM_NUM: - printf ("NUM %d\n", p->num); - break; - - case ASMRP_SYM_ID: - printf ("ID '%s'\n", p->str); - break; - - case ASMRP_SYM_STRING: - printf ("STRING \"%s\"\n", p->str); - break; - - case ASMRP_SYM_HASH: - printf ("#\n"); - break; - - case ASMRP_SYM_SEMICOLON: - printf (";\n"); - break; - case ASMRP_SYM_COMMA: - printf (",\n"); - break; - case ASMRP_SYM_EQUALS: - printf ("==\n"); - break; - case ASMRP_SYM_AND: - printf ("&&\n"); - break; - case ASMRP_SYM_OR: - printf ("||\n"); - break; - case ASMRP_SYM_LESS: - printf ("<\n"); - break; - case ASMRP_SYM_LEQ: - printf ("<=\n"); - break; - case ASMRP_SYM_GEQ: - printf (">=\n"); - break; - case ASMRP_SYM_GREATER: - printf (">\n"); - break; - case ASMRP_SYM_DOLLAR: - printf ("$\n"); - break; - case ASMRP_SYM_LPAREN: - printf ("(\n"); - break; - case ASMRP_SYM_RPAREN: - printf (")\n"); - break; - - default: - printf ("unknown symbol %d\n", p->sym); - } -} -#endif - -static void asmrp_get_sym (asmrp_t *p) { - - while (p->ch <= 32) { - if (p->ch == 0) { - p->sym = ASMRP_SYM_EOF; - return; - } - - asmrp_getch (p); - } - - if (p->ch == '\\') - asmrp_getch (p); - - switch (p->ch) { - - case '#': - p->sym = ASMRP_SYM_HASH; - asmrp_getch (p); - break; - case ';': - p->sym = ASMRP_SYM_SEMICOLON; - asmrp_getch (p); - break; - case ',': - p->sym = ASMRP_SYM_COMMA; - asmrp_getch (p); - break; - case '=': - p->sym = ASMRP_SYM_EQUALS; - asmrp_getch (p); - if (p->ch=='=') - asmrp_getch (p); - break; - case '&': - p->sym = ASMRP_SYM_AND; - asmrp_getch (p); - if (p->ch=='&') - asmrp_getch (p); - break; - case '|': - p->sym = ASMRP_SYM_OR; - asmrp_getch (p); - if (p->ch=='|') - asmrp_getch (p); - break; - case '<': - p->sym = ASMRP_SYM_LESS; - asmrp_getch (p); - if (p->ch=='=') { - p->sym = ASMRP_SYM_LEQ; - asmrp_getch (p); - } - break; - case '>': - p->sym = ASMRP_SYM_GREATER; - asmrp_getch (p); - if (p->ch=='=') { - p->sym = ASMRP_SYM_GEQ; - asmrp_getch (p); - } - break; - case '$': - p->sym = ASMRP_SYM_DOLLAR; - asmrp_getch (p); - break; - case '(': - p->sym = ASMRP_SYM_LPAREN; - asmrp_getch (p); - break; - case ')': - p->sym = ASMRP_SYM_RPAREN; - asmrp_getch (p); - break; - - case '"': - asmrp_getch (p); - asmrp_string (p); - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - asmrp_number (p); - break; - - default: - asmrp_identifier (p); - } - -#ifdef LOG - asmrp_print_sym (p); -#endif - -} - -static int asmrp_find_id (asmrp_t *p, char *s) { - - int i; - - for (i=0; i<p->sym_tab_num; i++) { - if (!strcmp (s, p->sym_tab[i].id)) - return i; - } - - return -1; -} - -static int asmrp_set_id (asmrp_t *p, char *s, int v) { - - int i; - - i = asmrp_find_id (p, s); - - if (i<0) { - i = p->sym_tab_num; - p->sym_tab_num++; - p->sym_tab[i].id = strdup (s); - -#ifdef LOG - printf ("new symbol '%s'\n", s); -#endif - - } - - p->sym_tab[i].v = v; - -#ifdef LOG - printf ("symbol '%s' assigned %d\n", s, v); -#endif - - return i; -} - -static int asmrp_condition (asmrp_t *p) ; - -static int asmrp_operand (asmrp_t *p) { - - int i, ret; - -#ifdef LOG - printf ("operand\n"); -#endif - - ret = 0; - - switch (p->sym) { - - case ASMRP_SYM_DOLLAR: - - asmrp_get_sym (p); - - if (p->sym != ASMRP_SYM_ID) { - printf ("error: identifier expected.\n"); - abort(); - } - - i = asmrp_find_id (p, p->str); - if (i<0) { - printf ("error: unknown identifier %s\n", p->str); - } - ret = p->sym_tab[i].v; - - asmrp_get_sym (p); - break; - - case ASMRP_SYM_NUM: - ret = p->num; - - asmrp_get_sym (p); - break; - - case ASMRP_SYM_LPAREN: - asmrp_get_sym (p); - - ret = asmrp_condition (p); - - if (p->sym != ASMRP_SYM_RPAREN) { - printf ("error: ) expected.\n"); - abort(); - } - - asmrp_get_sym (p); - break; - - default: - printf ("syntax error, $ number or ( expected\n"); - abort(); - } - -#ifdef LOG - printf ("operand done, =%d\n", ret); -#endif - - return ret; -} - -static int asmrp_comp_expression (asmrp_t *p) { - - int a; - -#ifdef LOG - printf ("comp_expression\n"); -#endif - - a = asmrp_operand (p); - - while ( (p->sym == ASMRP_SYM_LESS) - || (p->sym == ASMRP_SYM_LEQ) - || (p->sym == ASMRP_SYM_EQUALS) - || (p->sym == ASMRP_SYM_GEQ) - || (p->sym == ASMRP_SYM_GREATER) ) { - int op = p->sym; - int b; - - asmrp_get_sym (p); - - b = asmrp_operand (p); - - switch (op) { - case ASMRP_SYM_LESS: - a = a<b; - break; - case ASMRP_SYM_LEQ: - a = a<=b; - break; - case ASMRP_SYM_EQUALS: - a = a==b; - break; - case ASMRP_SYM_GEQ: - a = a>=b; - break; - case ASMRP_SYM_GREATER: - a = a>b; - break; - } - - } - -#ifdef LOG - printf ("comp_expression done = %d\n", a); -#endif - return a; -} - -static int asmrp_condition (asmrp_t *p) { - - int a; - -#ifdef LOG - printf ("condition\n"); -#endif - - a = asmrp_comp_expression (p); - - while ( (p->sym == ASMRP_SYM_AND) || (p->sym == ASMRP_SYM_OR) ) { - int op, b; - - op = p->sym; - - asmrp_get_sym (p); - - b = asmrp_comp_expression (p); - - switch (op) { - case ASMRP_SYM_AND: - a = a & b; - break; - case ASMRP_SYM_OR: - a = a | b; - break; - } - } - -#ifdef LOG - printf ("condition done = %d\n", a); -#endif - return a; -} - -static void asmrp_assignment (asmrp_t *p) { - -#ifdef LOG - printf ("assignment\n"); -#endif - - if (p->sym == ASMRP_SYM_COMMA || p->sym == ASMRP_SYM_SEMICOLON) { -#ifdef LOG - printf ("empty assignment\n"); -#endif - return; - } - - if (p->sym != ASMRP_SYM_ID) { - printf ("error: identifier expected\n"); - abort (); - } - asmrp_get_sym (p); - - if (p->sym != ASMRP_SYM_EQUALS) { - printf ("error: = expected\n"); - abort (); - } - asmrp_get_sym (p); - - if ( (p->sym != ASMRP_SYM_NUM) && (p->sym != ASMRP_SYM_STRING) - && (p->sym != ASMRP_SYM_ID)) { - printf ("error: number or string expected\n"); - abort (); - } - asmrp_get_sym (p); - -#ifdef LOG - printf ("assignment done\n"); -#endif -} - -static int asmrp_rule (asmrp_t *p) { - - int ret; - -#ifdef LOG - printf ("rule\n"); -#endif - - ret = 1; - - if (p->sym == ASMRP_SYM_HASH) { - - asmrp_get_sym (p); - ret = asmrp_condition (p); - - while (p->sym == ASMRP_SYM_COMMA) { - - asmrp_get_sym (p); - - asmrp_assignment (p); - } - - } else if (p->sym != ASMRP_SYM_SEMICOLON) { - - asmrp_assignment (p); - - while (p->sym == ASMRP_SYM_COMMA) { - - asmrp_get_sym (p); - asmrp_assignment (p); - } - } - -#ifdef LOG - printf ("rule done = %d\n", ret); -#endif - - if (p->sym != ASMRP_SYM_SEMICOLON) { - printf ("semicolon expected.\n"); - abort (); - } - - asmrp_get_sym (p); - - return ret; -} - -static int asmrp_eval (asmrp_t *p, int *matches) { - - int rule_num, num_matches; - -#ifdef LOG - printf ("eval\n"); -#endif - - asmrp_get_sym (p); - - rule_num = 0; num_matches = 0; - while (p->sym != ASMRP_SYM_EOF) { - - if (asmrp_rule (p)) { -#ifdef LOG - printf ("rule #%d is true\n", rule_num); -#endif - matches[num_matches] = rule_num; - num_matches++; - } - - rule_num++; - } - - matches[num_matches] = -1; - return num_matches; -} - -int asmrp_match (const char *rules, int bandwidth, int *matches) { - - asmrp_t *p; - int num_matches; - - p = asmrp_new (); - - asmrp_init (p, rules); - - asmrp_set_id (p, "Bandwidth", bandwidth); - asmrp_set_id (p, "OldPNMPlayer", 0); - - num_matches = asmrp_eval (p, matches); - - asmrp_dispose (p); - - return num_matches; -} -
--- a/libmpdemux/realrtsp/asmrp.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS asmrp.h,v 1.1 2002/12/12 22:14:54 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * a parser for real's asm rules - * - * grammar for these rules: - * - - rule_book = { '#' rule ';'} - rule = condition {',' assignment} - assignment = id '=' const - const = ( number | string ) - condition = comp_expr { ( '&&' | '||' ) comp_expr } - comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } - operand = ( '$' id | num | '(' condition ')' ) - - */ - -#ifndef HAVE_ASMRP_H -#define HAVE_ASMRP_H - -int asmrp_match (const char *rules, int bandwidth, int *matches) ; - -#endif
--- a/libmpdemux/realrtsp/real.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,612 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS real.c,v 1.8 2003/03/30 17:11:50 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * special functions for real streams. - * adopted from joschkas real tools. - * - */ - -#include <stdio.h> -#include <string.h> - -#include "../config.h" -#include "../bswap.h" -#include "real.h" -#include "asmrp.h" -#include "sdpplin.h" -#include "xbuffer.h" -#if USE_LIBAVUTIL_SO -#include "ffmpeg/md5.h" -#else -#include "libavutil/md5.h" -#endif - -/* -#define LOG -*/ - -static const unsigned char xor_table[] = { - 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53, - 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70, - 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09, - 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02, - 0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 }; - - -#define BE_32C(x,y) (*((uint32_t*)(x))=be2me_32(y)) - -#define BE_16(x) be2me_16(*(uint16_t*)(x)) - -#define BE_32(x) be2me_32(*(uint32_t*)(x)) - -#ifndef MAX -#define MAX(x,y) ((x>y) ? x : y) -#endif - -#define BUF_SIZE 4096 - -#ifdef LOG -static void hexdump (const char *buf, int length) { - - int i; - - printf (" hexdump> "); - for (i = 0; i < length; i++) { - unsigned char c = buf[i]; - - printf ("%02x", c); - - if ((i % 16) == 15) - printf ("\n "); - - if ((i % 2) == 1) - printf (" "); - - } - printf ("\n"); -} -#endif - - -static void calc_response_string (char *result, char *challenge) { - - char zres[16]; - int i; - - av_md5_sum(zres, challenge, 64); - - /* convert zres to ascii string */ - for (i=0; i<16; i++ ) { - char a, b; - - a = (zres[i] >> 4) & 15; - b = zres[i] & 15; - - result[i*2] = ((a<10) ? (a+48) : (a+87)) & 255; - result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255; - } -} - -static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) { - - int ch_len, table_len, resp_len; - int i; - char *ptr; - char buf[128]; - - /* initialize return values */ - memset(response, 0, 64); - memset(chksum, 0, 34); - - /* initialize buffer */ - memset(buf, 0, 128); - ptr=buf; - BE_32C(ptr, 0xa1e9149d); - ptr+=4; - BE_32C(ptr, 0x0e6b3b59); - ptr+=4; - - /* some (length) checks */ - if (challenge != NULL) - { - ch_len = strlen (challenge); - - if (ch_len == 40) /* what a hack... */ - { - challenge[32]=0; - ch_len=32; - } - if ( ch_len > 56 ) ch_len=56; - - /* copy challenge to buf */ - memcpy(ptr, challenge, ch_len); - } - - table_len = strlen(xor_table); - - if (table_len > 56) table_len=56; - - /* xor challenge bytewise with xor_table */ - for (i=0; i<table_len; i++) - ptr[i] = ptr[i] ^ xor_table[i]; - - calc_response_string (response, buf); - - /* add tail */ - resp_len = strlen (response); - strcpy (&response[resp_len], "01d0a8e3"); - - /* calculate checksum */ - for (i=0; i<resp_len/4; i++) - chksum[i] = response[i*4]; -} - - -/* - * takes a MLTI-Chunk and a rule number got from match_asm_rule, - * returns a pointer to selected data and number of bytes in that. - */ - -static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) { - - int numrules, codec, size; - int i; - - /* MLTI chunk should begin with MLTI */ - - if ((mlti_chunk[0] != 'M') - ||(mlti_chunk[1] != 'L') - ||(mlti_chunk[2] != 'T') - ||(mlti_chunk[3] != 'I')) - { -#ifdef LOG - printf("libreal: MLTI tag not detected, copying data\n"); -#endif - *out = xbuffer_copyin(*out, 0, mlti_chunk, mlti_size); - return mlti_size; - } - - mlti_chunk+=4; - - /* next 16 bits are the number of rules */ - numrules=BE_16(mlti_chunk); - if (selection >= numrules) return 0; - - /* now <numrules> indices of codecs follows */ - /* we skip to selection */ - mlti_chunk+=(selection+1)*2; - - /* get our index */ - codec=BE_16(mlti_chunk); - - /* skip to number of codecs */ - mlti_chunk+=(numrules-selection)*2; - - /* get number of codecs */ - numrules=BE_16(mlti_chunk); - - if (codec >= numrules) { - printf("codec index >= number of codecs. %i %i\n", codec, numrules); - return 0; - } - - mlti_chunk+=2; - - /* now seek to selected codec */ - for (i=0; i<codec; i++) { - size=BE_32(mlti_chunk); - mlti_chunk+=size+4; - } - - size=BE_32(mlti_chunk); - -#ifdef LOG - hexdump(mlti_chunk+4, size); -#endif - *out = xbuffer_copyin(*out, 0, mlti_chunk+4, size); - return size; -} - -/* - * looking at stream description. - */ - -static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) { - - sdpplin_t *desc; - rmff_header_t *header; - char *buf; - int len, i; - int max_bit_rate=0; - int avg_bit_rate=0; - int max_packet_size=0; - int avg_packet_size=0; - int duration=0; - - - if (!data) return NULL; - - desc=sdpplin_parse(data); - - if (!desc) return NULL; - - buf = xbuffer_init(2048); - header=calloc(1,sizeof(rmff_header_t)); - - header->fileheader=rmff_new_fileheader(4+desc->stream_count); - header->cont=rmff_new_cont( - desc->title, - desc->author, - desc->copyright, - desc->abstract); - header->data=rmff_new_dataheader(0,0); - header->streams=calloc(1,sizeof(rmff_mdpr_t*)*(desc->stream_count+1)); -#ifdef LOG - printf("number of streams: %u\n", desc->stream_count); -#endif - - for (i=0; i<desc->stream_count; i++) { - - int j=0; - int n; - char b[64]; - int rulematches[16]; - -#ifdef LOG - printf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth); -#endif - n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches); - for (j=0; j<n; j++) { -#ifdef LOG - printf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id); -#endif - sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]); - *stream_rules = xbuffer_strcat(*stream_rules, b); - } - - if (!desc->stream[i]->mlti_data) { - len = 0; - buf = NULL; - } else - len=select_mlti_data(desc->stream[i]->mlti_data, desc->stream[i]->mlti_data_size, rulematches[0], &buf); - - header->streams[i]=rmff_new_mdpr( - desc->stream[i]->stream_id, - desc->stream[i]->max_bit_rate, - desc->stream[i]->avg_bit_rate, - desc->stream[i]->max_packet_size, - desc->stream[i]->avg_packet_size, - desc->stream[i]->start_time, - desc->stream[i]->preroll, - desc->stream[i]->duration, - desc->stream[i]->stream_name, - desc->stream[i]->mime_type, - len, - buf); - - duration=MAX(duration,desc->stream[i]->duration); - max_bit_rate+=desc->stream[i]->max_bit_rate; - avg_bit_rate+=desc->stream[i]->avg_bit_rate; - max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size); - if (avg_packet_size) - avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2; - else - avg_packet_size=desc->stream[i]->avg_packet_size; - } - - if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',') - (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */ - - header->prop=rmff_new_prop( - max_bit_rate, - avg_bit_rate, - max_packet_size, - avg_packet_size, - 0, - duration, - 0, - 0, - 0, - desc->stream_count, - desc->flags); - - rmff_fix_header(header); - buf = xbuffer_free(buf); - - return header; -} - -int real_get_rdt_chunk(rtsp_t *rtsp_session, char **buffer) { - - int n=1; - uint8_t header[8]; - rmff_pheader_t ph; - int size; - int flags1, flags2; - int unknown1; - uint32_t ts; - static uint32_t prev_ts = -1; - static int prev_stream_number = -1; - - n=rtsp_read_data(rtsp_session, header, 8); - if (n<8) return 0; - if (header[0] != 0x24) - { - printf("rdt chunk not recognized: got 0x%02x\n", header[0]); - return 0; - } - size=(header[1]<<16)+(header[2]<<8)+(header[3]); - flags1=header[4]; - if ((flags1!=0x40)&&(flags1!=0x42)) - { -#ifdef LOG - printf("got flags1: 0x%02x\n",flags1); -#endif - if(header[6] == 0x06) { - printf("Stream EOF detected\n"); - return -1; - } - header[0]=header[5]; - header[1]=header[6]; - header[2]=header[7]; - n=rtsp_read_data(rtsp_session, header+3, 5); - if (n<5) return 0; -#ifdef LOG - printf("ignoring bytes:\n"); - hexdump(header, 8); -#endif - n=rtsp_read_data(rtsp_session, header+4, 4); - if (n<4) return 0; - flags1=header[4]; - size-=9; - } - flags2=header[7]; - // header[5..6] == frame number in stream - unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]); - n=rtsp_read_data(rtsp_session, header, 6); - if (n<6) return 0; - ts=BE_32(header); - -#ifdef LOG - printf("ts: %u, size: %u, flags: 0x%02x, unknown values: 0x%06x 0x%02x 0x%02x\n", - ts, size, flags1, unknown1, header[4], header[5]); -#endif - size+=2; - - ph.object_version=0; - ph.length=size; - ph.stream_number=(flags1>>1)&1; - ph.timestamp=ts; - ph.reserved=0; - if ((flags2&1) == 0 && (prev_ts != ts || prev_stream_number != ph.stream_number)) - { - prev_ts = ts; - prev_stream_number = ph.stream_number; - ph.flags=2; - } - else - ph.flags=0; - *buffer = xbuffer_ensure_size(*buffer, 12+size); - rmff_dump_pheader(&ph, *buffer); - size-=12; - n=rtsp_read_data(rtsp_session, (*buffer)+12, size); - - return (n <= 0) ? 0 : n+12; -} - -static int convert_timestamp(char *str, int *sec, int *msec) { - int hh, mm, ss, ms = 0; - if (sscanf(str, "%d:%d:%d.%d", &hh, &mm, &ss, &ms) < 3) { - hh = 0; - if (sscanf(str, "%d:%d.%d", &mm, &ss, &ms) < 2) { - mm = 0; - if (sscanf(str, "%d.%d", &ss, &ms) < 1) { - ss = 0; - ms = 0; - } - } - } - if (sec) - *sec = hh * 3600 + mm * 60 + ss; - if (msec) - *msec = ms; - return 1; -} - -//! maximum size of the rtsp description, must be < INT_MAX -#define MAX_DESC_BUF (20 * 1024 * 1024) -rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth) { - - char *description=NULL; - char *session_id=NULL; - rmff_header_t *h; - char *challenge1; - char challenge2[64]; - char checksum[34]; - char *subscribe; - char *buf = xbuffer_init(256); - char *mrl=rtsp_get_mrl(rtsp_session); - unsigned int size; - int status; - uint32_t maxbandwidth = bandwidth; - - /* get challenge */ - challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1")); -#ifdef LOG - printf("real: Challenge1: %s\n", challenge1); -#endif - - /* set a reasonable default to get the best stream, unless bandwidth given */ - if (!bandwidth) - bandwidth = 10485800; - - /* request stream description */ - rtsp_schedule_field(rtsp_session, "Accept: application/sdp"); - sprintf(buf, "Bandwidth: %u", bandwidth); - rtsp_schedule_field(rtsp_session, buf); - rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000"); - rtsp_schedule_field(rtsp_session, "RegionData: 0"); - rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); - rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1"); - rtsp_schedule_field(rtsp_session, "Language: en-US"); - rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup"); - status=rtsp_request_describe(rtsp_session,NULL); - - if ( status<200 || status>299 ) - { - char *alert=rtsp_search_answers(rtsp_session,"Alert"); - if (alert) { - printf("real: got message from server:\n%s\n", alert); - } - rtsp_send_ok(rtsp_session); - buf = xbuffer_free(buf); - return NULL; - } - - /* receive description */ - size=0; - if (!rtsp_search_answers(rtsp_session,"Content-length")) - printf("real: got no Content-length!\n"); - else - size=atoi(rtsp_search_answers(rtsp_session,"Content-length")); - - // as size is unsigned this also catches the case (size < 0) - if (size > MAX_DESC_BUF) { - printf("real: Content-length for description too big (> %uMB)!\n", - MAX_DESC_BUF/(1024*1024) ); - xbuffer_free(buf); - return NULL; - } - - if (!rtsp_search_answers(rtsp_session,"ETag")) - printf("real: got no ETag!\n"); - else - session_id=strdup(rtsp_search_answers(rtsp_session,"ETag")); - -#ifdef LOG - printf("real: Stream description size: %u\n", size); -#endif - - description=malloc(size+1); - - if( rtsp_read_data(rtsp_session, description, size) <= 0) { - buf = xbuffer_free(buf); - return NULL; - } - description[size]=0; - - /* parse sdp (sdpplin) and create a header and a subscribe string */ - subscribe = xbuffer_init(256); - strcpy(subscribe, "Subscribe: "); - h=real_parse_sdp(description, &subscribe, bandwidth); - if (!h) { - subscribe = xbuffer_free(subscribe); - buf = xbuffer_free(buf); - return NULL; - } - rmff_fix_header(h); - -#ifdef LOG - printf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n", - h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams); -#endif - - /* setup our streams */ - real_calc_response_and_checksum (challenge2, checksum, challenge1); - buf = xbuffer_ensure_size(buf, strlen(challenge2) + strlen(checksum) + 32); - sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum); - rtsp_schedule_field(rtsp_session, buf); - buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); - sprintf(buf, "If-Match: %s", session_id); - rtsp_schedule_field(rtsp_session, buf); - rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); - buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); - sprintf(buf, "%s/streamid=0", mrl); - rtsp_request_setup(rtsp_session,buf,NULL); - - if (h->prop->num_streams > 1) { - rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); - buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); - sprintf(buf, "If-Match: %s", session_id); - rtsp_schedule_field(rtsp_session, buf); - - buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); - sprintf(buf, "%s/streamid=1", mrl); - rtsp_request_setup(rtsp_session,buf,NULL); - } - /* set stream parameter (bandwidth) with our subscribe string */ - rtsp_schedule_field(rtsp_session, subscribe); - rtsp_request_setparameter(rtsp_session,NULL); - - /* set delivery bandwidth */ - if (maxbandwidth) { - sprintf(buf, "SetDeliveryBandwidth: Bandwidth=%u;BackOff=0", maxbandwidth); - rtsp_schedule_field(rtsp_session, buf); - rtsp_request_setparameter(rtsp_session,NULL); - } - - { - int s_ss = 0, s_ms = 0, e_ss = 0, e_ms = 0; - char *str; - if ((str = rtsp_get_param(rtsp_session, "start"))) { - convert_timestamp(str, &s_ss, &s_ms); - free(str); - } - if ((str = rtsp_get_param(rtsp_session, "end"))) { - convert_timestamp(str, &e_ss, &e_ms); - free(str); - } - str = buf + sprintf(buf, s_ms ? "%s%d.%d-" : "%s%d-", "Range: npt=", s_ss, s_ms); - if (e_ss || e_ms) - sprintf(str, e_ms ? "%d.%d" : "%d", e_ss, e_ms); - } - rtsp_schedule_field(rtsp_session, buf); - /* and finally send a play request */ - rtsp_request_play(rtsp_session,NULL); - - subscribe = xbuffer_free(subscribe); - buf = xbuffer_free(buf); - return h; -} - -struct real_rtsp_session_t * -init_real_rtsp_session (void) -{ - struct real_rtsp_session_t *real_rtsp_session = NULL; - - real_rtsp_session = malloc (sizeof (struct real_rtsp_session_t)); - real_rtsp_session->recv = xbuffer_init (BUF_SIZE); - - return real_rtsp_session; -} - -void -free_real_rtsp_session (struct real_rtsp_session_t* real_session) -{ - if (!real_session) - return; - - xbuffer_free (real_session->recv); - free (real_session); -}
--- a/libmpdemux/realrtsp/real.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS real.h,v 1.2 2002/12/24 01:30:22 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * special functions for real streams. - * adopted from joschkas real tools. - * - */ - -#ifndef HAVE_REAL_H -#define HAVE_REAL_H - -#include "rmff.h" -#include "../librtsp/rtsp.h" - -#define HEADER_SIZE 4096 - -struct real_rtsp_session_t { - /* receive buffer */ - uint8_t *recv; - int recv_size; - int recv_read; - - /* header buffer */ - uint8_t header[HEADER_SIZE]; - int header_len; - int header_read; -}; - -int real_get_rdt_chunk(rtsp_t *rtsp_session, char **buffer); -rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth); -struct real_rtsp_session_t *init_real_rtsp_session (void); -void free_real_rtsp_session (struct real_rtsp_session_t* real_session); - -#endif -
--- a/libmpdemux/realrtsp/rmff.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,907 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rmff.c,v 1.3 2002/12/24 01:30:22 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * functions for real media file format - * adopted from joschkas real tools - */ - -#include "rmff.h" -#include "xbuffer.h" - -/* -#define LOG -*/ - -#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) -#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ - (((uint8_t*)(x))[1] << 16) | \ - (((uint8_t*)(x))[2] << 8) | \ - ((uint8_t*)(x))[3]) - -static void hexdump (const char *buf, int length) { - - int i; - - printf ("rmff: ascii>"); - for (i = 0; i < length; i++) { - unsigned char c = buf[i]; - - if ((c >= 32) && (c <= 128)) - printf ("%c", c); - else - printf ("."); - } - printf ("\n"); - - printf ("rmff: hexdump> "); - for (i = 0; i < length; i++) { - unsigned char c = buf[i]; - - printf ("%02x", c); - - if ((i % 16) == 15) - printf ("\nrmff: "); - - if ((i % 2) == 1) - printf (" "); - - } - printf ("\n"); -} - -/* - * writes header data to a buffer - */ - -static void rmff_dump_fileheader(rmff_fileheader_t *fileheader, char *buffer) { - - if (!fileheader) return; - fileheader->object_id=BE_32(&fileheader->object_id); - fileheader->size=BE_32(&fileheader->size); - fileheader->object_version=BE_16(&fileheader->object_version); - fileheader->file_version=BE_32(&fileheader->file_version); - fileheader->num_headers=BE_32(&fileheader->num_headers); - - memcpy(buffer, fileheader, 8); - memcpy(&buffer[8], &fileheader->object_version, 2); - memcpy(&buffer[10], &fileheader->file_version, 8); - - fileheader->size=BE_32(&fileheader->size); - fileheader->object_version=BE_16(&fileheader->object_version); - fileheader->file_version=BE_32(&fileheader->file_version); - fileheader->num_headers=BE_32(&fileheader->num_headers); - fileheader->object_id=BE_32(&fileheader->object_id); -} - -static void rmff_dump_prop(rmff_prop_t *prop, char *buffer) { - - if (!prop) return; - prop->object_id=BE_32(&prop->object_id); - prop->size=BE_32(&prop->size); - prop->object_version=BE_16(&prop->object_version); - prop->max_bit_rate=BE_32(&prop->max_bit_rate); - prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); - prop->max_packet_size=BE_32(&prop->max_packet_size); - prop->avg_packet_size=BE_32(&prop->avg_packet_size); - prop->num_packets=BE_32(&prop->num_packets); - prop->duration=BE_32(&prop->duration); - prop->preroll=BE_32(&prop->preroll); - prop->index_offset=BE_32(&prop->index_offset); - prop->data_offset=BE_32(&prop->data_offset); - prop->num_streams=BE_16(&prop->num_streams); - prop->flags=BE_16(&prop->flags); - - memcpy(buffer, prop, 8); - memcpy(&buffer[8], &prop->object_version, 2); - memcpy(&buffer[10], &prop->max_bit_rate, 36); - memcpy(&buffer[46], &prop->num_streams, 2); - memcpy(&buffer[48], &prop->flags, 2); - - prop->size=BE_32(&prop->size); - prop->object_version=BE_16(&prop->object_version); - prop->max_bit_rate=BE_32(&prop->max_bit_rate); - prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); - prop->max_packet_size=BE_32(&prop->max_packet_size); - prop->avg_packet_size=BE_32(&prop->avg_packet_size); - prop->num_packets=BE_32(&prop->num_packets); - prop->duration=BE_32(&prop->duration); - prop->preroll=BE_32(&prop->preroll); - prop->index_offset=BE_32(&prop->index_offset); - prop->data_offset=BE_32(&prop->data_offset); - prop->num_streams=BE_16(&prop->num_streams); - prop->flags=BE_16(&prop->flags); - prop->object_id=BE_32(&prop->object_id); -} - -static void rmff_dump_mdpr(rmff_mdpr_t *mdpr, char *buffer) { - - int s1, s2, s3; - - if (!mdpr) return; - mdpr->object_id=BE_32(&mdpr->object_id); - mdpr->size=BE_32(&mdpr->size); - mdpr->object_version=BE_16(&mdpr->object_version); - mdpr->stream_number=BE_16(&mdpr->stream_number); - mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); - mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); - mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); - mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); - mdpr->start_time=BE_32(&mdpr->start_time); - mdpr->preroll=BE_32(&mdpr->preroll); - mdpr->duration=BE_32(&mdpr->duration); - - memcpy(buffer, mdpr, 8); - memcpy(&buffer[8], &mdpr->object_version, 2); - memcpy(&buffer[10], &mdpr->stream_number, 2); - memcpy(&buffer[12], &mdpr->max_bit_rate, 28); - memcpy(&buffer[40], &mdpr->stream_name_size, 1); - s1=mdpr->stream_name_size; - memcpy(&buffer[41], mdpr->stream_name, s1); - - memcpy(&buffer[41+s1], &mdpr->mime_type_size, 1); - s2=mdpr->mime_type_size; - memcpy(&buffer[42+s1], mdpr->mime_type, s2); - - mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); - memcpy(&buffer[42+s1+s2], &mdpr->type_specific_len, 4); - mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); - s3=mdpr->type_specific_len; - memcpy(&buffer[46+s1+s2], mdpr->type_specific_data, s3); - - mdpr->size=BE_32(&mdpr->size); - mdpr->stream_number=BE_16(&mdpr->stream_number); - mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); - mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); - mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); - mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); - mdpr->start_time=BE_32(&mdpr->start_time); - mdpr->preroll=BE_32(&mdpr->preroll); - mdpr->duration=BE_32(&mdpr->duration); - mdpr->object_id=BE_32(&mdpr->object_id); - -} - -static void rmff_dump_cont(rmff_cont_t *cont, char *buffer) { - - int p; - - if (!cont) return; - cont->object_id=BE_32(&cont->object_id); - cont->size=BE_32(&cont->size); - cont->object_version=BE_16(&cont->object_version); - - memcpy(buffer, cont, 8); - memcpy(&buffer[8], &cont->object_version, 2); - - cont->title_len=BE_16(&cont->title_len); - memcpy(&buffer[10], &cont->title_len, 2); - cont->title_len=BE_16(&cont->title_len); - memcpy(&buffer[12], cont->title, cont->title_len); - p=12+cont->title_len; - - cont->author_len=BE_16(&cont->author_len); - memcpy(&buffer[p], &cont->author_len, 2); - cont->author_len=BE_16(&cont->author_len); - memcpy(&buffer[p+2], cont->author, cont->author_len); - p+=2+cont->author_len; - - cont->copyright_len=BE_16(&cont->copyright_len); - memcpy(&buffer[p], &cont->copyright_len, 2); - cont->copyright_len=BE_16(&cont->copyright_len); - memcpy(&buffer[p+2], cont->copyright, cont->copyright_len); - p+=2+cont->copyright_len; - - cont->comment_len=BE_16(&cont->comment_len); - memcpy(&buffer[p], &cont->comment_len, 2); - cont->comment_len=BE_16(&cont->comment_len); - memcpy(&buffer[p+2], cont->comment, cont->comment_len); - - cont->size=BE_32(&cont->size); - cont->object_version=BE_16(&cont->object_version); - cont->object_id=BE_32(&cont->object_id); -} - -static void rmff_dump_dataheader(rmff_data_t *data, char *buffer) { - - if (!data) return; - data->object_id=BE_32(&data->object_id); - data->size=BE_32(&data->size); - data->object_version=BE_16(&data->object_version); - data->num_packets=BE_32(&data->num_packets); - data->next_data_header=BE_32(&data->next_data_header); - - memcpy(buffer, data, 8); - memcpy(&buffer[8], &data->object_version, 2); - memcpy(&buffer[10], &data->num_packets, 8); - - data->num_packets=BE_32(&data->num_packets); - data->next_data_header=BE_32(&data->next_data_header); - data->size=BE_32(&data->size); - data->object_version=BE_16(&data->object_version); - data->object_id=BE_32(&data->object_id); -} - -int rmff_dump_header(rmff_header_t *h, char *buffer, int max) { - - int written=0; - rmff_mdpr_t **stream=h->streams; - - rmff_dump_fileheader(h->fileheader, &buffer[written]); - written+=h->fileheader->size; - rmff_dump_prop(h->prop, &buffer[written]); - written+=h->prop->size; - rmff_dump_cont(h->cont, &buffer[written]); - written+=h->cont->size; - if (stream) - { - while(*stream) - { - rmff_dump_mdpr(*stream, &buffer[written]); - written+=(*stream)->size; - stream++; - } - } - - rmff_dump_dataheader(h->data, &buffer[written]); - written+=18; - - return written; -} - -void rmff_dump_pheader(rmff_pheader_t *h, char *data) { - - data[0]=(h->object_version>>8) & 0xff; - data[1]=h->object_version & 0xff; - data[2]=(h->length>>8) & 0xff; - data[3]=h->length & 0xff; - data[4]=(h->stream_number>>8) & 0xff; - data[5]=h->stream_number & 0xff; - data[6]=(h->timestamp>>24) & 0xff; - data[7]=(h->timestamp>>16) & 0xff; - data[8]=(h->timestamp>>8) & 0xff; - data[9]=h->timestamp & 0xff; - data[10]=h->reserved; - data[11]=h->flags; -} - -static rmff_fileheader_t *rmff_scan_fileheader(const char *data) { - - rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); - - fileheader->object_id=BE_32(data); - fileheader->size=BE_32(&data[4]); - fileheader->object_version=BE_16(&data[8]); - if (fileheader->object_version != 0) - { - printf("warning: unknown object version in .RMF: 0x%04x\n", - fileheader->object_version); - } - fileheader->file_version=BE_32(&data[10]); - fileheader->num_headers=BE_32(&data[14]); - - return fileheader; -} - -static rmff_prop_t *rmff_scan_prop(const char *data) { - - rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); - - prop->object_id=BE_32(data); - prop->size=BE_32(&data[4]); - prop->object_version=BE_16(&data[8]); - if (prop->object_version != 0) - { - printf("warning: unknown object version in PROP: 0x%04x\n", - prop->object_version); - } - prop->max_bit_rate=BE_32(&data[10]); - prop->avg_bit_rate=BE_32(&data[14]); - prop->max_packet_size=BE_32(&data[18]); - prop->avg_packet_size=BE_32(&data[22]); - prop->num_packets=BE_32(&data[26]); - prop->duration=BE_32(&data[30]); - prop->preroll=BE_32(&data[34]); - prop->index_offset=BE_32(&data[38]); - prop->data_offset=BE_32(&data[42]); - prop->num_streams=BE_16(&data[46]); - prop->flags=BE_16(&data[48]); - - return prop; -} - -static rmff_mdpr_t *rmff_scan_mdpr(const char *data) { - - rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); - - mdpr->object_id=BE_32(data); - mdpr->size=BE_32(&data[4]); - mdpr->object_version=BE_16(&data[8]); - if (mdpr->object_version != 0) - { - printf("warning: unknown object version in MDPR: 0x%04x\n", - mdpr->object_version); - } - mdpr->stream_number=BE_16(&data[10]); - mdpr->max_bit_rate=BE_32(&data[12]); - mdpr->avg_bit_rate=BE_32(&data[16]); - mdpr->max_packet_size=BE_32(&data[20]); - mdpr->avg_packet_size=BE_32(&data[24]); - mdpr->start_time=BE_32(&data[28]); - mdpr->preroll=BE_32(&data[32]); - mdpr->duration=BE_32(&data[36]); - - mdpr->stream_name_size=data[40]; - mdpr->stream_name=malloc(mdpr->stream_name_size+1); - memcpy(mdpr->stream_name, &data[41], mdpr->stream_name_size); - mdpr->stream_name[mdpr->stream_name_size]=0; - - mdpr->mime_type_size=data[41+mdpr->stream_name_size]; - mdpr->mime_type=malloc(mdpr->mime_type_size+1); - memcpy(mdpr->mime_type, &data[42+mdpr->stream_name_size], mdpr->mime_type_size); - mdpr->mime_type[mdpr->mime_type_size]=0; - - mdpr->type_specific_len=BE_32(&data[42+mdpr->stream_name_size+mdpr->mime_type_size]); - mdpr->type_specific_data=malloc(mdpr->type_specific_len); - memcpy(mdpr->type_specific_data, - &data[46+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len); - - return mdpr; -} - -static rmff_cont_t *rmff_scan_cont(const char *data) { - - rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); - int pos; - - cont->object_id=BE_32(data); - cont->size=BE_32(&data[4]); - cont->object_version=BE_16(&data[8]); - if (cont->object_version != 0) - { - printf("warning: unknown object version in CONT: 0x%04x\n", - cont->object_version); - } - cont->title_len=BE_16(&data[10]); - cont->title=malloc(cont->title_len+1); - memcpy(cont->title, &data[12], cont->title_len); - cont->title[cont->title_len]=0; - pos=cont->title_len+12; - cont->author_len=BE_16(&data[pos]); - cont->author=malloc(cont->author_len+1); - memcpy(cont->author, &data[pos+2], cont->author_len); - cont->author[cont->author_len]=0; - pos=pos+2+cont->author_len; - cont->copyright_len=BE_16(&data[pos]); - cont->copyright=malloc(cont->copyright_len+1); - memcpy(cont->copyright, &data[pos+2], cont->copyright_len); - cont->copyright[cont->copyright_len]=0; - pos=pos+2+cont->copyright_len; - cont->comment_len=BE_16(&data[pos]); - cont->comment=malloc(cont->comment_len+1); - memcpy(cont->comment, &data[pos+2], cont->comment_len); - cont->comment[cont->comment_len]=0; - - return cont; -} - -static rmff_data_t *rmff_scan_dataheader(const char *data) { - - rmff_data_t *dh=malloc(sizeof(rmff_data_t)); - - dh->object_id=BE_32(data); - dh->size=BE_32(&data[4]); - dh->object_version=BE_16(&data[8]); - if (dh->object_version != 0) - { - printf("warning: unknown object version in DATA: 0x%04x\n", - dh->object_version); - } - dh->num_packets=BE_32(&data[10]); - dh->next_data_header=BE_32(&data[14]); - - return dh; -} - -rmff_header_t *rmff_scan_header(const char *data) { - - rmff_header_t *header=malloc(sizeof(rmff_header_t)); - rmff_mdpr_t *mdpr=NULL; - int chunk_size; - uint32_t chunk_type; - const char *ptr=data; - int i; - - header->fileheader=NULL; - header->prop=NULL; - header->cont=NULL; - header->data=NULL; - - chunk_type = BE_32(ptr); - if (chunk_type != RMF_TAG) - { - printf("rmff: not an real media file header (.RMF tag not found).\n"); - free(header); - return NULL; - } - header->fileheader=rmff_scan_fileheader(ptr); - ptr += header->fileheader->size; - - header->streams=malloc(sizeof(rmff_mdpr_t*)*(header->fileheader->num_headers)); - for (i=0; i<header->fileheader->num_headers; i++) { - header->streams[i]=NULL; - } - - for (i=1; i<header->fileheader->num_headers; i++) { - chunk_type = BE_32(ptr); - - if (ptr[0] == 0) - { - printf("rmff: warning: only %d of %d header found.\n", i, header->fileheader->num_headers); - break; - } - - chunk_size=1; - switch (chunk_type) { - case PROP_TAG: - header->prop=rmff_scan_prop(ptr); - chunk_size=header->prop->size; - break; - case MDPR_TAG: - mdpr=rmff_scan_mdpr(ptr); - chunk_size=mdpr->size; - header->streams[mdpr->stream_number]=mdpr; - break; - case CONT_TAG: - header->cont=rmff_scan_cont(ptr); - chunk_size=header->cont->size; - break; - case DATA_TAG: - header->data=rmff_scan_dataheader(ptr); - chunk_size=34; /* hard coded header size */ - break; - default: - printf("unknown chunk\n"); - hexdump(ptr,10); - chunk_size=1; - break; - } - ptr+=chunk_size; - } - - return header; -} - -rmff_header_t *rmff_scan_header_stream(int fd) { - - rmff_header_t *header; - char *buf=xbuffer_init(1024); - int index=0; - uint32_t chunk_type; - uint32_t chunk_size; - - do { - buf = xbuffer_ensure_size(buf, index+8); - recv(fd, buf+index, 8, 0); - chunk_type=BE_32(buf+index); index+=4; - chunk_size=BE_32(buf+index); index+=4; - - switch (chunk_type) { - case DATA_TAG: - chunk_size=18; - case MDPR_TAG: - case CONT_TAG: - case RMF_TAG: - case PROP_TAG: - buf = xbuffer_ensure_size(buf, index+chunk_size-8); - recv(fd, buf+index, (chunk_size-8), 0); - index+=(chunk_size-8); - break; - default: - printf("rmff_scan_header_stream: unknown chunk"); - hexdump(buf+index-8, 8); - chunk_type=DATA_TAG; - } - } while (chunk_type != DATA_TAG); - - header = rmff_scan_header(buf); - - xbuffer_free(buf); - - return header; -} - -void rmff_scan_pheader(rmff_pheader_t *h, char *data) { - - h->object_version=BE_16(data); - h->length=BE_16(data+2); - h->stream_number=BE_16(data+4); - h->timestamp=BE_32(data+6); - h->reserved=(uint8_t)data[10]; - h->flags=(uint8_t)data[11]; -} - -rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers) { - - rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); - - fileheader->object_id=RMF_TAG; - fileheader->size=18; - fileheader->object_version=0; - fileheader->file_version=0; - fileheader->num_headers=num_headers; - - return fileheader; -} - -rmff_prop_t *rmff_new_prop ( - uint32_t max_bit_rate, - uint32_t avg_bit_rate, - uint32_t max_packet_size, - uint32_t avg_packet_size, - uint32_t num_packets, - uint32_t duration, - uint32_t preroll, - uint32_t index_offset, - uint32_t data_offset, - uint16_t num_streams, - uint16_t flags ) { - - rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); - - prop->object_id=PROP_TAG; - prop->size=50; - prop->object_version=0; - - prop->max_bit_rate=max_bit_rate; - prop->avg_bit_rate=avg_bit_rate; - prop->max_packet_size=max_packet_size; - prop->avg_packet_size=avg_packet_size; - prop->num_packets=num_packets; - prop->duration=duration; - prop->preroll=preroll; - prop->index_offset=index_offset; - prop->data_offset=data_offset; - prop->num_streams=num_streams; - prop->flags=flags; - - return prop; -} - -rmff_mdpr_t *rmff_new_mdpr( - uint16_t stream_number, - uint32_t max_bit_rate, - uint32_t avg_bit_rate, - uint32_t max_packet_size, - uint32_t avg_packet_size, - uint32_t start_time, - uint32_t preroll, - uint32_t duration, - const char *stream_name, - const char *mime_type, - uint32_t type_specific_len, - const char *type_specific_data ) { - - rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); - - mdpr->object_id=MDPR_TAG; - mdpr->object_version=0; - - mdpr->stream_number=stream_number; - mdpr->max_bit_rate=max_bit_rate; - mdpr->avg_bit_rate=avg_bit_rate; - mdpr->max_packet_size=max_packet_size; - mdpr->avg_packet_size=avg_packet_size; - mdpr->start_time=start_time; - mdpr->preroll=preroll; - mdpr->duration=duration; - mdpr->stream_name_size=0; - if (stream_name) { - mdpr->stream_name=strdup(stream_name); - mdpr->stream_name_size=strlen(stream_name); - } - mdpr->mime_type_size=0; - if (mime_type) { - mdpr->mime_type=strdup(mime_type); - mdpr->mime_type_size=strlen(mime_type); - } - mdpr->type_specific_len=type_specific_len; - mdpr->type_specific_data=malloc(type_specific_len); - memcpy(mdpr->type_specific_data,type_specific_data,type_specific_len); - mdpr->mlti_data=NULL; - - mdpr->size=mdpr->stream_name_size+mdpr->mime_type_size+mdpr->type_specific_len+46; - - return mdpr; -} - -rmff_cont_t *rmff_new_cont(const char *title, const char *author, const char *copyright, const char *comment) { - - rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); - - cont->object_id=CONT_TAG; - cont->object_version=0; - - cont->title=NULL; - cont->author=NULL; - cont->copyright=NULL; - cont->comment=NULL; - - cont->title_len=0; - cont->author_len=0; - cont->copyright_len=0; - cont->comment_len=0; - - if (title) { - cont->title_len=strlen(title); - cont->title=strdup(title); - } - if (author) { - cont->author_len=strlen(author); - cont->author=strdup(author); - } - if (copyright) { - cont->copyright_len=strlen(copyright); - cont->copyright=strdup(copyright); - } - if (comment) { - cont->comment_len=strlen(comment); - cont->comment=strdup(comment); - } - cont->size=cont->title_len+cont->author_len+cont->copyright_len+cont->comment_len+18; - - return cont; -} - -rmff_data_t *rmff_new_dataheader(uint32_t num_packets, uint32_t next_data_header) { - - rmff_data_t *data=malloc(sizeof(rmff_data_t)); - - data->object_id=DATA_TAG; - data->size=18; - data->object_version=0; - data->num_packets=num_packets; - data->next_data_header=next_data_header; - - return data; -} - -void rmff_print_header(rmff_header_t *h) { - - rmff_mdpr_t **stream; - - if(!h) { - printf("rmff_print_header: NULL given\n"); - return; - } - if(h->fileheader) - { - printf("\nFILE:\n"); - printf("file version : %d\n", h->fileheader->file_version); - printf("number of headers : %d\n", h->fileheader->num_headers); - } - if(h->cont) - { - printf("\nCONTENT:\n"); - printf("title : %s\n", h->cont->title); - printf("author : %s\n", h->cont->author); - printf("copyright : %s\n", h->cont->copyright); - printf("comment : %s\n", h->cont->comment); - } - if(h->prop) - { - printf("\nSTREAM PROPERTIES:\n"); - printf("bit rate (max/avg) : %i/%i\n", h->prop->max_bit_rate, h->prop->avg_bit_rate); - printf("packet size (max/avg) : %i/%i bytes\n", h->prop->max_packet_size, h->prop->avg_packet_size); - printf("packets : %i\n", h->prop->num_packets); - printf("duration : %i ms\n", h->prop->duration); - printf("pre-buffer : %i ms\n", h->prop->preroll); - printf("index offset : %i bytes\n", h->prop->index_offset); - printf("data offset : %i bytes\n", h->prop->data_offset); - printf("media streams : %i\n", h->prop->num_streams); - printf("flags : "); - if (h->prop->flags & PN_SAVE_ENABLED) printf("save_enabled "); - if (h->prop->flags & PN_PERFECT_PLAY_ENABLED) printf("perfect_play_enabled "); - if (h->prop->flags & PN_LIVE_BROADCAST) printf("live_broadcast "); - printf("\n"); - } - stream=h->streams; - if(stream) - { - while (*stream) - { - printf("\nSTREAM %i:\n", (*stream)->stream_number); - printf("stream name [mime type] : %s [%s]\n", (*stream)->stream_name, (*stream)->mime_type); - printf("bit rate (max/avg) : %i/%i\n", (*stream)->max_bit_rate, (*stream)->avg_bit_rate); - printf("packet size (max/avg) : %i/%i bytes\n", (*stream)->max_packet_size, (*stream)->avg_packet_size); - printf("start time : %i\n", (*stream)->start_time); - printf("pre-buffer : %i ms\n", (*stream)->preroll); - printf("duration : %i ms\n", (*stream)->duration); - printf("type specific data:\n"); - hexdump((*stream)->type_specific_data, (*stream)->type_specific_len); - stream++; - } - } - if(h->data) - { - printf("\nDATA:\n"); - printf("size : %i\n", h->data->size); - printf("packets : %i\n", h->data->num_packets); - printf("next DATA : 0x%08x\n", h->data->next_data_header); - } -} - -void rmff_fix_header(rmff_header_t *h) { - - int num_headers=0; - int header_size=0; - rmff_mdpr_t **streams; - int num_streams=0; - - if (!h) { - printf("rmff_fix_header: fatal: no header given.\n"); - return; - } - - if (!h->streams) { - printf("rmff_fix_header: warning: no MDPR chunks\n"); - } else - { - streams=h->streams; - while (*streams) - { - num_streams++; - num_headers++; - header_size+=(*streams)->size; - streams++; - } - } - - if (h->prop) { - if (h->prop->size != 50) - { -#ifdef LOG - printf("rmff_fix_header: correcting prop.size from %i to %i\n", h->prop->size, 50); -#endif - h->prop->size=50; - } - if (h->prop->num_streams != num_streams) - { -#ifdef LOG - printf("rmff_fix_header: correcting prop.num_streams from %i to %i\n", h->prop->num_streams, num_streams); -#endif - h->prop->num_streams=num_streams; - } - num_headers++; - header_size+=50; - } else - printf("rmff_fix_header: warning: no PROP chunk.\n"); - - if (h->cont) { - num_headers++; - header_size+=h->cont->size; - } else - printf("rmff_fix_header: warning: no CONT chunk.\n"); - - if (!h->data) { -#ifdef LOG - printf("rmff_fix_header: no DATA chunk, creating one\n"); -#endif - h->data=malloc(sizeof(rmff_data_t)); - h->data->object_id=DATA_TAG; - h->data->object_version=0; - h->data->size=34; - h->data->num_packets=0; - h->data->next_data_header=0; - } - num_headers++; - - - if (!h->fileheader) { -#ifdef LOG - printf("rmff_fix_header: no fileheader, creating one"); -#endif - h->fileheader=malloc(sizeof(rmff_fileheader_t)); - h->fileheader->object_id=RMF_TAG; - h->fileheader->size=34; - h->fileheader->object_version=0; - h->fileheader->file_version=0; - h->fileheader->num_headers=num_headers+1; - } - header_size+=h->fileheader->size; - num_headers++; - - if(h->fileheader->num_headers != num_headers) { -#ifdef LOG - printf("rmff_fix_header: setting num_headers from %i to %i\n", h->fileheader->num_headers, num_headers); -#endif - h->fileheader->num_headers=num_headers; - } - - if(h->prop) { - if (h->prop->data_offset != header_size) { -#ifdef LOG - printf("rmff_fix_header: setting prop.data_offset from %i to %i\n", h->prop->data_offset, header_size); -#endif - h->prop->data_offset=header_size; - } - if (h->prop->num_packets == 0) { - int p=(int)(h->prop->avg_bit_rate/8.0*(h->prop->duration/1000.0)/h->prop->avg_packet_size); -#ifdef LOG - printf("rmff_fix_header: assuming prop.num_packets=%i\n", p); -#endif - h->prop->num_packets=p; - } - if (h->data->num_packets == 0) { -#ifdef LOG - printf("rmff_fix_header: assuming data.num_packets=%i\n", h->prop->num_packets); -#endif - h->data->num_packets=h->prop->num_packets; - } - -#ifdef LOG - printf("rmff_fix_header: assuming data.size=%i\n", h->prop->num_packets*h->prop->avg_packet_size); -#endif - h->data->size=h->prop->num_packets*h->prop->avg_packet_size; - } -} - -int rmff_get_header_size(rmff_header_t *h) { - - if (!h) return 0; - if (!h->prop) return -1; - - return h->prop->data_offset+18; - -} - -void rmff_free_header(rmff_header_t *h) { - - if (!h) return; - - if (h->fileheader) free(h->fileheader); - if (h->prop) free(h->prop); - if (h->data) free(h->data); - if (h->cont) - { - free(h->cont->title); - free(h->cont->author); - free(h->cont->copyright); - free(h->cont->comment); - free(h->cont); - } - if (h->streams) - { - rmff_mdpr_t **s=h->streams; - - while(*s) { - free((*s)->stream_name); - free((*s)->mime_type); - free((*s)->type_specific_data); - free(*s); - s++; - } - free(h->streams); - } - free(h); -}
--- a/libmpdemux/realrtsp/rmff.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS rmff.h,v 1.3 2003/02/10 22:11:10 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * some functions for real media file headers - * adopted from joschkas real tools - */ - -#include <sys/types.h> -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#else -#include <winsock2.h> -#endif -#include <unistd.h> -#include <stdio.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> - - -#ifndef HAVE_RMFF_H -#define HAVE_RMFF_H - - -#define RMFF_HEADER_SIZE 0x12 - -#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ - (((long)(unsigned char)(ch3) ) | \ - ( (long)(unsigned char)(ch2) << 8 ) | \ - ( (long)(unsigned char)(ch1) << 16 ) | \ - ( (long)(unsigned char)(ch0) << 24 ) ) - - -#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') -#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') -#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') -#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') -#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') -#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') -#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) - -#define MLTI_TAG FOURCC_TAG('M', 'L', 'T', 'I') - -/* prop flags */ -#define PN_SAVE_ENABLED 0x01 -#define PN_PERFECT_PLAY_ENABLED 0x02 -#define PN_LIVE_BROADCAST 0x04 - -/* - * rm header data structs - */ - -typedef struct { - - uint32_t object_id; - uint32_t size; - uint16_t object_version; - - uint32_t file_version; - uint32_t num_headers; -} rmff_fileheader_t; - -typedef struct { - - uint32_t object_id; - uint32_t size; - uint16_t object_version; - - uint32_t max_bit_rate; - uint32_t avg_bit_rate; - uint32_t max_packet_size; - uint32_t avg_packet_size; - uint32_t num_packets; - uint32_t duration; - uint32_t preroll; - uint32_t index_offset; - uint32_t data_offset; - uint16_t num_streams; - uint16_t flags; - -} rmff_prop_t; - -typedef struct { - - uint32_t object_id; - uint32_t size; - uint16_t object_version; - - uint16_t stream_number; - uint32_t max_bit_rate; - uint32_t avg_bit_rate; - uint32_t max_packet_size; - uint32_t avg_packet_size; - uint32_t start_time; - uint32_t preroll; - uint32_t duration; - uint8_t stream_name_size; - char *stream_name; - uint8_t mime_type_size; - char *mime_type; - uint32_t type_specific_len; - char *type_specific_data; - - int mlti_data_size; - char *mlti_data; - -} rmff_mdpr_t; - -typedef struct { - - uint32_t object_id; - uint32_t size; - uint16_t object_version; - - uint16_t title_len; - char *title; - uint16_t author_len; - char *author; - uint16_t copyright_len; - char *copyright; - uint16_t comment_len; - char *comment; - -} rmff_cont_t; - -typedef struct { - - uint32_t object_id; - uint32_t size; - uint16_t object_version; - - uint32_t num_packets; - uint32_t next_data_header; /* rarely used */ -} rmff_data_t; - -typedef struct { - - rmff_fileheader_t *fileheader; - rmff_prop_t *prop; - rmff_mdpr_t **streams; - rmff_cont_t *cont; - rmff_data_t *data; -} rmff_header_t; - -typedef struct { - - uint16_t object_version; - - uint16_t length; - uint16_t stream_number; - uint32_t timestamp; - uint8_t reserved; - uint8_t flags; - -} rmff_pheader_t; - -/* - * constructors for header structs - */ - -rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers); - -rmff_prop_t *rmff_new_prop ( - uint32_t max_bit_rate, - uint32_t avg_bit_rate, - uint32_t max_packet_size, - uint32_t avg_packet_size, - uint32_t num_packets, - uint32_t duration, - uint32_t preroll, - uint32_t index_offset, - uint32_t data_offset, - uint16_t num_streams, - uint16_t flags ); - -rmff_mdpr_t *rmff_new_mdpr( - uint16_t stream_number, - uint32_t max_bit_rate, - uint32_t avg_bit_rate, - uint32_t max_packet_size, - uint32_t avg_packet_size, - uint32_t start_time, - uint32_t preroll, - uint32_t duration, - const char *stream_name, - const char *mime_type, - uint32_t type_specific_len, - const char *type_specific_data ); - -rmff_cont_t *rmff_new_cont( - const char *title, - const char *author, - const char *copyright, - const char *comment); - -rmff_data_t *rmff_new_dataheader( - uint32_t num_packets, uint32_t next_data_header); - -/* - * reads header infos from data and returns a newly allocated header struct - */ -rmff_header_t *rmff_scan_header(const char *data); - -/* - * scans a data packet header. Notice, that this function does not allocate - * the header struct itself. - */ -void rmff_scan_pheader(rmff_pheader_t *h, char *data); - -/* - * reads header infos from stream and returns a newly allocated header struct - */ -rmff_header_t *rmff_scan_header_stream(int fd); - -/* - * prints header information in human readible form to stdout - */ -void rmff_print_header(rmff_header_t *h); - -/* - * does some checks and fixes header if possible - */ -void rmff_fix_header(rmff_header_t *h); - -/* - * returns the size of the header (incl. first data-header) - */ -int rmff_get_header_size(rmff_header_t *h); - -/* - * dumps the header <h> to <buffer>. <max> is the size of <buffer> - */ -int rmff_dump_header(rmff_header_t *h, char *buffer, int max); - -/* - * dumps a packet header - */ -void rmff_dump_pheader(rmff_pheader_t *h, char *data); - -/* - * frees a header struct - */ -void rmff_free_header(rmff_header_t *h); - -#endif
--- a/libmpdemux/realrtsp/sdpplin.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,366 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS sdpplin.c,v 1.1 2002/12/24 01:30:22 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * sdp/sdpplin parser. - * - */ - -#include "config.h" -#include "../librtsp/rtsp.h" -#include "sdpplin.h" -#include "xbuffer.h" -#include "mp_msg.h" - -/* -#define LOG -*/ - -/* - * Decodes base64 strings (based upon b64 package) - */ - -static char *b64_decode(const char *in, char *out, int *size) -{ - char dtable[256]; /* Encode / decode table */ - int i,j,k; - - for (i = 0; i < 255; i++) { - dtable[i] = 0x80; - } - for (i = 'A'; i <= 'Z'; i++) { - dtable[i] = 0 + (i - 'A'); - } - for (i = 'a'; i <= 'z'; i++) { - dtable[i] = 26 + (i - 'a'); - } - for (i = '0'; i <= '9'; i++) { - dtable[i] = 52 + (i - '0'); - } - dtable['+'] = 62; - dtable['/'] = 63; - dtable['='] = 0; - - k=0; - - /*CONSTANTCONDITION*/ - for (j=0; j<strlen(in); j+=4) - { - char a[4], b[4]; - - for (i = 0; i < 4; i++) { - int c = in[i+j]; - - if (dtable[c] & 0x80) { - printf("Illegal character '%c' in input.\n", c); -// exit(1); - return NULL; - } - a[i] = (char) c; - b[i] = (char) dtable[c]; - } - out = xbuffer_ensure_size(out, k+4); - out[k++] = (b[0] << 2) | (b[1] >> 4); - out[k++] = (b[1] << 4) | (b[2] >> 2); - out[k++] = (b[2] << 6) | b[3]; - i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); - if (i < 3) { - out[k]=0; - *size=k; - return out; - } - } - out[k]=0; - *size=k; - return out; -} - -static char *nl(char *data) { - - char *nlptr = (data) ? strchr(data,'\n') : NULL; - return (nlptr) ? nlptr + 1 : NULL; -} - -static int filter(const char *in, const char *filter, char **out) { - - int flen=strlen(filter); - int len; - - if (!in) - return 0; - - len = (strchr(in,'\n')) ? strchr(in,'\n')-in : strlen(in); - - if (!strncmp(in,filter,flen)) - { - if(in[flen]=='"') flen++; - if(in[len-1]==13) len--; - if(in[len-1]=='"') len--; - *out = xbuffer_copyin(*out, 0, in+flen, len-flen+1); - (*out)[len-flen]=0; - - return len-flen; - } - - return 0; -} -static sdpplin_stream_t *sdpplin_parse_stream(char **data) { - - sdpplin_stream_t *desc=calloc(1,sizeof(sdpplin_stream_t)); - char *buf=xbuffer_init(32); - char *decoded=xbuffer_init(32); - int handled; - int got_mimetype; - - if (filter(*data, "m=", &buf)) { - desc->id = strdup(buf); - } else - { - printf("sdpplin: no m= found.\n"); - free(desc); - xbuffer_free(buf); - return NULL; - } - *data=nl(*data); - - got_mimetype = 0; - - while (*data && **data && *data[0]!='m') { -#ifdef LOG - { - int len=strchr(*data,'\n')-(*data); - buf = xbuffer_copyin(buf, 0, *data, len+1); - buf[len]=0; - printf("libreal: sdpplin_stream: '%s'\n", buf); - } -#endif - - handled=0; - - if(filter(*data,"a=control:streamid=",&buf)) { - desc->stream_id=atoi(buf); - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=MaxBitRate:integer;",&buf)) { - desc->max_bit_rate=atoi(buf); - if (!desc->avg_bit_rate) - desc->avg_bit_rate=desc->max_bit_rate; - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=MaxPacketSize:integer;",&buf)) { - desc->max_packet_size=atoi(buf); - if (!desc->avg_packet_size) - desc->avg_packet_size=desc->max_packet_size; - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=StartTime:integer;",&buf)) { - desc->start_time=atoi(buf); - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=Preroll:integer;",&buf)) { - desc->preroll=atoi(buf); - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=length:npt=",&buf)) { - desc->duration=(uint32_t)(atof(buf)*1000); - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=StreamName:string;",&buf)) { - desc->stream_name=strdup(buf); - desc->stream_name_size=strlen(desc->stream_name); - handled=1; - *data=nl(*data); - } - - if(filter(*data,"a=mimetype:string;",&buf)) { - desc->mime_type=strdup(buf); - desc->mime_type_size=strlen(desc->mime_type); - handled=1; - got_mimetype = 1; - *data=nl(*data); - } - - if(filter(*data,"a=OpaqueData:buffer;",&buf)) { - decoded = b64_decode(buf, decoded, &(desc->mlti_data_size)); - desc->mlti_data=malloc(desc->mlti_data_size); - memcpy(desc->mlti_data, decoded, desc->mlti_data_size); - handled=1; - *data=nl(*data); -#ifdef LOG - printf("mlti_data_size: %i\n", desc->mlti_data_size); -#endif - } - - if(filter(*data,"a=ASMRuleBook:string;",&buf)) { - desc->asm_rule_book=strdup(buf); - handled=1; - *data=nl(*data); - } - - if(!handled) { -#ifdef LOG - int len=strchr(*data,'\n')-(*data); - buf = xbuffer_copyin(buf, 0, *data, len+1); - buf[len]=0; - printf("libreal: sdpplin_stream: not handled: '%s'\n", buf); -#endif - *data=nl(*data); - } - } - - if (!got_mimetype) { - mp_msg(MSGT_OPEN, MSGL_V, "libreal: sdpplin_stream: no mimetype\n"); - desc->mime_type = strdup("audio/x-pn-realaudio"); - desc->mime_type_size = strlen(desc->mime_type); - if (desc->stream_id) - mp_msg(MSGT_OPEN, MSGL_WARN, "libreal: sdpplin_stream: implicit mimetype for stream_id != 0, weird.\n"); - } - - xbuffer_free(buf); - xbuffer_free(decoded); - - return desc; -} - -sdpplin_t *sdpplin_parse(char *data) { - - sdpplin_t *desc=calloc(1,sizeof(sdpplin_t)); - char *buf=xbuffer_init(32); - char *decoded=xbuffer_init(32); - int handled; - int len; - - while (data && *data) { -#ifdef LOG - { - int len=strchr(data,'\n')-(data); - buf = xbuffer_copyin(buf, 0, data, len+1); - buf[len]=0; - printf("libreal: sdpplin: '%s'\n", buf); - } -#endif - - handled=0; - - if (filter(data, "m=", &buf)) { - sdpplin_stream_t *stream=sdpplin_parse_stream(&data); -#ifdef LOG - printf("got data for stream id %u\n", stream->stream_id); -#endif - if (desc->stream && (stream->stream_id >= 0) && (stream->stream_id < desc->stream_count)) - desc->stream[stream->stream_id]=stream; - else if (desc->stream) - { - mp_msg(MSGT_OPEN, MSGL_ERR, "sdpplin: bad stream_id %d (must be >= 0, < %d). Broken sdp?\n", - stream->stream_id, desc->stream_count); - free(stream); - } else { - mp_msg(MSGT_OPEN, MSGL_V, "sdpplin: got 'm=', but 'a=StreamCount' is still unknown.\n"); - if (stream->stream_id == 0) { - desc->stream_count=1; - desc->stream=malloc(sizeof(sdpplin_stream_t*)); - desc->stream[0]=stream; - } else { - mp_msg(MSGT_OPEN, MSGL_ERR, "sdpplin: got 'm=', but 'a=StreamCount' is still unknown and stream_id != 0. Broken sdp?\n"); - free(stream); - } - } - continue; - } - - if(filter(data,"a=Title:buffer;",&buf)) { - decoded=b64_decode(buf, decoded, &len); - desc->title=strdup(decoded); - handled=1; - data=nl(data); - } - - if(filter(data,"a=Author:buffer;",&buf)) { - decoded=b64_decode(buf, decoded, &len); - desc->author=strdup(decoded); - handled=1; - data=nl(data); - } - - if(filter(data,"a=Copyright:buffer;",&buf)) { - decoded=b64_decode(buf, decoded, &len); - desc->copyright=strdup(decoded); - handled=1; - data=nl(data); - } - - if(filter(data,"a=Abstract:buffer;",&buf)) { - decoded=b64_decode(buf, decoded, &len); - desc->abstract=strdup(decoded); - handled=1; - data=nl(data); - } - - if(filter(data,"a=StreamCount:integer;",&buf)) { - desc->stream_count=(unsigned int)atoi(buf); - desc->stream=malloc(sizeof(sdpplin_stream_t*)*desc->stream_count); - handled=1; - data=nl(data); - } - - if(filter(data,"a=Flags:integer;",&buf)) { - desc->flags=atoi(buf); - handled=1; - data=nl(data); - } - - if(!handled) { -#ifdef LOG - int len=strchr(data,'\n')-data; - buf = xbuffer_copyin(buf, 0, data, len+1); - buf[len]=0; - printf("libreal: sdpplin: not handled: '%s'\n", buf); -#endif - data=nl(data); - } - } - - xbuffer_free(buf); - xbuffer_free(decoded); - - return desc; -} - -void sdpplin_free(sdpplin_t *description) { - - /* TODO: free strings */ - free(description); -} -
--- a/libmpdemux/realrtsp/sdpplin.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * This file was ported to MPlayer from xine CVS sdpplin.h,v 1.1 2002/12/24 01:30:22 - */ - -/* - * Copyright (C) 2002 the xine project - * - * This file is part of xine, a free video player. - * - * xine is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * xine is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU 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 - * - * - * sdp/sdpplin parser. - * - */ - -#ifndef HAVE_SDPPLIN_H -#define HAVE_SDPPLIN_H - -#include "rmff.h" -#include "../librtsp/rtsp.h" - -typedef struct { - - char *id; - char *bandwidth; - - int stream_id; - char *range; - char *length; - char *rtpmap; - char *mimetype; - int min_switch_overlap; - int start_time; - int end_one_rule_end_all; - int avg_bit_rate; - int max_bit_rate; - int avg_packet_size; - int max_packet_size; - int end_time; - int seek_greater_on_switch; - int preroll; - - int duration; - char *stream_name; - int stream_name_size; - char *mime_type; - int mime_type_size; - char *mlti_data; - int mlti_data_size; - int rmff_flags_length; - char *rmff_flags; - int asm_rule_book_length; - char *asm_rule_book; - -} sdpplin_stream_t; - -typedef struct { - - int sdp_version, sdpplin_version; - char *owner; - char *session_name; - char *session_info; - char *uri; - char *email; - char *phone; - char *connection; - char *bandwidth; - - int flags; - int is_real_data_type; - int stream_count; - char *title; - char *author; - char *copyright; - char *keywords; - int asm_rule_book_length; - char *asm_rule_book; - char *abstract; - char *range; - int avg_bit_rate; - int max_bit_rate; - int avg_packet_size; - int max_packet_size; - int preroll; - int duration; - - sdpplin_stream_t **stream; - -} sdpplin_t; - -sdpplin_t *sdpplin_parse(char *data); - -void sdpplin_free(sdpplin_t *description); - -#endif -
--- a/libmpdemux/realrtsp/xbuffer.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * xbuffer code - * - * Includes a minimalistic replacement for xine_buffer functions used in - * Real streaming code. Only function needed by this code are implemented. - * - * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project - * - * WARNING: do not mix original xine_buffer functions with this code! - * xbuffers behave like xine_buffers, but are not byte-compatible with them. - * You must take care of pointers returned by xbuffers functions (no macro to - * do it automatically) - * - */ - -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> -#include "xbuffer.h" - - -typedef struct { - uint32_t size; - uint32_t chunk_size; -} xbuffer_header_t; - -#define XBUFFER_HEADER_SIZE sizeof (xbuffer_header_t) - - - -void *xbuffer_init(int chunk_size) { - uint8_t *data=calloc(1,chunk_size+XBUFFER_HEADER_SIZE); - - xbuffer_header_t *header=(xbuffer_header_t*)data; - - header->size=chunk_size; - header->chunk_size=chunk_size; - - return data+XBUFFER_HEADER_SIZE; -} - - - -void *xbuffer_free(void *buf) { - if (!buf) { - return NULL; - } - - free(((uint8_t*)buf)-XBUFFER_HEADER_SIZE); - - return NULL; -} - - - -void *xbuffer_copyin(void *buf, int index, const void *data, int len) { - if (!buf || !data) { - return NULL; - } - - buf = xbuffer_ensure_size(buf, index+len); - memcpy(((uint8_t*)buf)+index, data, len); - - return buf; -} - - - -void *xbuffer_ensure_size(void *buf, int size) { - xbuffer_header_t *xbuf; - int new_size; - - if (!buf) { - return 0; - } - - xbuf = ((xbuffer_header_t*)(((uint8_t*)buf)-XBUFFER_HEADER_SIZE)); - - if (xbuf->size < size) { - new_size = size + xbuf->chunk_size - (size % xbuf->chunk_size); - xbuf->size = new_size; - buf = ((uint8_t*)realloc(((uint8_t*)buf)-XBUFFER_HEADER_SIZE, - new_size+XBUFFER_HEADER_SIZE)) + XBUFFER_HEADER_SIZE; - } - - return buf; -} - - - -void *xbuffer_strcat(void *buf, char *data) { - - if (!buf || !data) { - return NULL; - } - - buf = xbuffer_ensure_size(buf, strlen(buf)+strlen(data)+1); - - strcat(buf, data); - - return buf; -}
--- a/libmpdemux/realrtsp/xbuffer.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * xbuffer code - * - * Includes a minimalistic replacement for xine_buffer functions used in - * Real streaming code. Only function needed by this code are implemented. - * - * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project - * - * WARNING: do not mix original xine_buffer functions with this code! - * xbuffers behave like xine_buffers, but are not byte-compatible with them. - * You must take care of pointers returned by xbuffers functions (no macro to - * do it automatically) - * - */ - - -#ifndef _XCL_H_ -#define _XCL_H_ - -void *xbuffer_init(int chunk_size); -void *xbuffer_free(void *buf); -void *xbuffer_copyin(void *buf, int index, const void *data, int len); -void *xbuffer_ensure_size(void *buf, int size); -void *xbuffer_strcat(void *buf, char *data); - -#endif
--- a/libmpdemux/rtp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,434 +0,0 @@ -/* Imported from the dvbstream-0.2 project - * - * Modified for use with MPlayer, for details see the changelog at - * http://svn.mplayerhq.hu/mplayer/trunk/ - * $Id$ - */ - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/types.h> -#include <ctype.h> -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <netinet/in.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#define closesocket close -#else -#include <winsock2.h> -#include <ws2tcpip.h> -#endif -#include <errno.h> -#include "stream.h" - -/* MPEG-2 TS RTP stack */ - -#define DEBUG 1 -#include "rtp.h" - -extern int network_bandwidth; - - -#define DEBUG 1 -#include "../mp_msg.h" -#include "rtp.h" - -// RTP reorder routines -// Also handling of repeated UDP packets (a bug of ExtremeNetworks switches firmware) -// rtpreord procedures -// write rtp packets in cache -// get rtp packets reordered - -#define MAXRTPPACKETSIN 32 // The number of max packets being reordered - -struct rtpbuffer -{ - unsigned char data[MAXRTPPACKETSIN][STREAM_BUFFER_SIZE]; - unsigned short seq[MAXRTPPACKETSIN]; - unsigned short len[MAXRTPPACKETSIN]; - unsigned short first; -}; -static struct rtpbuffer rtpbuf; - -// RTP Reordering functions -// Algorithm works as follows: -// If next packet is in sequence just copy it to buffer -// Otherwise copy it in cache according to its sequence number -// Cache is a circular array where "rtpbuf.first" points to next sequence slot -// and keeps track of expected sequence - -// Initialize rtp cache -static void rtp_cache_reset(unsigned short seq) -{ - int i; - - rtpbuf.first = 0; - rtpbuf.seq[0] = ++seq; - - for (i=0; i<MAXRTPPACKETSIN; i++) { - rtpbuf.len[i] = 0; - } -} - -// Write in a cache the rtp packet in right rtp sequence order -static int rtp_cache(int fd, char *buffer, int length) -{ - struct rtpheader rh; - int newseq; - char *data; - unsigned short seq; - static int is_first = 1; - - getrtp2(fd, &rh, &data, &length); - if(!length) - return 0; - seq = rh.b.sequence; - - newseq = seq - rtpbuf.seq[rtpbuf.first]; - - if ((newseq == 0) || is_first) - { - is_first = 0; - - //mp_msg(MSGT_NETWORK, MSGL_DBG4, "RTP (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); - rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN; - rtpbuf.seq[rtpbuf.first] = ++seq; - goto feed; - } - - if (newseq > MAXRTPPACKETSIN) - { - mp_msg(MSGT_NETWORK, MSGL_DBG2, "Overrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); - rtp_cache_reset(seq); - goto feed; - } - - if (newseq < 0) - { - int i; - - // Is it a stray packet re-sent to network? - for (i=0; i<MAXRTPPACKETSIN; i++) { - if (rtpbuf.seq[i] == seq) { - mp_msg(MSGT_NETWORK, MSGL_ERR, "Stray packet (seq[%d]=%d seq=%d, newseq=%d found at %d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq, i); - return 0; // Yes, it is! - } - } - // Some heuristic to decide when to drop packet or to restart everything - if (newseq > -(3 * MAXRTPPACKETSIN)) { - mp_msg(MSGT_NETWORK, MSGL_ERR, "Too Old packet (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); - return 0; // Yes, it is! - } - - mp_msg(MSGT_NETWORK, MSGL_ERR, "Underrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); - - rtp_cache_reset(seq); - goto feed; - } - - mp_msg(MSGT_NETWORK, MSGL_DBG4, "Out of Seq (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); - newseq = ( newseq + rtpbuf.first ) % MAXRTPPACKETSIN; - memcpy (rtpbuf.data[newseq], data, length); - rtpbuf.len[newseq] = length; - rtpbuf.seq[newseq] = seq; - - return 0; - -feed: - memcpy (buffer, data, length); - return length; -} - -// Get next packet in cache -// Look in cache to get first packet in sequence -static int rtp_get_next(int fd, char *buffer, int length) -{ - int i; - unsigned short nextseq; - - // If we have empty buffer we loop to fill it - for (i=0; i < MAXRTPPACKETSIN -3; i++) { - if (rtpbuf.len[rtpbuf.first] != 0) break; - - length = rtp_cache(fd, buffer, length) ; - - // returns on first packet in sequence - if (length > 0) { - //mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp [%d] %hu\n", i, rtpbuf.first); - return length; - } else if (length < 0) break; - - // Only if length == 0 loop continues! - } - - i = rtpbuf.first; - while (rtpbuf.len[i] == 0) { - mp_msg(MSGT_NETWORK, MSGL_ERR, "Lost packet %hu\n", rtpbuf.seq[i]); - i = ( 1 + i ) % MAXRTPPACKETSIN; - if (rtpbuf.first == i) break; - } - rtpbuf.first = i; - - // Copy next non empty packet from cache - mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp from cache [%d] %hu\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first]); - memcpy (buffer, rtpbuf.data[rtpbuf.first], rtpbuf.len[rtpbuf.first]); - length = rtpbuf.len[rtpbuf.first]; // can be zero? - - // Reset fisrt slot and go next in cache - rtpbuf.len[rtpbuf.first] = 0; - nextseq = rtpbuf.seq[rtpbuf.first]; - rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN; - rtpbuf.seq[rtpbuf.first] = nextseq + 1; - - return length; -} - - -// Read next rtp packet using cache -int read_rtp_from_server(int fd, char *buffer, int length) { - // Following test is ASSERT (i.e. uneuseful if code is correct) - if(buffer==NULL || length<STREAM_BUFFER_SIZE) { - mp_msg(MSGT_NETWORK, MSGL_ERR, "RTP buffer invalid; no data return from network\n"); - return 0; - } - - // loop just to skip empty packets - while ((length = rtp_get_next(fd, buffer, length)) == 0) { - mp_msg(MSGT_NETWORK, MSGL_ERR, "Got empty packet from RTP cache!?\n"); - } - - return(length); -} - -// Start listening on a UDP port. If multicast, join the group. -static int rtp_open_socket( URL_t *url ) { - int socket_server_fd, rxsockbufsz; - int err, err_len; - fd_set set; - struct sockaddr_in server_address; - struct ip_mreq mcast; - struct timeval tv; - struct hostent *hp; - - mp_msg(MSGT_NETWORK,MSGL_V,"Listening for traffic on %s:%d ...\n", url->hostname, url->port ); - - socket_server_fd = socket(AF_INET, SOCK_DGRAM, 0); -// fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); - if( socket_server_fd==-1 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create socket\n"); - return -1; - } - - if( isalpha(url->hostname[0]) ) { -#ifndef HAVE_WINSOCK2 - hp =(struct hostent*)gethostbyname( url->hostname ); - if( hp==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); - goto err_out; - } - memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr_list[0], hp->h_length ); -#else - server_address.sin_addr.s_addr = htonl(INADDR_ANY); -#endif - } else { -#ifndef HAVE_WINSOCK2 -#ifdef USE_ATON - inet_aton(url->hostname, &server_address.sin_addr); -#else - inet_pton(AF_INET, url->hostname, &server_address.sin_addr); -#endif -#else - server_address.sin_addr.s_addr = htonl(INADDR_ANY); -#endif - } - server_address.sin_family=AF_INET; - server_address.sin_port=htons(url->port); - - if( bind( socket_server_fd, (struct sockaddr*)&server_address, sizeof(server_address) )==-1 ) { -#ifndef HAVE_WINSOCK2 - if( errno!=EINPROGRESS ) { -#else - if( WSAGetLastError() != WSAEINPROGRESS ) { -#endif - mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server\n"); - goto err_out; - } - } - -#ifdef HAVE_WINSOCK2 - if (isalpha(url->hostname[0])) { - hp =(struct hostent*)gethostbyname( url->hostname ); - if( hp==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); - goto err_out; - } - memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr, hp->h_length ); - } else { - unsigned int addr = inet_addr(url->hostname); - memcpy( (void*)&server_address.sin_addr, (void*)&addr, sizeof(addr) ); - } -#endif - - // Increase the socket rx buffer size to maximum -- this is UDP - rxsockbufsz = 240 * 1024; - if( setsockopt( socket_server_fd, SOL_SOCKET, SO_RCVBUF, &rxsockbufsz, sizeof(rxsockbufsz))) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't set receive socket buffer size\n"); - } - - if((ntohl(server_address.sin_addr.s_addr) >> 28) == 0xe) { - mcast.imr_multiaddr.s_addr = server_address.sin_addr.s_addr; - //mcast.imr_interface.s_addr = inet_addr("10.1.1.2"); - mcast.imr_interface.s_addr = 0; - if( setsockopt( socket_server_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof(mcast))) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?)\n"); - goto err_out; - } - } - - tv.tv_sec = 0; - tv.tv_usec = (1 * 1000000); // 1 second timeout - FD_ZERO( &set ); - FD_SET( socket_server_fd, &set ); - err = select(socket_server_fd+1, &set, NULL, NULL, &tv); - if (err < 0) { - mp_msg(MSGT_NETWORK, MSGL_FATAL, "Select failed: %s\n", strerror(errno)); - goto err_out; - } - if (err == 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"Timeout! No data from host %s\n", url->hostname ); - goto err_out; - } - err_len = sizeof( err ); - getsockopt( socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len ); - if( err ) { - mp_msg(MSGT_NETWORK,MSGL_DBG2,"Socket error: %d\n", err ); - goto err_out; - } - return socket_server_fd; - -err_out: - closesocket(socket_server_fd); - return -1; -} - -static int rtp_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { - return read_rtp_from_server( fd, buffer, size ); -} - -static int rtp_streaming_start( stream_t *stream, int raw_udp ) { - streaming_ctrl_t *streaming_ctrl; - int fd; - - if( stream==NULL ) return -1; - streaming_ctrl = stream->streaming_ctrl; - fd = stream->fd; - - if( fd<0 ) { - fd = rtp_open_socket( (streaming_ctrl->url) ); - if( fd<0 ) return -1; - stream->fd = fd; - } - - if(raw_udp) - streaming_ctrl->streaming_read = nop_streaming_read; - else - streaming_ctrl->streaming_read = rtp_streaming_read; - streaming_ctrl->streaming_seek = nop_streaming_seek; - streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes - streaming_ctrl->buffering = 0; - streaming_ctrl->status = streaming_playing_e; - return 0; -} - - -static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) { - static char buf[1600]; - unsigned int intP; - char* charP = (char*) &intP; - int headerSize; - int lengthPacket; - lengthPacket=recv(fd,buf,1590,0); - if (lengthPacket<0) - mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: socket read error\n"); - else if (lengthPacket<12) - mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: packet too small (%d) to be an rtp frame (>12bytes)\n", lengthPacket); - if(lengthPacket<12) { - *lengthData = 0; - return 0; - } - rh->b.v = (unsigned int) ((buf[0]>>6)&0x03); - rh->b.p = (unsigned int) ((buf[0]>>5)&0x01); - rh->b.x = (unsigned int) ((buf[0]>>4)&0x01); - rh->b.cc = (unsigned int) ((buf[0]>>0)&0x0f); - rh->b.m = (unsigned int) ((buf[1]>>7)&0x01); - rh->b.pt = (unsigned int) ((buf[1]>>0)&0x7f); - intP = 0; - memcpy(charP+2,&buf[2],2); - rh->b.sequence = ntohl(intP); - intP = 0; - memcpy(charP,&buf[4],4); - rh->timestamp = ntohl(intP); - - headerSize = 12 + 4*rh->b.cc; /* in bytes */ - - *lengthData = lengthPacket - headerSize; - *data = (char*) buf + headerSize; - - // mp_msg(MSGT_NETWORK,MSGL_DBG2,"Reading rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",rh->b.v,rh->b.p,rh->b.x,rh->b.cc,rh->b.m,rh->b.pt,rh->b.sequence,rh->timestamp,lengthPacket); - - return(0); -} - - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - URL_t *url; - int udp = 0; - - mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_RTP, URL: %s\n", stream->url); - stream->streaming_ctrl = streaming_ctrl_new(); - if( stream->streaming_ctrl==NULL ) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - - if( url->port==0 ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"You must enter a port number for RTP and UDP streams!\n"); - goto fail; - } - if(!strncmp(stream->url, "udp", 3)) - udp = 1; - - if(rtp_streaming_start(stream, udp) < 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp_streaming_start(rtp) failed\n"); - goto fail; - } - - stream->type = STREAMTYPE_STREAM; - fixup_network_stream_cache(stream); - return STREAM_OK; - -fail: - streaming_ctrl_free( stream->streaming_ctrl ); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; -} - - -stream_info_t stream_info_rtp_udp = { - "mpeg rtp and upd streaming", - "rtp and udp", - "Dave Chapman", - "native rtp support", - open_s, - {"rtp", "udp", NULL}, - NULL, - 0 // Urls are an option string -}; - -
--- a/libmpdemux/rtp.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* Imported from the dvbstream project - * - * Modified for use with MPlayer, for details see the changelog at - * http://svn.mplayerhq.hu/mplayer/trunk/ - * $Id$ - */ - -#ifndef _RTP_H -#define _RTP_H - -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <sys/socket.h> -#else -#include <winsock2.h> -#endif - -struct rtpbits { - unsigned int v:2; /* version: 2 */ - unsigned int p:1; /* is there padding appended: 0 */ - unsigned int x:1; /* number of extension headers: 0 */ - unsigned int cc:4; /* number of CSRC identifiers: 0 */ - unsigned int m:1; /* marker: 0 */ - unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */ - unsigned int sequence:16; /* sequence number: random */ -}; - -struct rtpheader { /* in network byte order */ - struct rtpbits b; - int timestamp; /* start: random */ - int ssrc; /* random */ -}; - - -static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData); -int read_rtp_from_server(int fd, char *buffer, int length); - -#endif
--- a/libmpdemux/stream.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,434 +0,0 @@ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <sys/types.h> -#include <sys/stat.h> -#ifndef __MINGW32__ -#include <sys/ioctl.h> -#include <sys/wait.h> -#endif -#include <fcntl.h> -#include <signal.h> -#include <strings.h> - -#include "config.h" - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#else -#include <winsock2.h> -#endif - -#include "mp_msg.h" -#include "help_mp.h" -#include "osdep/shmem.h" - -#include "stream.h" -#include "demuxer.h" - -#include "m_option.h" -#include "m_struct.h" - - -void cache_uninit(stream_t *s); // defined in cache2.c - -//#include "vcd_read_bincue.h" - -#ifdef HAVE_VCD -extern stream_info_t stream_info_vcd; -#endif -#ifdef HAVE_CDDA -extern stream_info_t stream_info_cdda; -#endif -#ifdef MPLAYER_NETWORK -extern stream_info_t stream_info_netstream; -extern stream_info_t stream_info_pnm; -extern stream_info_t stream_info_asf; -extern stream_info_t stream_info_rtsp; -extern stream_info_t stream_info_rtp_udp; -extern stream_info_t stream_info_http1; -extern stream_info_t stream_info_http2; -#endif -#ifdef HAS_DVBIN_SUPPORT -extern stream_info_t stream_info_dvb; -#endif -#ifdef HAVE_PVR -extern stream_info_t stream_info_pvr; -#endif -#ifdef HAVE_FTP -extern stream_info_t stream_info_ftp; -#endif -#ifdef HAVE_VSTREAM -extern stream_info_t stream_info_vstream; -#endif -#ifdef USE_DVDNAV -extern stream_info_t stream_info_dvdnav; -#endif -#ifdef LIBSMBCLIENT -extern stream_info_t stream_info_smb; -#endif -#ifdef STREAMING_LIVE555 -extern stream_info_t stream_info_sdp; -extern stream_info_t stream_info_rtsp_sip; -#endif - -extern stream_info_t stream_info_cue; -extern stream_info_t stream_info_null; -extern stream_info_t stream_info_file; -#ifdef HAVE_DVD -extern stream_info_t stream_info_dvd; -#endif - -stream_info_t* auto_open_streams[] = { -#ifdef HAVE_VCD - &stream_info_vcd, -#endif -#ifdef HAVE_CDDA - &stream_info_cdda, -#endif -#ifdef MPLAYER_NETWORK - &stream_info_netstream, - &stream_info_http1, - &stream_info_asf, - &stream_info_pnm, - &stream_info_rtsp, -#ifdef STREAMING_LIVE555 - &stream_info_sdp, - &stream_info_rtsp_sip, -#endif - &stream_info_rtp_udp, - &stream_info_http2, -#endif -#ifdef HAS_DVBIN_SUPPORT - &stream_info_dvb, -#endif -#ifdef HAVE_PVR - &stream_info_pvr, -#endif -#ifdef HAVE_FTP - &stream_info_ftp, -#endif -#ifdef HAVE_VSTREAM - &stream_info_vstream, -#endif -#ifdef LIBSMBCLIENT - &stream_info_smb, -#endif - &stream_info_cue, -#ifdef HAVE_DVD - &stream_info_dvd, -#endif -#ifdef USE_DVDNAV - &stream_info_dvdnav, -#endif - - &stream_info_null, - &stream_info_file, - NULL -}; - -stream_t* open_stream_plugin(stream_info_t* sinfo,char* filename,int mode, - char** options, int* file_format, int* ret) { - void* arg = NULL; - stream_t* s; - m_struct_t* desc = (m_struct_t*)sinfo->opts; - - // Parse options - if(desc) { - arg = m_struct_alloc(desc); - if(sinfo->opts_url) { - m_option_t url_opt = - { "stream url", arg , CONF_TYPE_CUSTOM_URL, 0, 0 ,0, sinfo->opts }; - if(m_option_parse(&url_opt,"stream url",filename,arg,M_CONFIG_FILE) < 0) { - mp_msg(MSGT_OPEN,MSGL_ERR, "URL parsing failed on url %s\n",filename); - m_struct_free(desc,arg); - return NULL; - } - } - if(options) { - int i; - for(i = 0 ; options[i] != NULL ; i += 2) { - mp_msg(MSGT_OPEN,MSGL_DBG2, "Set stream arg %s=%s\n", - options[i],options[i+1]); - if(!m_struct_set(desc,arg,options[i],options[i+1])) - mp_msg(MSGT_OPEN,MSGL_WARN, "Failed to set stream option %s=%s\n", - options[i],options[i+1]); - } - } - } - s = new_stream(-2,-2); - s->url=strdup(filename); - s->flags |= mode; - *ret = sinfo->open(s,mode,arg,file_format); - if((*ret) != STREAM_OK) { - free(s->url); - free(s); - return NULL; - } - if(s->type <= -2) - mp_msg(MSGT_OPEN,MSGL_WARN, "Warning streams need a type !!!!\n"); - if(s->flags & STREAM_SEEK && !s->seek) - s->flags &= ~STREAM_SEEK; - if(s->seek && !(s->flags & STREAM_SEEK)) - s->flags |= STREAM_SEEK; - - - mp_msg(MSGT_OPEN,MSGL_V, "STREAM: [%s] %s\n",sinfo->name,filename); - mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Description: %s\n",sinfo->info); - mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Author: %s\n", sinfo->author); - mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Comment: %s\n", sinfo->comment); - - return s; -} - - -stream_t* open_stream_full(char* filename,int mode, char** options, int* file_format) { - int i,j,l,r; - stream_info_t* sinfo; - stream_t* s; - - for(i = 0 ; auto_open_streams[i] ; i++) { - sinfo = auto_open_streams[i]; - if(!sinfo->protocols) { - mp_msg(MSGT_OPEN,MSGL_WARN, "Stream type %s has protocols == NULL, it's a bug\n", sinfo->name); - continue; - } - for(j = 0 ; sinfo->protocols[j] ; j++) { - l = strlen(sinfo->protocols[j]); - // l == 0 => Don't do protocol matching (ie network and filenames) - if((l == 0) || ((strncmp(sinfo->protocols[j],filename,l) == 0) && - (strncmp("://",filename+l,3) == 0))) { - *file_format = DEMUXER_TYPE_UNKNOWN; - s = open_stream_plugin(sinfo,filename,mode,options,file_format,&r); - if(s) return s; - if(r != STREAM_UNSUPORTED) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_FailedToOpen,filename); - return NULL; - } - break; - } - } - } - - mp_msg(MSGT_OPEN,MSGL_ERR, "No stream found to handle url %s\n",filename); - return NULL; -} - -//=================== STREAMER ========================= - -int stream_fill_buffer(stream_t *s){ - int len; - if (/*s->fd == NULL ||*/ s->eof) { s->buf_pos = s->buf_len = 0; return 0; } - switch(s->type){ - case STREAMTYPE_STREAM: -#ifdef MPLAYER_NETWORK - if( s->streaming_ctrl!=NULL ) { - len=s->streaming_ctrl->streaming_read(s->fd,s->buffer,STREAM_BUFFER_SIZE, s->streaming_ctrl);break; - } else { - len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break; - } -#else - len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break; -#endif - case STREAMTYPE_DS: - len = demux_read_data((demux_stream_t*)s->priv,s->buffer,STREAM_BUFFER_SIZE); - break; - - - default: - len= s->fill_buffer ? s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE) : 0; - } - if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; } - s->buf_pos=0; - s->buf_len=len; - s->pos+=len; -// printf("[%d]",len);fflush(stdout); - return len; -} - -int stream_seek_long(stream_t *s,off_t pos){ -off_t newpos=0; - -// if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos); - - s->buf_pos=s->buf_len=0; - - switch(s->type){ - case STREAMTYPE_STREAM: -#ifdef _LARGEFILE_SOURCE - newpos=pos&(~((long long)STREAM_BUFFER_SIZE-1));break; -#else - newpos=pos&(~(STREAM_BUFFER_SIZE-1));break; -#endif - default: - // Round on sector size - if(s->sector_size) - newpos=(pos/s->sector_size)*s->sector_size; - else { // Otherwise on the buffer size -#ifdef _LARGEFILE_SOURCE - newpos=pos&(~((long long)STREAM_BUFFER_SIZE-1));break; -#else - newpos=pos&(~(STREAM_BUFFER_SIZE-1));break; -#endif - } - break; - } - -if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ){ - mp_msg(MSGT_STREAM,MSGL_DBG3, "s->pos=%"PRIX64" newpos=%"PRIX64" new_bufpos=%"PRIX64" buflen=%X \n", - (int64_t)s->pos,(int64_t)newpos,(int64_t)pos,s->buf_len); -} - pos-=newpos; - -if(newpos==0 || newpos!=s->pos){ - switch(s->type){ - case STREAMTYPE_STREAM: - //s->pos=newpos; // real seek - // Some streaming protocol allow to seek backward and forward - // A function call that return -1 can tell that the protocol - // doesn't support seeking. -#ifdef MPLAYER_NETWORK - if(s->seek) { // new stream seek is much cleaner than streaming_ctrl one - if(!s->seek(s,newpos)) { - mp_msg(MSGT_STREAM,MSGL_ERR, "Seek failed\n"); - return 0; - } - break; - } - - if( s->streaming_ctrl!=NULL && s->streaming_ctrl->streaming_seek ) { - if( s->streaming_ctrl->streaming_seek( s->fd, pos, s->streaming_ctrl )<0 ) { - mp_msg(MSGT_STREAM,MSGL_INFO,"Stream not seekable!\n"); - return 1; - } - } -#else - if(newpos<s->pos){ - mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n"); - return 1; - } - while(s->pos<newpos){ - if(stream_fill_buffer(s)<=0) break; // EOF - } -#endif - break; - default: - // This should at the beginning as soon as all streams are converted - if(!s->seek) - return 0; - // Now seek - if(!s->seek(s,newpos)) { - mp_msg(MSGT_STREAM,MSGL_ERR, "Seek failed\n"); - return 0; - } - } -// putchar('.');fflush(stdout); -//} else { -// putchar('%');fflush(stdout); -} - -while(stream_fill_buffer(s) > 0 && pos >= 0) { - if(pos<=s->buf_len){ - s->buf_pos=pos; // byte position in sector - return 1; - } - pos -= s->buf_len; -} - -// if(pos==s->buf_len) printf("XXX Seek to last byte of file -> EOF\n"); - - mp_msg(MSGT_STREAM,MSGL_V,"stream_seek: WARNING! Can't seek to 0x%"PRIX64" !\n",(int64_t)(pos+newpos)); - return 0; -} - - -void stream_reset(stream_t *s){ - if(s->eof){ - s->pos=0; //ftell(f); -// s->buf_pos=s->buf_len=0; - s->eof=0; - } - if(s->control) s->control(s,STREAM_CTRL_RESET,NULL); - //stream_seek(s,0); -} - -int stream_control(stream_t *s, int cmd, void *arg){ - if(!s->control) return STREAM_UNSUPORTED; - return s->control(s, cmd, arg); -} - -stream_t* new_memory_stream(unsigned char* data,int len){ - stream_t *s; - - if(len < 0) - return NULL; - s=malloc(sizeof(stream_t)+len); - memset(s,0,sizeof(stream_t)); - s->fd=-1; - s->type=STREAMTYPE_MEMORY; - s->buf_pos=0; s->buf_len=len; - s->start_pos=0; s->end_pos=len; - stream_reset(s); - s->pos=len; - memcpy(s->buffer,data,len); - return s; -} - -stream_t* new_stream(int fd,int type){ - stream_t *s=malloc(sizeof(stream_t)); - if(s==NULL) return NULL; - memset(s,0,sizeof(stream_t)); - -#ifdef HAVE_WINSOCK2 - { - WSADATA wsdata; - int temp = WSAStartup(0x0202, &wsdata); // there might be a better place for this (-> later) - mp_msg(MSGT_STREAM,MSGL_V,"WINSOCK2 init: %i\n", temp); - } -#endif - - s->fd=fd; - s->type=type; - s->buf_pos=s->buf_len=0; - s->start_pos=s->end_pos=0; - s->priv=NULL; - s->url=NULL; - s->cache_pid=0; - stream_reset(s); - return s; -} - -void free_stream(stream_t *s){ -// printf("\n*** free_stream() called ***\n"); -#ifdef USE_STREAM_CACHE - if(s->cache_pid) { - cache_uninit(s); - } -#endif - if(s->close) s->close(s); - if(s->fd>0){ - /* on unix we define closesocket to close - on windows however we have to distinguish between - network socket and file */ - if(s->url && strstr(s->url,"://")) - closesocket(s->fd); - else close(s->fd); - } -#ifdef HAVE_WINSOCK2 - mp_msg(MSGT_STREAM,MSGL_V,"WINSOCK2 uninit\n"); - WSACleanup(); // there might be a better place for this (-> later) -#endif - // Disabled atm, i don't like that. s->priv can be anything after all - // streams should destroy their priv on close - //if(s->priv) free(s->priv); - if(s->url) free(s->url); - free(s); -} - -stream_t* new_ds_stream(demux_stream_t *ds) { - stream_t* s = new_stream(-1,STREAMTYPE_DS); - s->priv = ds; - return s; -}
--- a/libmpdemux/stream.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,301 +0,0 @@ -#ifndef __STREAM_H -#define __STREAM_H - -#include "mp_msg.h" -#include <string.h> -#include <inttypes.h> -#include <sys/types.h> - -#define STREAMTYPE_DUMMY -1 // for placeholders, when the actual reading is handled in the demuxer -#define STREAMTYPE_FILE 0 // read from seekable file -#define STREAMTYPE_VCD 1 // raw mode-2 CDROM reading, 2324 bytes/sector -#define STREAMTYPE_STREAM 2 // same as FILE but no seeking (for net/stdin) -#define STREAMTYPE_DVD 3 // libdvdread -#define STREAMTYPE_MEMORY 4 // read data from memory area -#define STREAMTYPE_PLAYLIST 6 // FIXME!!! same as STREAMTYPE_FILE now -#define STREAMTYPE_DS 8 // read from a demuxer stream -#define STREAMTYPE_DVDNAV 9 // we cannot safely "seek" in this... -#define STREAMTYPE_CDDA 10 // raw audio CD reader -#define STREAMTYPE_SMB 11 // smb:// url, using libsmbclient (samba) -#define STREAMTYPE_VCDBINCUE 12 // vcd directly from bin/cue files -#define STREAMTYPE_DVB 13 -#define STREAMTYPE_VSTREAM 14 -#define STREAMTYPE_SDP 15 -#define STREAMTYPE_PVR 16 - -#define STREAM_BUFFER_SIZE 2048 - -#define VCD_SECTOR_SIZE 2352 -#define VCD_SECTOR_OFFS 24 -#define VCD_SECTOR_DATA 2324 - -/// atm it will always use mode == STREAM_READ -/// streams that use the new api should check the mode at open -#define STREAM_READ 0 -#define STREAM_WRITE 1 -/// Seek flags, if not mannualy set and s->seek isn't NULL -/// STREAM_SEEK is automaticly set -#define STREAM_SEEK_BW 2 -#define STREAM_SEEK_FW 4 -#define STREAM_SEEK (STREAM_SEEK_BW|STREAM_SEEK_FW) - -//////////// Open return code -/// This can't open the requested protocol (used by stream wich have a -/// * protocol when they don't know the requested protocol) -#define STREAM_UNSUPORTED -1 -#define STREAM_ERROR 0 -#define STREAM_OK 1 - -#define MAX_STREAM_PROTOCOLS 10 - -#define STREAM_CTRL_RESET 0 -#define STREAM_CTRL_GET_TIME_LENGTH 1 - -#ifdef MPLAYER_NETWORK -#include "network.h" -#endif - -struct stream_st; -typedef struct stream_info_st { - const char *info; - const char *name; - const char *author; - const char *comment; - /// mode isn't used atm (ie always READ) but it shouldn't be ignored - /// opts is at least in it's defaults settings and may have been - /// altered by url parsing if enabled and the options string parsing. - int (*open)(struct stream_st* st, int mode, void* opts, int* file_format); - char* protocols[MAX_STREAM_PROTOCOLS]; - void* opts; - int opts_url; /* If this is 1 we will parse the url as an option string - * too. Otherwise options are only parsed from the - * options string given to open_stream_plugin */ -} stream_info_t; - -typedef struct stream_st { - // Read - int (*fill_buffer)(struct stream_st *s, char* buffer, int max_len); - // Write - int (*write_buffer)(struct stream_st *s, char* buffer, int len); - // Seek - int (*seek)(struct stream_st *s,off_t pos); - // Control - // Will be later used to let streams like dvd and cdda report - // their structure (ie tracks, chapters, etc) - int (*control)(struct stream_st *s,int cmd,void* arg); - // Close - void (*close)(struct stream_st *s); - - int fd; // file descriptor, see man open(2) - int type; // see STREAMTYPE_* - int flags; - int sector_size; // sector size (seek will be aligned on this size if non 0) - unsigned int buf_pos,buf_len; - off_t pos,start_pos,end_pos; - int eof; - unsigned int cache_pid; - void* cache_data; - void* priv; // used for DVD, TV, RTSP etc - char* url; // strdup() of filename/url -#ifdef MPLAYER_NETWORK - streaming_ctrl_t *streaming_ctrl; -#endif - unsigned char buffer[STREAM_BUFFER_SIZE>VCD_SECTOR_SIZE?STREAM_BUFFER_SIZE:VCD_SECTOR_SIZE]; -} stream_t; - -#ifdef USE_STREAM_CACHE -int stream_enable_cache(stream_t *stream,int size,int min,int prefill); -int cache_stream_fill_buffer(stream_t *s); -int cache_stream_seek_long(stream_t *s,off_t pos); -#else -// no cache, define wrappers: -#define cache_stream_fill_buffer(x) stream_fill_buffer(x) -#define cache_stream_seek_long(x,y) stream_seek_long(x,y) -#define stream_enable_cache(x,y,z,w) 1 -#endif -void fixup_network_stream_cache(stream_t *stream); - -inline static int stream_read_char(stream_t *s){ - return (s->buf_pos<s->buf_len)?s->buffer[s->buf_pos++]: - (cache_stream_fill_buffer(s)?s->buffer[s->buf_pos++]:-256); -// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++]; -// stream_fill_buffer(s); -// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++]; -// return 0; // EOF -} - -inline static unsigned int stream_read_word(stream_t *s){ - int x,y; - x=stream_read_char(s); - y=stream_read_char(s); - return (x<<8)|y; -} - -inline static unsigned int stream_read_dword(stream_t *s){ - unsigned int y; - y=stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - return y; -} - -#define stream_read_fourcc stream_read_dword_le - -inline static unsigned int stream_read_word_le(stream_t *s){ - int x,y; - x=stream_read_char(s); - y=stream_read_char(s); - return (y<<8)|x; -} - -inline static unsigned int stream_read_dword_le(stream_t *s){ - unsigned int y; - y=stream_read_char(s); - y|=stream_read_char(s)<<8; - y|=stream_read_char(s)<<16; - y|=stream_read_char(s)<<24; - return y; -} - -inline static uint64_t stream_read_qword(stream_t *s){ - uint64_t y; - y = stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - return y; -} - -inline static uint64_t stream_read_qword_le(stream_t *s){ - uint64_t y; - y = stream_read_char(s); - y|=stream_read_char(s)<<8; - y|=stream_read_char(s)<<16; - y|=stream_read_char(s)<<24; - y|=(uint64_t)stream_read_char(s)<<32; - y|=(uint64_t)stream_read_char(s)<<40; - y|=(uint64_t)stream_read_char(s)<<48; - y|=(uint64_t)stream_read_char(s)<<56; - return y; -} - -inline static unsigned int stream_read_int24(stream_t *s){ - unsigned int y; - y = stream_read_char(s); - y=(y<<8)|stream_read_char(s); - y=(y<<8)|stream_read_char(s); - return y; -} - -inline static int stream_read(stream_t *s,char* mem,int total){ - int len=total; - while(len>0){ - int x; - x=s->buf_len-s->buf_pos; - if(x==0){ - if(!cache_stream_fill_buffer(s)) return total-len; // EOF - x=s->buf_len-s->buf_pos; - } - if(s->buf_pos>s->buf_len) mp_msg(MSGT_DEMUX, MSGL_WARN, "stream_read: WARNING! s->buf_pos>s->buf_len\n"); - if(x>len) x=len; - memcpy(mem,&s->buffer[s->buf_pos],x); - s->buf_pos+=x; mem+=x; len-=x; - } - return total; -} - -inline static unsigned char* stream_read_line(stream_t *s,unsigned char* mem, int max) { - int len; - unsigned char* end,*ptr = mem;; - do { - len = s->buf_len-s->buf_pos; - // try to fill the buffer - if(len <= 0 && - (!cache_stream_fill_buffer(s) || - (len = s->buf_len-s->buf_pos) <= 0)) break; - end = (unsigned char*) memchr((void*)(s->buffer+s->buf_pos),'\n',len); - if(end) len = end - (s->buffer+s->buf_pos) + 1; - if(len > 0 && max > 1) { - int l = len > max-1 ? max-1 : len; - memcpy(ptr,s->buffer+s->buf_pos,l); - max -= l; - ptr += l; - } - s->buf_pos += len; - } while(!end); - if(s->eof && ptr == mem) return NULL; - if(max > 0) ptr[0] = 0; - return mem; -} - - -inline static int stream_eof(stream_t *s){ - return s->eof; -} - -inline static off_t stream_tell(stream_t *s){ - return s->pos+s->buf_pos-s->buf_len; -} - -inline static int stream_seek(stream_t *s,off_t pos){ - - mp_dbg(MSGT_DEMUX, MSGL_DBG3, "seek to 0x%qX\n",(long long)pos); - - if(pos<s->pos){ - off_t x=pos-(s->pos-s->buf_len); - if(x>=0){ - s->buf_pos=x; -// putchar('*');fflush(stdout); - return 1; - } - } - - return cache_stream_seek_long(s,pos); -} - -inline static int stream_skip(stream_t *s,off_t len){ - if( (len<0 && (s->flags & STREAM_SEEK_BW)) || (len>2*STREAM_BUFFER_SIZE && (s->flags & STREAM_SEEK_FW)) ) { - // negative or big skip! - return stream_seek(s,stream_tell(s)+len); - } - while(len>0){ - int x=s->buf_len-s->buf_pos; - if(x==0){ - if(!cache_stream_fill_buffer(s)) return 0; // EOF - x=s->buf_len-s->buf_pos; - } - if(x>len) x=len; - //memcpy(mem,&s->buf[s->buf_pos],x); - s->buf_pos+=x; len-=x; - } - return 1; -} - -void stream_reset(stream_t *s); -int stream_control(stream_t *s, int cmd, void *arg); -stream_t* new_stream(int fd,int type); -void free_stream(stream_t *s); -stream_t* new_memory_stream(unsigned char* data,int len); -stream_t* open_stream(char* filename,char** options,int* file_format); -stream_t* open_stream_full(char* filename,int mode, char** options, int* file_format); - -extern int dvd_title; -extern int dvd_chapter; -extern int dvd_last_chapter; -extern int dvd_angle; - -extern char * audio_stream; - -typedef struct { - int id; // 0 - 31 mpeg; 128 - 159 ac3; 160 - 191 pcm - int language; - int type; - int channels; -} stream_language_t; - -#endif // __STREAM_H
--- a/libmpdemux/stream_dvd.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,851 +0,0 @@ - - -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include "config.h" -#include "mp_msg.h" -#include "help_mp.h" - -#ifdef __FreeBSD__ -#include <sys/cdrio.h> -#endif - -#define FIRST_AC3_AID 128 -#define FIRST_DTS_AID 136 -#define FIRST_MPG_AID 0 -#define FIRST_PCM_AID 160 - -#include "stream.h" -#include "m_option.h" -#include "m_struct.h" - -#include "stream_dvd.h" - -/// We keep these 2 for the gui atm, but they will be removed. -extern int dvd_title; -extern int dvd_chapter; -extern int dvd_last_chapter; -extern char* dvd_device; -int dvd_angle=1; - -#ifdef USE_DVDREAD -#define LIBDVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro)) -/* - * Try to autodetect the libdvd-0.9.0 library - * (0.9.0 removed the <dvdread/dvd_udf.h> header, and moved the two defines - * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to - * <dvdread/dvd_reader.h>) - */ -#ifndef DVDREAD_VERSION -#if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN) -#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,9,0) -#else -#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,8,0) -#endif -#endif - -char * dvd_audio_stream_types[8] = { "ac3","unknown","mpeg1","mpeg2ext","lpcm","unknown","dts" }; -char * dvd_audio_stream_channels[6] = { "mono", "stereo", "unknown", "unknown", "5.1/6.1", "5.1" }; -#endif /* #ifdef USE_DVDREAD */ - - -static struct stream_priv_s { - int title; -} stream_priv_dflts = { - 1 -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - { "hostname", ST_OFF(title), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "dvd", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -int dvd_parse_chapter_range(m_option_t *conf, const char *range) { - const char *s; - char *t; - if (!range) - return M_OPT_MISSING_PARAM; - s = range; - dvd_chapter = 1; - dvd_last_chapter = 0; - if(*range && isdigit(*range)) { - dvd_chapter = strtol(range, &s, 10); - if(range == s) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); - return M_OPT_INVALID; - } - } - if(*s == 0) - return 0; - else if(*s != '-') { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); - return M_OPT_INVALID; - } - ++s; - if(*s == 0) - return 0; - if(! isdigit(*s)) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); - return M_OPT_INVALID; - } - dvd_last_chapter = strtol(s, &t, 10); - if (s == t || *t) { - mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); - return M_OPT_INVALID; - } - return 0; -} - -#ifdef USE_DVDREAD -int dvd_chapter_from_cell(dvd_priv_t* dvd,int title,int cell) -{ - pgc_t * cur_pgc; - ptt_info_t* ptt; - int chapter = cell; - int pgc_id,pgn; - if(title < 0 || cell < 0){ - return 0; - } - /* for most DVD's chapter == cell */ - /* but there are more complecated cases... */ - if(chapter >= dvd->vmg_file->tt_srpt->title[title].nr_of_ptts) { - chapter = dvd->vmg_file->tt_srpt->title[title].nr_of_ptts-1; - } - title = dvd->tt_srpt->title[title].vts_ttn-1; - ptt = dvd->vts_file->vts_ptt_srpt->title[title].ptt; - while(chapter >= 0) { - pgc_id = ptt[chapter].pgcn; - pgn = ptt[chapter].pgn; - cur_pgc = dvd->vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; - if(cell >= cur_pgc->program_map[pgn-1]-1) { - return chapter; - } - --chapter; - } - /* didn't find a chapter ??? */ - return chapter; -} - -int dvd_aid_from_lang(stream_t *stream, unsigned char* lang) { - dvd_priv_t *d=stream->priv; - int code,i; - if(lang) { - while(strlen(lang)>=2) { - code=lang[1]|(lang[0]<<8); - for(i=0;i<d->nr_of_channels;i++) { - if(d->audio_streams[i].language==code) { - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDaudioChannel, - d->audio_streams[i].id, lang[0],lang[1]); - return d->audio_streams[i].id; - } - //printf("%X != %X (%c%c)\n",code,d->audio_streams[i].language,lang[0],lang[1]); - } - lang+=2; while (lang[0]==',' || lang[0]==' ') ++lang; - } - mp_msg(MSGT_OPEN,MSGL_WARN,MSGTR_DVDnoMatchingAudio); - } - return -1; -} - -int dvd_number_of_subs(stream_t *stream) { - dvd_priv_t *d; - if (!stream) return -1; - d = stream->priv; - if (!d) return -1; - return d->nr_of_subtitles; -} - -int dvd_lang_from_sid(stream_t *stream, int id) { - dvd_priv_t *d; - if (!stream) return 0; - d = stream->priv; - if (!d) return 0; - if (id >= d->nr_of_subtitles) return 0; - return d->subtitles[id].language; -} - -int dvd_sid_from_lang(stream_t *stream, unsigned char* lang) { - dvd_priv_t *d=stream->priv; - int code,i; - while(lang && strlen(lang)>=2) { - code=lang[1]|(lang[0]<<8); - for(i=0;i<d->nr_of_subtitles;i++) { - if(d->subtitles[i].language==code) { - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDsubtitleChannel, i, lang[0],lang[1]); - return i; - } - } - lang+=2; - while (lang[0]==',' || lang[0]==' ') ++lang; - } - mp_msg(MSGT_OPEN,MSGL_WARN,MSGTR_DVDnoMatchingSubtitle); - return -1; -} - -static int dvd_next_cell(dvd_priv_t *d) { - int next_cell=d->cur_cell; - - mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next1=0x%X \n",next_cell); - if( d->cur_pgc->cell_playback[ next_cell ].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { - while(next_cell<d->last_cell) { - if( d->cur_pgc->cell_playback[next_cell].block_mode == BLOCK_MODE_LAST_CELL ) - break; - ++next_cell; - } - } - mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next2=0x%X \n",next_cell); - - ++next_cell; - if(next_cell>=d->last_cell) - return -1; // EOF - if(d->cur_pgc->cell_playback[next_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { - next_cell+=dvd_angle; - if(next_cell>=d->last_cell) - return -1; // EOF - } - mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next3=0x%X \n",next_cell); - return next_cell; -} - -int dvd_read_sector(dvd_priv_t *d,unsigned char* data) { - int len; - - if(d->packs_left==0) { - /** - * 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. - * - * Otherwise, we set our next address past the end of this cell to - * force the code above to go to the next cell in the program. - */ - if(d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) { - d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); - mp_msg(MSGT_DVD,MSGL_DBG2, "Navi new pos=0x%X \n",d->cur_pack); - } else { - // end of cell! find next cell! - mp_msg(MSGT_DVD,MSGL_V, "--- END OF CELL !!! ---\n"); - d->cur_pack=d->cell_last_pack+1; - } - } - -read_next: - if(d->cur_pack>d->cell_last_pack) { - // end of cell! - int next=dvd_next_cell(d); - if(next>=0) { - d->cur_cell=next; - // if( d->cur_pgc->cell_playback[d->cur_cell].block_type - // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle; - d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; - d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; - mp_msg(MSGT_DVD,MSGL_V, "DVD next cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); - } else - return -1; // EOF - } - - len = DVDReadBlocks(d->title, d->cur_pack, 1, data); - if(!len) return -1; //error - - if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF && - data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF) { - // found a Navi packet!!! -#if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0) - navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ])); -#else - navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t)); -#endif - if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ) { - mp_msg(MSGT_DVD,MSGL_V, "Invalid NAVI packet! lba=0x%X navi=0x%X \n", - d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn); - } else { - // process! - d->packs_left = d->dsi_pack.dsi_gi.vobu_ea; - mp_msg(MSGT_DVD,MSGL_DBG2, "Found NAVI packet! lba=0x%X len=%d \n",d->cur_pack,d->packs_left); - //navPrint_DSI(&d->dsi_pack); - mp_msg(MSGT_DVD,MSGL_DBG3,"\r### CELL %d: Navi: %d/%d IFO: %d/%d \n",d->cur_cell, - d->dsi_pack.dsi_gi.vobu_c_idn,d->dsi_pack.dsi_gi.vobu_vob_idn, - d->cur_pgc->cell_position[d->cur_cell].cell_nr, - d->cur_pgc->cell_position[d->cur_cell].vob_id_nr); - - if(d->angle_seek) { - int i,skip=0; -#if defined(__GNUC__) && ( defined(__sparc__) || defined(hpux) ) - // workaround for a bug in the sparc/hpux version of gcc 2.95.X ... 3.2, - // it generates incorrect code for unaligned access to a packed - // structure member, resulting in an mplayer crash with a SIGBUS - // signal. - // - // See also gcc problem report PR c/7847: - // http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=view+audit-trail&pr=7847 - for(i=0;i<9;i++) { // check if all values zero: - typeof(d->dsi_pack.sml_agli.data[i].address) tmp_addr; - memcpy(&tmp_addr,&d->dsi_pack.sml_agli.data[i].address,sizeof(tmp_addr)); - if((skip=tmp_addr)!=0) break; - } -#else - for(i=0;i<9;i++) // check if all values zero: - if((skip=d->dsi_pack.sml_agli.data[i].address)!=0) break; -#endif - if(skip) { - // sml_agli table has valid data (at least one non-zero): - d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ - d->dsi_pack.sml_agli.data[dvd_angle].address; - d->angle_seek=0; - mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced using sml_agli map! new_lba=0x%X \n",d->cur_pack); - } else { - // check if we're in the right cell, jump otherwise: - if( (d->dsi_pack.dsi_gi.vobu_c_idn==d->cur_pgc->cell_position[d->cur_cell].cell_nr) && - (d->dsi_pack.dsi_gi.vobu_vob_idn==d->cur_pgc->cell_position[d->cur_cell].vob_id_nr) ){ - d->angle_seek=0; - mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced by cell/vob IDN search! \n"); - } else { - // wrong angle, skip this vobu: - d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ - d->dsi_pack.dsi_gi.vobu_ea; - d->angle_seek=2; // DEBUG - } - } - } - } - ++d->cur_pack; - goto read_next; - } - - ++d->cur_pack; - if(d->packs_left>=0) --d->packs_left; - - if(d->angle_seek) { - if(d->angle_seek==2) mp_msg(MSGT_DVD,MSGL_V, "!!! warning! reading packet while angle_seek !!!\n"); - goto read_next; // searching for Navi packet - } - - return d->cur_pack-1; -} - -void dvd_seek(dvd_priv_t *d,int pos) { - d->packs_left=-1; - d->cur_pack=pos; - - // check if we stay in current cell (speedup things, and avoid angle skip) - if(d->cur_pack>d->cell_last_pack || - d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector) { - - // ok, cell change, find the right cell! - d->cur_cell=0; - if(d->cur_pgc->cell_playback[d->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) - d->cur_cell+=dvd_angle; - - while(1) { - int next; - d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; - if(d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector) { - d->cur_pack=d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; - break; - } - if(d->cur_pack<=d->cell_last_pack) break; // ok, we find it! :) - next=dvd_next_cell(d); - if(next<0) { - //d->cur_pack=d->cell_last_pack+1; - break; // we're after the last cell - } - d->cur_cell=next; - } - } - - mp_msg(MSGT_DVD,MSGL_V, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n", - d->cur_pack,d->cur_cell,d->cur_pgc->cell_playback[ d->cur_cell ].first_sector,d->cell_last_pack); - - // if we're in interleaved multi-angle cell, find the right angle chain! - // (read Navi block, and use the seamless angle jump table) - d->angle_seek=1; -} - -void dvd_close(dvd_priv_t *d) { - ifoClose(d->vts_file); - ifoClose(d->vmg_file); - DVDCloseFile(d->title); - DVDClose(d->dvd); - dvd_chapter = 1; - dvd_last_chapter = 0; -} - -#endif /* #ifdef USE_DVDREAD */ - -static int fill_buffer(stream_t *s, char *but, int len) -{ -#ifdef USE_DVDREAD - if(s->type == STREAMTYPE_DVD) { - off_t pos=dvd_read_sector(s->priv,s->buffer); - if(pos>=0) { - len=2048; // full sector - s->pos=2048*pos-len; - } else len=-1; // error - } -#endif - return len; -} - -static int seek(stream_t *s, off_t newpos) { -#ifdef USE_DVDREAD - s->pos=newpos; // real seek - dvd_seek(s->priv,s->pos/2048); -#endif - return 1; -} - -static void stream_dvd_close(stream_t *s) { -#ifdef USE_DVDREAD - dvd_close(s->priv); -#endif -} - -/** -\brief Converts DVD time structure to milliseconds. -\param *dev the DVD time structure to convert -\return returns the time in milliseconds -*/ -static int dvdtimetomsec(dvd_time_t *dt) -{ - static int framerates[4] = {0, 2500, 0, 2997}; - int framerate = framerates[(dt->frame_u & 0xc0) >> 6]; - int msec = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000; - msec += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000; - msec += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000; - if(framerate > 0) - msec += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 100000 / framerate; - return msec; -} - -static int mp_get_titleset_length(ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no) -{ - int vts_ttn; ///< title number within video title set - int pgc_no; ///< program chain number - int msec; ///< time length in milliseconds - - msec=0; - if(!vts_file || !tt_srpt) - return 0; - - if(vts_file->vtsi_mat && vts_file->vts_pgcit) - { - vts_ttn = tt_srpt->title[title_no].vts_ttn - 1; - pgc_no = vts_file->vts_ptt_srpt->title[vts_ttn].ptt[0].pgcn - 1; - msec = dvdtimetomsec(&vts_file->vts_pgcit->pgci_srp[pgc_no].pgc->playback_time); - } - return msec; -} - - -static int mp_describe_titleset(dvd_reader_t *dvd, tt_srpt_t *tt_srpt, int vts_no) -{ - ifo_handle_t *vts_file; - int title_no, msec=0; - - vts_file = ifoOpen(dvd, vts_no); - if(!vts_file) - return 0; - - if(!vts_file->vtsi_mat || !vts_file->vts_pgcit) - { - ifoClose(vts_file); - return 0; - } - - for(title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) - { - if (tt_srpt->title[title_no].title_set_nr != vts_no) - continue; - msec = mp_get_titleset_length(vts_file, tt_srpt, title_no); - mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_TITLE_%d_LENGTH=%d.%03d\n", title_no + 1, msec / 1000, msec % 1000); - } - ifoClose(vts_file); - return 1; -} - -static int control(stream_t *stream,int cmd,void* arg) -{ - switch(cmd) - { - case STREAM_CTRL_GET_TIME_LENGTH: - { - dvd_priv_t *d = stream->priv; - *((unsigned int *)arg) = mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title-1); - return 1; - } - } - return STREAM_UNSUPORTED; -} - - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - struct stream_priv_s* p = (struct stream_priv_s*)opts; - char *filename; - - filename = strdup(stream->url); - mp_msg(MSGT_OPEN,MSGL_V,"URL: %s\n", filename); - dvd_title = p->title; -#ifdef USE_DVDREAD - if(1){ - //int ret,ret2; - dvd_priv_t *d; - int ttn,pgc_id,pgn; - dvd_reader_t *dvd; - dvd_file_t *title; - ifo_handle_t *vmg_file; - tt_srpt_t *tt_srpt; - ifo_handle_t *vts_file; - /** - * Open the disc. - */ - if(!dvd_device) dvd_device=strdup(DEFAULT_DVD_DEVICE); -#ifdef SYS_DARWIN - /* Dynamic DVD drive selection on Darwin */ - if(!strcmp(dvd_device, "/dev/rdiskN")) { - int i; - char *temp_device = malloc(strlen(dvd_device)+1); - - for (i = 1; i < 10; i++) { - sprintf(temp_device, "/dev/rdisk%d", i); - dvd = DVDOpen(temp_device); - if(!dvd) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device); - } else { -#if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4) - int len; - if(!UDFFindFile(dvd,"/",&len)) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device); - DVDClose(dvd); - } else -#endif - { - free(temp_device); - break; - } - } - } - - if(!dvd) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - } else -#endif /* SYS_DARWIN */ - { - dvd = DVDOpen(dvd_device); - if(!dvd) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,dvd_device); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - } - - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDwait); - - /** - * Load the video manager to find out the information about the titles on - * this disc. - */ - vmg_file = ifoOpen(dvd, 0); - if(!vmg_file) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVMG); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - tt_srpt = vmg_file->tt_srpt; - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - int title_no; ///< title number - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLES=%d\n", tt_srpt->nr_of_srpts); - for (title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) - { - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_CHAPTERS=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_ptts); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_ANGLES=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_angles); - } - } - if (mp_msg_test(MSGT_IDENTIFY, MSGL_V)) - { - unsigned char discid [16]; ///< disk ID, a 128 bit MD5 sum - int vts_no; ///< video title set number - for (vts_no = 1; vts_no <= vmg_file->vts_atrt->nr_of_vtss; vts_no++) - mp_describe_titleset(dvd, tt_srpt, vts_no); - if (DVDDiscID(dvd, discid) >= 0) - { - int i; - char buf[33]; - for (i = 0; i < 16; i ++) - sprintf(buf+2*i, "%02X", discid[i]); - mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_DISC_ID=%s\n", buf); - } - } - /** - * Make sure our title number is valid. - */ - mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumTitles, tt_srpt->nr_of_srpts ); - if(dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidTitle, dvd_title); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - --dvd_title; // remap 1.. -> 0.. - /** - * Make sure the chapter number is valid for this title. - */ - mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumChapters, tt_srpt->title[dvd_title].nr_of_ptts); - if(dvd_chapter<1 || dvd_chapter>tt_srpt->title[dvd_title].nr_of_ptts) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidChapter, dvd_chapter); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - if(dvd_last_chapter>0) { - if(dvd_last_chapter<dvd_chapter || dvd_last_chapter>tt_srpt->title[dvd_title].nr_of_ptts) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidLastChapter, dvd_last_chapter); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - } - --dvd_chapter; // remap 1.. -> 0.. - /* XXX No need to remap dvd_last_chapter */ - /** - * Make sure the angle number is valid for this title. - */ - mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumAngles, tt_srpt->title[dvd_title].nr_of_angles); - if(dvd_angle<1 || dvd_angle>tt_srpt->title[dvd_title].nr_of_angles) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidAngle, dvd_angle); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - --dvd_angle; // remap 1.. -> 0.. - - ttn = tt_srpt->title[dvd_title].vts_ttn - 1; - /** - * Load the VTS information for the title set our title is in. - */ - vts_file = ifoOpen( dvd, tt_srpt->title[dvd_title].title_set_nr ); - if(!vts_file) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoIFO, tt_srpt->title[dvd_title].title_set_nr ); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - /** - * We've got enough info, time to open the title set data. - */ - title = DVDOpenFile(dvd, tt_srpt->title[dvd_title].title_set_nr, DVD_READ_TITLE_VOBS); - if(!title) { - mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVOBs, tt_srpt->title[dvd_title].title_set_nr); - ifoClose( vts_file ); - ifoClose( vmg_file ); - DVDClose( dvd ); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - - mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDopenOk); - // store data - d=malloc(sizeof(dvd_priv_t)); memset(d,0,sizeof(dvd_priv_t)); - d->dvd=dvd; - d->title=title; - d->vmg_file=vmg_file; - d->tt_srpt=tt_srpt; - d->vts_file=vts_file; - d->cur_title = dvd_title+1; - - /** - * Check number of audio channels and types - */ - { - d->nr_of_channels=0; - if(vts_file->vts_pgcit) { - int i; - for(i=0;i<8;i++) -#ifdef USE_MPDVDKIT - if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i].present) { -#else - if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i] & 0x8000) { -#endif - audio_attr_t * audio = &vts_file->vtsi_mat->vts_audio_attr[i]; - int language = 0; - char tmp[] = "unknown"; - - if(audio->lang_type == 1) { - language=audio->lang_code; - tmp[0]=language>>8; - tmp[1]=language&0xff; - tmp[2]=0; - } - - d->audio_streams[d->nr_of_channels].language=language; -#ifdef USE_MPDVDKIT - d->audio_streams[d->nr_of_channels].id=vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i].s_audio; -#else - d->audio_streams[d->nr_of_channels].id=vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i] >> 8 & 7; -#endif - switch(audio->audio_format) { - case 0: // ac3 - d->audio_streams[d->nr_of_channels].id+=FIRST_AC3_AID; - break; - case 6: // dts - d->audio_streams[d->nr_of_channels].id+=FIRST_DTS_AID; - break; - case 2: // mpeg layer 1/2/3 - case 3: // mpeg2 ext - d->audio_streams[d->nr_of_channels].id+=FIRST_MPG_AID; - break; - case 4: // lpcm - d->audio_streams[d->nr_of_channels].id+=FIRST_PCM_AID; - break; - } - - d->audio_streams[d->nr_of_channels].type=audio->audio_format; - // Pontscho: to my mind, tha channels: - // 1 - stereo - // 5 - 5.1 - d->audio_streams[d->nr_of_channels].channels=audio->channels; - mp_msg(MSGT_OPEN,MSGL_V,"[open] audio stream: %d audio format: %s (%s) language: %s aid: %d\n", - d->nr_of_channels, - dvd_audio_stream_types[ audio->audio_format ], - dvd_audio_stream_channels[ audio->channels ], - tmp, - d->audio_streams[d->nr_of_channels].id - ); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", d->audio_streams[d->nr_of_channels].id); - if(language && tmp[0]) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", d->audio_streams[d->nr_of_channels].id, tmp); - - d->nr_of_channels++; - } - } - mp_msg(MSGT_OPEN,MSGL_V,"[open] number of audio channels on disk: %d.\n",d->nr_of_channels ); - } - - /** - * Check number of subtitles and language - */ - { - int i; - - d->nr_of_subtitles=0; - for(i=0;i<32;i++) -#ifdef USE_MPDVDKIT - if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].present) { -#else - if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] & 0x80000000) { -#endif - subp_attr_t * subtitle = &vts_file->vtsi_mat->vts_subp_attr[i]; - video_attr_t *video = &vts_file->vtsi_mat->vts_video_attr; - int language = 0; - char tmp[] = "unknown"; - - if(subtitle->type == 1) { - language=subtitle->lang_code; - tmp[0]=language>>8; - tmp[1]=language&0xff; - tmp[2]=0; - } - - d->subtitles[ d->nr_of_subtitles ].language=language; - d->subtitles[ d->nr_of_subtitles ].id=d->nr_of_subtitles; - if(video->display_aspect_ratio == 0) /* 4:3 */ -#ifdef USE_MPDVDKIT - d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].s_4p3; -#else - d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] >> 24 & 31; -#endif - else if(video->display_aspect_ratio == 3) /* 16:9 */ -#ifdef USE_MPDVDKIT - d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].s_lbox; -#else - d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] >> 8 & 31; -#endif - - mp_msg(MSGT_OPEN,MSGL_V,"[open] subtitle ( sid ): %d language: %s\n", d->nr_of_subtitles, tmp); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", d->subtitles[d->nr_of_subtitles].id); - if(language && tmp[0]) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", d->nr_of_subtitles, tmp); - d->nr_of_subtitles++; - } - mp_msg(MSGT_OPEN,MSGL_V,"[open] number of subtitles on disk: %d\n",d->nr_of_subtitles ); - } - - /** - * Determine which program chain we want to watch. This is based on the - * chapter number. - */ - pgc_id = vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_chapter].pgcn; // local - pgn = vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_chapter].pgn; // local - d->cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; - d->cur_cell = d->cur_pgc->program_map[pgn-1] - 1; // start playback here - d->packs_left=-1; // for Navi stuff - d->angle_seek=0; - /* XXX dvd_last_chapter is in the range 1..nr_of_ptts */ - if(dvd_last_chapter > 0 && dvd_last_chapter < tt_srpt->title[dvd_title].nr_of_ptts) { - pgn=vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_last_chapter].pgn; - d->last_cell=d->cur_pgc->program_map[pgn-1] - 1; - } else - d->last_cell=d->cur_pgc->nr_of_cells; - - if(d->cur_pgc->cell_playback[d->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) - d->cur_cell+=dvd_angle; - d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; - d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; - mp_msg(MSGT_DVD,MSGL_V, "DVD start cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); - - // ... (unimplemented) - // return NULL; - stream->type = STREAMTYPE_DVD; - stream->sector_size = 2048; - stream->flags = STREAM_READ | STREAM_SEEK; - stream->fill_buffer = fill_buffer; - stream->seek = seek; - stream->control = control; - stream->close = stream_dvd_close; - stream->start_pos = (off_t)d->cur_pack*2048; - stream->end_pos = (off_t)(d->cur_pgc->cell_playback[d->last_cell-1].last_sector)*2048; - mp_msg(MSGT_DVD,MSGL_V,"DVD start=%d end=%d \n",d->cur_pack,d->cur_pgc->cell_playback[d->last_cell-1].last_sector); - stream->priv = (void*)d; - return STREAM_OK; - } -#endif /* #ifdef USE_DVDREAD */ - mp_msg(MSGT_DVD,MSGL_ERR,MSGTR_NoDVDSupport); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; -} - - -stream_info_t stream_info_dvd = { - "DVD stream", - "null", - "", - "", - open_s, - { "dvd", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/stream_dvd.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ - -#ifdef USE_DVDREAD - -#ifdef USE_MPDVDKIT -#include "libmpdvdkit2/dvd_reader.h" -#include "libmpdvdkit2/ifo_types.h" -#include "libmpdvdkit2/ifo_read.h" -#include "libmpdvdkit2/nav_read.h" -#else -#include <dvdread/dvd_reader.h> -#include <dvdread/ifo_types.h> -#include <dvdread/ifo_read.h> -#include <dvdread/nav_read.h> -#endif - -typedef struct { - dvd_reader_t *dvd; - dvd_file_t *title; - ifo_handle_t *vmg_file; - tt_srpt_t *tt_srpt; - ifo_handle_t *vts_file; - vts_ptt_srpt_t *vts_ptt_srpt; - pgc_t *cur_pgc; -// - int cur_title; - int cur_cell; - int last_cell; - int cur_pack; - int cell_last_pack; -// Navi: - int packs_left; - dsi_t dsi_pack; - int angle_seek; -// audio datas - int nr_of_channels; - stream_language_t audio_streams[32]; -// subtitles - int nr_of_subtitles; - stream_language_t subtitles[32]; -} dvd_priv_t; - -int dvd_number_of_subs(stream_t *stream); -int dvd_lang_from_sid(stream_t *stream, int id); -int dvd_aid_from_lang(stream_t *stream, unsigned char* lang); -int dvd_sid_from_lang(stream_t *stream, unsigned char* lang); -int dvd_chapter_from_cell(dvd_priv_t *dvd,int title,int cell); - -#endif
--- a/libmpdemux/stream_file.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -static struct stream_priv_s { - char* filename; - char *filename2; -} stream_priv_dflts = { - NULL, NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - {"string", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"filename", ST_OFF(filename2), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "file", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - int r = read(s->fd,buffer,max_len); - return (r <= 0) ? -1 : r; -} - -static int write_buffer(stream_t *s, char* buffer, int len) { - int r = write(s->fd,buffer,len); - return (r <= 0) ? -1 : r; -} - -static int seek(stream_t *s,off_t newpos) { - s->pos = newpos; - if(lseek(s->fd,s->pos,SEEK_SET)<0) { - s->eof=1; - return 0; - } - return 1; -} - -static int seek_forward(stream_t *s,off_t newpos) { - if(newpos<s->pos){ - mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n"); - return 0; - } - while(s->pos<newpos){ - int len=s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE); - if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; break; } // EOF - s->buf_pos=0; - s->buf_len=len; - s->pos+=len; - } - return 1; -} - -static int open_f(stream_t *stream,int mode, void* opts, int* file_format) { - int f; - mode_t m = 0; - off_t len; - unsigned char *filename; - struct stream_priv_s* p = (struct stream_priv_s*)opts; - - if(mode == STREAM_READ) - m = O_RDONLY; - else if(mode == STREAM_WRITE) - m = O_WRONLY; - else { - mp_msg(MSGT_OPEN,MSGL_ERR, "[file] Unknown open mode %d\n",mode); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - - if(p->filename) - filename = p->filename; - else if(p->filename2) - filename = p->filename2; - else - filename = NULL; - if(!filename) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[file] No filename\n"); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - -#if defined(__CYGWIN__)|| defined(__MINGW32__) - m |= O_BINARY; -#endif - - if(!strcmp(filename,"-")){ - if(mode == STREAM_READ) { - // read from stdin - mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ReadSTDIN); - f=0; // 0=stdin -#ifdef __MINGW32__ - setmode(fileno(stdin),O_BINARY); -#endif - } else { - mp_msg(MSGT_OPEN,MSGL_INFO,"Writing to stdout\n"); - f=1; -#ifdef __MINGW32__ - setmode(fileno(stdout),O_BINARY); -#endif - } - } else { - f=open(filename,m); - if(f<0) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - } - - len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET); -#ifdef __MINGW32__ - if(f==0 || len == -1) { -#else - if(len == -1) { -#endif - stream->seek = seek_forward; - stream->type = STREAMTYPE_STREAM; // Must be move to STREAMTYPE_FILE - stream->flags |= STREAM_SEEK_FW; - } else if(len >= 0) { - stream->seek = seek; - stream->end_pos = len; - stream->type = STREAMTYPE_FILE; - } - - mp_msg(MSGT_OPEN,MSGL_V,"[file] File size is %"PRId64" bytes\n", (int64_t)len); - - stream->fd = f; - stream->fill_buffer = fill_buffer; - stream->write_buffer = write_buffer; - - m_struct_free(&stream_opts,opts); - return STREAM_OK; -} - -stream_info_t stream_info_file = { - "File", - "file", - "Albeu", - "based on the code from ??? (probably Arpi)", - open_f, - { "file", "", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/stream_ftp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,469 +0,0 @@ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#ifndef HAVE_WINSOCK2 -#include <sys/socket.h> -#define closesocket close -#else -#include <winsock2.h> -#endif - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -static struct stream_priv_s { - char* user; - char* pass; - char* host; - int port; - char* filename; - - char *cput,*cget; - int handle; - int cavail,cleft; - char *buf; -} stream_priv_dflts = { - "anonymous","no@spam", - NULL, - 21, - NULL, - NULL, - NULL, - - 0, - 0,0, - NULL -}; - -#define BUFSIZE 2048 - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - {"username", ST_OFF(user), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"password", ST_OFF(pass), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"port", ST_OFF(port), CONF_TYPE_INT, 0, 0 ,65635, NULL}, - {"filename", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "ftp", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -#define TELNET_IAC 255 /* interpret as command: */ -#define TELNET_IP 244 /* interrupt process--permanently */ -#define TELNET_SYNCH 242 /* for telfunc calls */ - -// Check if there is something to read on a fd. This avoid hanging -// forever if the network stop responding. -static int fd_can_read(int fd,int timeout) { - fd_set fds; - struct timeval tv; - - FD_ZERO(&fds); - FD_SET(fd,&fds); - tv.tv_sec = timeout; - tv.tv_usec = 0; - - return (select(fd+1, &fds, NULL, NULL, &tv) > 0); -} - -/* - * read a line of text - * - * return -1 on error or bytecount - */ -static int readline(char *buf,int max,struct stream_priv_s *ctl) -{ - int x,retval = 0; - char *end,*bp=buf; - int eof = 0; - - do { - if (ctl->cavail > 0) { - x = (max >= ctl->cavail) ? ctl->cavail : max-1; - end = memccpy(bp,ctl->cget,'\n',x); - if (end != NULL) - x = end - bp; - retval += x; - bp += x; - *bp = '\0'; - max -= x; - ctl->cget += x; - ctl->cavail -= x; - if (end != NULL) { - bp -= 2; - if (strcmp(bp,"\r\n") == 0) { - *bp++ = '\n'; - *bp++ = '\0'; - --retval; - } - break; - } - } - if (max == 1) { - *buf = '\0'; - break; - } - if (ctl->cput == ctl->cget) { - ctl->cput = ctl->cget = ctl->buf; - ctl->cavail = 0; - ctl->cleft = BUFSIZE; - } - if(eof) { - if (retval == 0) - retval = -1; - break; - } - - if(!fd_can_read(ctl->handle, 15)) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); - retval = -1; - break; - } - - if ((x = recv(ctl->handle,ctl->cput,ctl->cleft,0)) == -1) { - mp_msg(MSGT_STREAM,MSGL_ERR, "[ftp] read error: %s\n",strerror(errno)); - retval = -1; - break; - } - if (x == 0) - eof = 1; - ctl->cleft -= x; - ctl->cavail += x; - ctl->cput += x; - } while (1); - - return retval; -} - -/* - * read a response from the server - * - * return 0 if first char doesn't match - * return 1 if first char matches - */ -static int readresp(struct stream_priv_s* ctl,char* rsp) -{ - static char response[256]; - char match[5]; - int r; - - if (readline(response,256,ctl) == -1) - return 0; - - r = atoi(response)/100; - if(rsp) strcpy(rsp,response); - - mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response); - - if (response[3] == '-') { - strncpy(match,response,3); - match[3] = ' '; - match[4] = '\0'; - do { - if (readline(response,256,ctl) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Control socket read failed\n"); - return 0; - } - mp_msg(MSGT_OPEN,MSGL_V, "[ftp] < %s",response); - } while (strncmp(response,match,4)); - } - return r; -} - - -static int FtpSendCmd(const char *cmd, struct stream_priv_s *nControl,char* rsp) -{ - int l = strlen(cmd); - int hascrlf = cmd[l - 2] == '\r' && cmd[l - 1] == '\n'; - - if(hascrlf && l == 2) mp_msg(MSGT_STREAM,MSGL_V, "\n"); - else mp_msg(MSGT_STREAM,MSGL_V, "[ftp] > %s",cmd); - while(l > 0) { - int s = send(nControl->handle,cmd,l,0); - - if(s <= 0) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] write error: %s\n",strerror(errno)); - return 0; - } - - cmd += s; - l -= s; - } - - if (hascrlf) - return readresp(nControl,rsp); - else - return FtpSendCmd("\r\n", nControl, rsp); -} - -static int FtpOpenPort(struct stream_priv_s* p) { - int resp,fd; - char rsp_txt[256]; - char* par,str[128]; - int num[6]; - - resp = FtpSendCmd("PASV",p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'PASV' failed: %s\n",rsp_txt); - return 0; - } - - par = strchr(rsp_txt,'('); - - if(!par || !par[0] || !par[1]) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] invalid server response: %s ??\n",rsp_txt); - return 0; - } - - sscanf(par+1,"%u,%u,%u,%u,%u,%u",&num[0],&num[1],&num[2], - &num[3],&num[4],&num[5]); - snprintf(str,127,"%d.%d.%d.%d",num[0],num[1],num[2],num[3]); - fd = connect2Server(str,(num[4]<<8)+num[5],0); - - if(fd < 0) - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] failed to create data connection\n"); - - return fd; -} - -static int FtpOpenData(stream_t* s,size_t newpos) { - struct stream_priv_s* p = s->priv; - int resp; - char str[256],rsp_txt[256]; - - // Open a new connection - s->fd = FtpOpenPort(p); - - if(s->fd < 0) return 0; - - if(newpos > 0) { - snprintf(str,255,"REST %"PRId64, (int64_t)newpos); - - resp = FtpSendCmd(str,p,rsp_txt); - if(resp != 3) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt); - newpos = 0; - } - } - - // Get the file - snprintf(str,255,"RETR %s",p->filename); - resp = FtpSendCmd(str,p,rsp_txt); - - if(resp != 1) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); - return 0; - } - - s->pos = newpos; - return 1; -} - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - int r; - - if(s->fd < 0 && !FtpOpenData(s,s->pos)) - return -1; - - if(!fd_can_read(s->fd, 15)) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); - return -1; - } - - r = recv(s->fd,buffer,max_len,0); - return (r <= 0) ? -1 : r; -} - -static int seek(stream_t *s,off_t newpos) { - struct stream_priv_s* p = s->priv; - int resp; - char rsp_txt[256]; - - if(s->pos > s->end_pos) { - s->eof=1; - return 0; - } - - // Check to see if the server doesn't alredy terminated the transfert - if(fd_can_read(p->handle, 0)) { - if(readresp(p,rsp_txt) != 2) - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] Warning the server didn't finished the transfert correctly: %s\n",rsp_txt); - closesocket(s->fd); - s->fd = -1; - } - - // Close current download - if(s->fd >= 0) { - static const char pre_cmd[]={TELNET_IAC,TELNET_IP,TELNET_IAC,TELNET_SYNCH}; - //int fl; - - // First close the fd - closesocket(s->fd); - s->fd = 0; - - // Send send the telnet sequence needed to make the server react - - // Dunno if this is really needed, lftp have it. I let - // it here in case it turn out to be needed on some other OS - //fl=fcntl(p->handle,F_GETFL); - //fcntl(p->handle,F_SETFL,fl&~O_NONBLOCK); - - // send only first byte as OOB due to OOB braindamage in many unices - send(p->handle,pre_cmd,1,MSG_OOB); - send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,0); - - //fcntl(p->handle,F_SETFL,fl); - - // Get the 426 Transfer aborted - // Or the 226 Transfer complete - resp = readresp(p,rsp_txt); - if(resp != 4 && resp != 2) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Server didn't abort correctly: %s\n",rsp_txt); - s->eof = 1; - return 0; - } - // Send the ABOR command - // Ignore the return code as sometimes it fail with "nothing to abort" - FtpSendCmd("ABOR",p,rsp_txt); - } - return FtpOpenData(s,newpos); -} - - -static void close_f(stream_t *s) { - struct stream_priv_s* p = s->priv; - - if(!p) return; - - if(s->fd > 0) { - closesocket(s->fd); - s->fd = 0; - } - - FtpSendCmd("QUIT",p,NULL); - - if(p->handle) closesocket(p->handle); - if(p->buf) free(p->buf); - - m_struct_free(&stream_opts,p); -} - - - -static int open_f(stream_t *stream,int mode, void* opts, int* file_format) { - int len = 0,resp; - struct stream_priv_s* p = (struct stream_priv_s*)opts; - char str[256],rsp_txt[256]; - - if(mode != STREAM_READ) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - - if(!p->filename || !p->host) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Bad url\n"); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - // Open the control connection - p->handle = connect2Server(p->host,p->port,1); - - if(p->handle < 0) { - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - // We got a connection, let's start serious things - stream->fd = -1; - stream->priv = p; - p->buf = malloc(BUFSIZE); - - if (readresp(p, NULL) == 0) { - close_f(stream); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - // Login - snprintf(str,255,"USER %s",p->user); - resp = FtpSendCmd(str,p,rsp_txt); - - // password needed - if(resp == 3) { - snprintf(str,255,"PASS %s",p->pass); - resp = FtpSendCmd(str,p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); - close_f(stream); - return STREAM_ERROR; - } - } else if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); - close_f(stream); - return STREAM_ERROR; - } - - // Set the transfert type - resp = FtpSendCmd("TYPE I",p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'TYPE I' failed: %s\n",rsp_txt); - close_f(stream); - return STREAM_ERROR; - } - - // Get the filesize - snprintf(str,255,"SIZE %s",p->filename); - resp = FtpSendCmd(str,p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt); - } else { - int dummy; - sscanf(rsp_txt,"%d %d",&dummy,&len); - } - - if(len > 0) { - stream->seek = seek; - stream->end_pos = len; - } - - // The data connection is really opened only at the first - // read/seek. This must be done when the cache is used - // because the connection would stay open in the main process, - // preventing correct abort with many servers. - stream->fd = -1; - stream->priv = p; - stream->fill_buffer = fill_buffer; - stream->close = close_f; - - return STREAM_OK; -} - -stream_info_t stream_info_ftp = { - "File Transfer Protocol", - "ftp", - "Albeu", - "reuse a bit of code from ftplib written by Thomas Pfau", - open_f, - { "ftp", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/stream_livedotcom.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ - -#include "config.h" - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "stream.h" -#include "network.h" -#include "demuxer.h" -#include "help_mp.h" - -extern int network_bandwidth; - -static int _rtsp_streaming_seek(int fd, off_t pos, streaming_ctrl_t* streaming_ctrl) { - return -1; // For now, we don't handle RTSP stream seeking -} - -static int rtsp_streaming_start(stream_t* stream) { - stream->streaming_ctrl->streaming_seek = _rtsp_streaming_seek; - return 0; -} - - -static int open_live_rtsp_sip(stream_t *stream,int mode, void* opts, int* file_format) { - URL_t *url; - - stream->streaming_ctrl = streaming_ctrl_new(); - if( stream->streaming_ctrl==NULL ) { - return STREAM_ERROR; - } - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new(stream->url); - stream->streaming_ctrl->url = check4proxies(url); - //url_free(url); - - mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_LIVE555, URL: %s\n", stream->url); - - if(rtsp_streaming_start(stream) < 0) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"rtsp_streaming_start failed\n"); - goto fail; - } - - *file_format = DEMUXER_TYPE_RTP; - stream->type = STREAMTYPE_STREAM; - return STREAM_OK; - -fail: - streaming_ctrl_free( stream->streaming_ctrl ); - stream->streaming_ctrl = NULL; - return STREAM_ERROR; -} - -static int open_live_sdp(stream_t *stream,int mode, void* opts, int* file_format) { - int f; - char *filename = stream->url; - off_t len; - char* sdpDescription; - ssize_t numBytesRead; - - if(strncmp("sdp://",filename,6) == 0) { - filename += 6; -#if defined(__CYGWIN__) || defined(__MINGW32__) - f = open(filename,O_RDONLY|O_BINARY); -#else - f = open(filename,O_RDONLY); -#endif - if(f < 0) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename); - return STREAM_ERROR; - } - - len=lseek(f,0,SEEK_END); - lseek(f,0,SEEK_SET); - if(len == -1) - return STREAM_ERROR; - if(len > SIZE_MAX - 1) - return STREAM_ERROR; - - sdpDescription = malloc(len+1); - if(sdpDescription == NULL) return STREAM_ERROR; - numBytesRead = read(f, sdpDescription, len); - if(numBytesRead != len) { - free(sdpDescription); - return STREAM_ERROR; - } - sdpDescription[len] = '\0'; // to be safe - stream->priv = sdpDescription; - - stream->type = STREAMTYPE_SDP; - *file_format = DEMUXER_TYPE_RTP; - return STREAM_OK; - } - return STREAM_UNSUPORTED; -} - - -stream_info_t stream_info_rtsp_sip = { - "standard RTSP and SIP", - "RTSP and SIP", - "Ross Finlayson", - "Uses LIVE555 Streaming Media library.", - open_live_rtsp_sip, - {"rtsp", "sip", NULL }, - NULL, - 0 // Urls are an option string -}; - -stream_info_t stream_info_sdp = { - "SDP stream descriptor", - "SDP", - "Ross Finlayson", - "Uses LIVE555 Streaming Media library.", - open_live_sdp, - {"sdp", NULL }, - NULL, - 0 // Urls are an option string -};
--- a/libmpdemux/stream_netstream.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/* - * stream_netstream.c - * - * Copyright (C) Alban Bedel - 04/2003 - * - * This file is part of MPlayer, a free movie player. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -/* - * Net stream allow you to access MPlayer stream accross a tcp - * connection. - * Note that at least mf and tv use a dummy stream (they are - * implemented at the demuxer level) so you won't be able to - * access those :(( but dvd, vcd and so on should work perfectly - * (if you have the bandwidth ;) - * A simple server is in TOOLS/netstream. - * - */ - - -#include "config.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#include <stdlib.h> -#include <stdio.h> -#include <inttypes.h> -#include <errno.h> - -#ifndef HAVE_WINSOCK2 -#define closesocket close -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#else -#include <winsock2.h> -#endif - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" -#include "bswap.h" - -#include "netstream.h" - -static struct stream_priv_s { - char* host; - int port; - char* url; -} stream_priv_dflts = { - NULL, - 10000, - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"port", ST_OFF(port), CONF_TYPE_INT, M_OPT_MIN, 1 ,0, NULL}, - {"filename", ST_OFF(url), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "netstream", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -//// When the cache is running we need a lock as -//// fill_buffer is called from another proccess -static int lock_fd(int fd) { -#ifndef HAVE_WINSOCK2 - struct flock lock; - - memset(&lock,0,sizeof(struct flock)); - lock.l_type = F_WRLCK; - - mp_msg(MSGT_STREAM,MSGL_DBG2, "Lock (%d)\n",getpid()); - do { - if(fcntl(fd,F_SETLKW,&lock)) { - if(errno == EAGAIN) continue; - mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to get the lock: %s\n", - strerror(errno)); - return 0; - } - } while(0); - mp_msg(MSGT_STREAM,MSGL_DBG2, "Locked (%d)\n",getpid()); -#else -printf("FIXME? should lock here\n"); -#endif - return 1; -} - -static int unlock_fd(int fd) { -#ifndef HAVE_WINSOCK2 - struct flock lock; - - memset(&lock,0,sizeof(struct flock)); - lock.l_type = F_UNLCK; - - mp_msg(MSGT_STREAM,MSGL_DBG2, "Unlock (%d)\n",getpid()); - if(fcntl(fd,F_SETLK,&lock)) { - mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to release the lock: %s\n", - strerror(errno)); - return 0; - } -#else -printf("FIXME? should unlock here\n"); -#endif - return 1; -} - -static mp_net_stream_packet_t* send_net_stream_cmd(stream_t *s,uint16_t cmd,char* data,int len) { - mp_net_stream_packet_t* pack; - - // Cache is enabled : lock - if(s->cache_data && !lock_fd(s->fd)) - return NULL; - // Send a command - if(!write_packet(s->fd,cmd,data,len)) { - if(s->cache_data) unlock_fd(s->fd); - return 0; - } - // Read the response - pack = read_packet(s->fd); - // Now we can unlock - if(s->cache_data) unlock_fd(s->fd); - - if(!pack) - return NULL; - - switch(pack->cmd) { - case NET_STREAM_OK: - return pack; - case NET_STREAM_ERROR: - if(pack->len > sizeof(mp_net_stream_packet_t)) - mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed: %s\n",pack->data); - else - mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed\n"); - free(pack); - return NULL; - } - - mp_msg(MSGT_STREAM,MSGL_ERR, "Unknown response to %d: %d\n",cmd,pack->cmd); - free(pack); - return NULL; -} - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - uint16_t len = le2me_16(max_len); - mp_net_stream_packet_t* pack; - - pack = send_net_stream_cmd(s,NET_STREAM_FILL_BUFFER,(char*)&len,2); - if(!pack) { - return -1; - } - len = pack->len - sizeof(mp_net_stream_packet_t); - if(len > max_len) { - mp_msg(MSGT_STREAM,MSGL_ERR, "Got a too big a packet %d / %d\n",len,max_len); - free(pack); - return 0; - } - if(len > 0) - memcpy(buffer,pack->data,len); - free(pack); - return len; -} - - -static int seek(stream_t *s,off_t newpos) { - uint64_t pos = le2me_64((uint64_t)newpos); - mp_net_stream_packet_t* pack; - - pack = send_net_stream_cmd(s,NET_STREAM_SEEK,(char*)&pos,8); - if(!pack) { - return 0; - } - s->pos = newpos; - free(pack); - return 1; -} - -static int net_stream_reset(struct stream_st *s) { - mp_net_stream_packet_t* pack; - - pack = send_net_stream_cmd(s,NET_STREAM_RESET,NULL,0); - if(!pack) { - return 0; - } - free(pack); - return 1; -} - -static int control(struct stream_st *s,int cmd,void* arg) { - switch(cmd) { - case STREAM_CTRL_RESET: - return net_stream_reset(s); - } - return STREAM_UNSUPORTED; -} - -static void close_s(struct stream_st *s) { - mp_net_stream_packet_t* pack; - - pack = send_net_stream_cmd(s,NET_STREAM_CLOSE,NULL,0); - if(pack) - free(pack); -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - int f; - struct stream_priv_s* p = (struct stream_priv_s*)opts; - mp_net_stream_packet_t* pack; - mp_net_stream_opened_t* opened; - - if(mode != STREAM_READ) - return STREAM_UNSUPORTED; - - if(!p->host) { - mp_msg(MSGT_OPEN,MSGL_ERR, "We need an host name (ex: mpst://server.net/cdda://5)\n"); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - if(!p->url || strlen(p->url) == 0) { - mp_msg(MSGT_OPEN,MSGL_ERR, "We need a remote url (ex: mpst://server.net/cdda://5)\n"); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - f = connect2Server(p->host,p->port,1); - if(f < 0) { - mp_msg(MSGT_OPEN,MSGL_ERR, "Connection to %s:%d failed\n",p->host,p->port); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - stream->fd = f; - /// Now send an open command - pack = send_net_stream_cmd(stream,NET_STREAM_OPEN,p->url,strlen(p->url) + 1); - if(!pack) { - goto error; - } - - if(pack->len != sizeof(mp_net_stream_packet_t) + - sizeof(mp_net_stream_opened_t)) { - mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid open response packet len (%d bytes)\n",pack->len); - free(pack); - goto error; - } - - opened = (mp_net_stream_opened_t*)pack->data; - net_stream_opened_2_me(opened); - - *file_format = opened->file_format; - stream->flags = opened->flags; - stream->sector_size = opened->sector_size; - stream->start_pos = opened->start_pos; - stream->end_pos = opened->end_pos; - - stream->fill_buffer = fill_buffer; - stream->control = control; - if(stream->flags & STREAM_SEEK) - stream->seek = seek; - stream->close = close_s; - - free(pack); - m_struct_free(&stream_opts,opts); - - return STREAM_OK; - - error: - closesocket(f); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; -} - -stream_info_t stream_info_netstream = { - "Net stream", - "netstream", - "Albeu", - "", - open_s, - { "mpst",NULL }, - &stream_opts, - 1 // Url is an option string -};
--- a/libmpdemux/stream_null.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ - -#include "config.h" - -#include <stdlib.h> -#include <string.h> - -#include "stream.h" -#include "demuxer.h" - -#ifdef USE_TV -extern char* tv_param_channel; -#endif - - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - stream->type = STREAMTYPE_DUMMY; - - if(strncmp("mf://",stream->url,5) == 0) { - *file_format = DEMUXER_TYPE_MF; - } -#ifdef USE_TV - else if (strncmp("tv://",stream->url,5) == 0) { - *file_format = DEMUXER_TYPE_TV; - if(stream->url[5] != '\0') - tv_param_channel = strdup(stream->url + 5); - } -#endif - return 1; -} - - -stream_info_t stream_info_null = { - "Null stream", - "null", - "Albeu", - "", - open_s, - { -#ifdef USE_TV -"tv", -#endif -"mf", "null", NULL }, - NULL, - 0 // Urls are an option string -};
--- a/libmpdemux/stream_pvr.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1026 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Zores - * Stream layer for WinTV PVR-150/250/350 (a.k.a IVTV) PVR cards. - * See http://ivtvdriver.org/index.php/Main_Page for more details on the - * cards supported by the ivtv driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <sys/time.h> -#include <errno.h> -#include <sys/ioctl.h> -#include <sys/fcntl.h> -#include <inttypes.h> -#include <sys/poll.h> -#include <linux/videodev2.h> -#include <linux/ivtv.h> - -#include "mp_msg.h" -#include "help_mp.h" - -#include "stream.h" -#include "tv.h" - -#define PVR_DEFAULT_DEVICE "/dev/video0" - -/* logging mechanisms */ -#define LOG_LEVEL_PVR "[pvr]" -#define LOG_LEVEL_V4L2 "[v4l2]" -#define LOG_LEVEL_IVTV "[ivtv]" - -/* IVTV driver settings (see http://ivtvdriver.org/index.php/Ivtvctl ) */ - -/* codec aspect ratio (1:1, 4:3, 16:9, 2.21:1) */ -#define PVR_ASPECT_RATIO_1_1 1 -#define PVR_ASPECT_RATIO_4_3 2 -#define PVR_ASPECT_RATIO_16_9 3 -#define PVR_ASPECT_RATIO_2_21_1 4 - -/* audio codec sample rate (32KHz, CD 44.1 KHz, AC97 48 KHz) */ -#define PVR_AUDIO_SAMPLE_RATE_44_1_KHZ 0x0000 -#define PVR_AUDIO_SAMPLE_RATE_48_KHZ 0x0001 -#define PVR_AUDIO_SAMPLE_RATE_32_KHZ 0x0002 - -/* audio codec layer (1 or 2) */ -#define PVR_AUDIO_LAYER_1 0x0004 -#define PVR_AUDIO_LAYER_2 0x0008 - -/* audio codec bitrate */ -#define PVR_AUDIO_BITRATE_32 0x0010 -#define PVR_AUDIO_BITRATE_L1_64 0x0020 -#define PVR_AUDIO_BITRATE_L1_96 0x0030 -#define PVR_AUDIO_BITRATE_L1_128 0x0040 -#define PVR_AUDIO_BITRATE_L1_160 0x0050 -#define PVR_AUDIO_BITRATE_L1_192 0x0060 -#define PVR_AUDIO_BITRATE_L1_224 0x0070 -#define PVR_AUDIO_BITRATE_L1_256 0x0080 -#define PVR_AUDIO_BITRATE_L1_288 0x0090 -#define PVR_AUDIO_BITRATE_L1_320 0x00A0 -#define PVR_AUDIO_BITRATE_L1_352 0x00B0 -#define PVR_AUDIO_BITRATE_L1_384 0x00C0 -#define PVR_AUDIO_BITRATE_L1_416 0x00D0 -#define PVR_AUDIO_BITRATE_L1_448 0x00E0 -#define PVR_AUDIO_BITRATE_L2_48 0x0020 -#define PVR_AUDIO_BITRATE_L2_56 0x0030 -#define PVR_AUDIO_BITRATE_L2_64 0x0040 -#define PVR_AUDIO_BITRATE_L2_80 0x0050 -#define PVR_AUDIO_BITRATE_L2_96 0x0060 -#define PVR_AUDIO_BITRATE_L2_112 0x0070 -#define PVR_AUDIO_BITRATE_L2_128 0x0080 -#define PVR_AUDIO_BITRATE_L2_160 0x0090 -#define PVR_AUDIO_BITRATE_L2_192 0x00A0 -#define PVR_AUDIO_BITRATE_L2_224 0x00B0 -#define PVR_AUDIO_BITRATE_L2_256 0x00C0 -#define PVR_AUDIO_BITRATE_L2_320 0x00D0 -#define PVR_AUDIO_BITRATE_L2_384 0x00E0 - -/* audio codec mode */ -#define PVR_AUDIO_MODE_ARG_STEREO "stereo" -#define PVR_AUDIO_MODE_ARG_JOINT_STEREO "joint_stereo" -#define PVR_AUDIO_MODE_ARG_DUAL "dual" -#define PVR_AUDIO_MODE_ARG_MONO "mono" -#define PVR_AUDIO_MODE_STEREO 0x0000 -#define PVR_AUDIO_MODE_JOINT_STEREO 0x0100 -#define PVR_AUDIO_MODE_DUAL 0x0200 -#define PVR_AUDIO_MODE_MONO 0x0300 - -/* video codec bitrate mode */ -#define PVR_VIDEO_BITRATE_MODE_ARG_VBR "vbr" -#define PVR_VIDEO_BITRATE_MODE_ARG_CBR "cbr" -#define PVR_VIDEO_BITRATE_MODE_VBR 0 -#define PVR_VIDEO_BITRATE_MODE_CBR 1 - -/* video codec stream type */ -#define PVR_VIDEO_STREAM_TYPE_PS "ps" -#define PVR_VIDEO_STREAM_TYPE_TS "ts" -#define PVR_VIDEO_STREAM_TYPE_MPEG1 "mpeg1" -#define PVR_VIDEO_STREAM_TYPE_DVD "dvd" -#define PVR_VIDEO_STREAM_TYPE_VCD "vcd" -#define PVR_VIDEO_STREAM_TYPE_SVCD "svcd" -#define PVR_VIDEO_STREAM_TYPE_DVD_S1 "dvds1" -#define PVR_VIDEO_STREAM_TYPE_DVD_S2 "dvds2" - -/* command line arguments */ -int pvr_param_aspect_ratio = 0; -int pvr_param_sample_rate = 0; -int pvr_param_audio_layer = 0; -int pvr_param_audio_bitrate = 0; -char *pvr_param_audio_mode = NULL; -int pvr_param_bitrate = 0; -char *pvr_param_bitrate_mode = NULL; -int pvr_param_bitrate_peak = 0; -char *pvr_param_stream_type = NULL; - -struct pvr_t { - int dev_fd; - char *video_dev; - - /* v4l2 params */ - int mute; - int input; - int normid; - int brightness; - int contrast; - int hue; - int saturation; - int width; - int height; - char *freq; - - /* ivtv params */ - int aspect; - int samplerate; - int layer; - int audio_rate; - int audio_mode; - int bitrate; - int bitrate_mode; - int bitrate_peak; - int stream_type; -}; - -static struct pvr_t * -pvr_init (void) -{ - struct pvr_t *pvr = NULL; - - pvr = malloc (sizeof (struct pvr_t)); - pvr->dev_fd = -1; - pvr->video_dev = strdup (PVR_DEFAULT_DEVICE); - - /* v4l2 params */ - pvr->mute = 0; - pvr->input = 0; - pvr->normid = -1; - pvr->brightness = 0; - pvr->contrast = 0; - pvr->hue = 0; - pvr->saturation = 0; - pvr->width = -1; - pvr->height = -1; - pvr->freq = NULL; - - /* ivtv params */ - pvr->aspect = -1; - pvr->samplerate = -1; - pvr->layer = -1; - pvr->audio_rate = -1; - pvr->audio_mode = -1; - pvr->bitrate = -1; - pvr->bitrate_mode = -1; - pvr->bitrate_peak = -1; - pvr->stream_type = -1; - - return pvr; -} - -static void -pvr_uninit (struct pvr_t *pvr) -{ - if (!pvr) - return; - - /* close device */ - if (pvr->dev_fd) - close (pvr->dev_fd); - - if (pvr->video_dev) - free (pvr->video_dev); - if (pvr->freq) - free (pvr->freq); - free (pvr); -} - -/* IVTV layer */ - -static void -parse_ivtv_options (struct pvr_t *pvr) -{ - if (!pvr) - return; - - /* -pvr aspect=digit */ - if (pvr_param_aspect_ratio >= 1 && pvr_param_aspect_ratio <= 4) - pvr->aspect = pvr_param_aspect_ratio; - - /* -pvr arate=x */ - if (pvr_param_sample_rate != 0) - { - switch (pvr_param_sample_rate) - { - case 32000: - pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_32_KHZ; - break; - case 44100: - pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_44_1_KHZ; - break; - case 48000: - pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_48_KHZ; - break; - default: - break; - } - } - - /* -pvr alayer=x */ - if (pvr_param_audio_layer == 1) - pvr->layer = PVR_AUDIO_LAYER_1; - else if (pvr_param_audio_layer == 2) - pvr->layer = PVR_AUDIO_LAYER_2; - - /* -pvr abitrate=x */ - if (pvr_param_audio_bitrate != 0) - { - /* set according to layer or use layer 1 by default if not specified */ - switch (pvr_param_audio_bitrate) - { - case 32: - pvr->audio_rate = PVR_AUDIO_BITRATE_32; - break; - case 48: - pvr->audio_rate = PVR_AUDIO_BITRATE_L2_48; - break; - case 56: - pvr->audio_rate = PVR_AUDIO_BITRATE_L2_56; - break; - case 64: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_64 : PVR_AUDIO_BITRATE_L1_64; - break; - case 80: - pvr->audio_rate = PVR_AUDIO_BITRATE_L2_80; - break; - case 96: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_96 : PVR_AUDIO_BITRATE_L1_96; - break; - case 112: - pvr->audio_rate = PVR_AUDIO_BITRATE_L2_112; - break; - case 128: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_128 : PVR_AUDIO_BITRATE_L1_128; - break; - case 160: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_160 : PVR_AUDIO_BITRATE_L1_160; - break; - case 192: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_192 : PVR_AUDIO_BITRATE_L1_192; - break; - case 224: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_224 : PVR_AUDIO_BITRATE_L1_224; - break; - case 256: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_256 : PVR_AUDIO_BITRATE_L1_256; - break; - case 288: - pvr->audio_rate = PVR_AUDIO_BITRATE_L1_288; - break; - case 320: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_320 : PVR_AUDIO_BITRATE_L1_320; - break; - case 352: - pvr->audio_rate = PVR_AUDIO_BITRATE_L1_352; - break; - case 384: - pvr->audio_rate = (pvr_param_audio_layer == 2) ? - PVR_AUDIO_BITRATE_L2_384 : PVR_AUDIO_BITRATE_L1_384; - break; - case 416: - pvr->audio_rate = PVR_AUDIO_BITRATE_L1_416; - break; - case 448: - pvr->audio_rate = PVR_AUDIO_BITRATE_L1_448; - break; - default: - break; - } - } - - /* -pvr amode=x */ - if (pvr_param_audio_mode) - { - if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_STEREO)) - pvr->audio_mode = PVR_AUDIO_MODE_STEREO; - else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_JOINT_STEREO)) - pvr->audio_mode = PVR_AUDIO_MODE_JOINT_STEREO; - else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_DUAL)) - pvr->audio_mode = PVR_AUDIO_MODE_DUAL; - else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_MONO)) - pvr->audio_mode = PVR_AUDIO_MODE_MONO; - else /* for anything else, set to stereo */ - pvr->audio_mode = PVR_AUDIO_MODE_STEREO; - } - - /* -pvr vbitrate=x */ - if (pvr_param_bitrate) - pvr->bitrate = pvr_param_bitrate; - - /* -pvr vmode=x */ - if (pvr_param_bitrate_mode) - { - if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_VBR)) - pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; - else if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_CBR)) - pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_CBR; - else /* for anything else, set to VBR */ - pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; - } - - /* -pvr vpeak=x */ - if (pvr_param_bitrate_peak) - pvr->bitrate_peak = pvr_param_bitrate_peak; - - /* -pvr fmt=x */ - if (pvr_param_stream_type) - { - if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_PS)) - pvr->stream_type = IVTV_STREAM_PS; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_TS)) - pvr->stream_type = IVTV_STREAM_TS; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_MPEG1)) - pvr->stream_type = IVTV_STREAM_MPEG1; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD)) - pvr->stream_type = IVTV_STREAM_DVD; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_VCD)) - pvr->stream_type = IVTV_STREAM_VCD; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_SVCD)) - pvr->stream_type = IVTV_STREAM_SVCD; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S1)) - pvr->stream_type = IVTV_STREAM_DVD_S1; - else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S2)) - pvr->stream_type = IVTV_STREAM_DVD_S2; - else /* for anything else, set to MPEG PS */ - pvr->stream_type = IVTV_STREAM_PS; - } -} - -static int -set_ivtv_settings (struct pvr_t *pvr) -{ - struct ivtv_ioctl_codec codec; - - if (!pvr) - return -1; - - if (pvr->dev_fd < 0) - return -1; - - /* get current settings */ - if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno)); - return -1; - } - - /* set default encoding settings - * may be overlapped by user parameters - * Use VBR MPEG_PS encoding at 6 Mbps (peak at 9.6 Mbps) - * with 48 KHz L2 384 kbps audio. - */ - codec.aspect = PVR_ASPECT_RATIO_4_3; - codec.bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; - codec.bitrate = 6000000; - codec.bitrate_peak = 9600000; - codec.stream_type = IVTV_STREAM_PS; - codec.audio_bitmask = PVR_AUDIO_LAYER_2 - | PVR_AUDIO_BITRATE_L2_384 | PVR_AUDIO_SAMPLE_RATE_48_KHZ; - - /* set aspect ratio */ - if (pvr->aspect != -1) - codec.aspect = pvr->aspect; - - /* if user value is given, we need to reset audio bitmask */ - if ((pvr->samplerate != -1) || (pvr->layer != -1) - || (pvr->audio_rate != -1) || (pvr->audio_mode != -1)) - codec.audio_bitmask = 0; - - /* set audio samplerate */ - if (pvr->samplerate != -1) - codec.audio_bitmask |= pvr->samplerate; - - /* set audio layer */ - if (pvr->layer != -1) - codec.audio_bitmask |= pvr->layer; - - /* set audio bitrate */ - if (pvr->audio_rate != -1) - codec.audio_bitmask |= pvr->audio_rate; - - /* set audio mode */ - if (pvr->audio_mode != -1) - codec.audio_bitmask |= pvr->audio_mode; - - /* set video bitrate */ - if (pvr->bitrate != -1) - codec.bitrate = pvr->bitrate; - - /* set video bitrate mode */ - if (pvr->bitrate_mode != -1) - codec.bitrate_mode = pvr->bitrate_mode; - - /* set video bitrate peak */ - if (pvr->bitrate != -1) - codec.bitrate_peak = pvr->bitrate_peak; - - /* set video stream type */ - if (pvr->stream_type != -1) - codec.stream_type = pvr->stream_type; - - /* set new encoding settings */ - if (ioctl (pvr->dev_fd, IVTV_IOC_S_CODEC, &codec) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno)); - return -1; - } - - return 0; -} - -/* V4L2 layer */ - -static void -parse_v4l2_tv_options (struct pvr_t *pvr) -{ - if (!pvr) - return; - - if (tv_param_device) - { - if (pvr->video_dev) - free (pvr->video_dev); - pvr->video_dev = strdup (tv_param_device); - } - - if (tv_param_noaudio) - pvr->mute = tv_param_noaudio; - - if (tv_param_input) - pvr->input = tv_param_input; - - if (tv_param_normid) - pvr->normid = tv_param_normid; - - if (tv_param_brightness) - pvr->brightness = tv_param_brightness; - - if (tv_param_contrast) - pvr->contrast = tv_param_contrast; - - if (tv_param_hue) - pvr->hue = tv_param_hue; - - if (tv_param_saturation) - pvr->saturation = tv_param_saturation; - - if (tv_param_width) - pvr->width = tv_param_width; - - if (tv_param_height) - pvr->height = tv_param_height; - - if (tv_param_freq) - pvr->freq = strdup (tv_param_freq); -} - -static int -set_v4l2_settings (struct pvr_t *pvr) -{ - if (!pvr) - return -1; - - if (pvr->dev_fd < 0) - return -1; - - /* -tv noaudio */ - if (pvr->mute) - { - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't mute (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - } - - /* -tv input=x */ - if (pvr->input != 0) - { - if (ioctl (pvr->dev_fd, VIDIOC_S_INPUT, &pvr->input) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set input (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - } - - /* -tv normid=x */ - if (pvr->normid != -1) - { - struct v4l2_standard std; - std.index = pvr->normid; - - if (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &std) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - - mp_msg (MSGT_OPEN, MSGL_V, - "%s set norm to %s\n", LOG_LEVEL_V4L2, std.name); - - if (ioctl (pvr->dev_fd, VIDIOC_S_STD, &std.id) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - } - - /* -tv brightness=x */ - if (pvr->brightness != 0) - { - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_BRIGHTNESS; - ctrl.value = pvr->brightness; - - if (ctrl.value < 0) - ctrl.value = 0; - if (ctrl.value > 255) - ctrl.value = 255; - - if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set brightness to %d (%s).\n", - LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); - return -1; - } - } - - /* -tv contrast=x */ - if (pvr->contrast != 0) - { - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_CONTRAST; - ctrl.value = pvr->contrast; - - if (ctrl.value < 0) - ctrl.value = 0; - if (ctrl.value > 127) - ctrl.value = 127; - - if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set contrast to %d (%s).\n", - LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); - return -1; - } - } - - /* -tv hue=x */ - if (pvr->hue != 0) - { - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_HUE; - ctrl.value = pvr->hue; - - if (ctrl.value < -128) - ctrl.value = -128; - if (ctrl.value > 127) - ctrl.value = 127; - - if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set hue to %d (%s).\n", - LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); - return -1; - } - } - - /* -tv saturation=x */ - if (pvr->saturation != 0) - { - struct v4l2_control ctrl; - ctrl.id = V4L2_CID_SATURATION; - ctrl.value = pvr->saturation; - - if (ctrl.value < 0) - ctrl.value = 0; - if (ctrl.value > 127) - ctrl.value = 127; - - if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set saturation to %d (%s).\n", - LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); - return -1; - } - } - - /* -tv width=x:height=y */ - if (pvr->width && pvr->height) - { - struct v4l2_format vfmt; - vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vfmt.fmt.pix.width = pvr->width; - vfmt.fmt.pix.height = pvr->height; - - if (ioctl (pvr->dev_fd, VIDIOC_S_FMT, &vfmt) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set resolution to %dx%d (%s).\n", - LOG_LEVEL_V4L2, pvr->width, pvr->height, strerror (errno)); - return -1; - } - } - - /* -tv freq=x */ - if (pvr->freq) - { - struct v4l2_frequency vf; - vf.tuner = 0; - vf.type = 0; - vf.frequency = strtol (pvr->freq, 0L, 0); - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s setting frequency to %d\n", LOG_LEVEL_V4L2, vf.frequency); - - if (ioctl (pvr->dev_fd, VIDIOC_S_FREQUENCY, &vf) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set frequency (%s).\n", - LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - } - - return 0; -} - -static int -v4l2_list_capabilities (struct pvr_t *pvr) -{ - struct v4l2_audio vaudio; - struct v4l2_standard vs; - struct v4l2_input vin; - int err = 0; - - if (!pvr) - return -1; - - if (pvr->dev_fd < 0) - return -1; - - /* list available video inputs */ - vin.index = 0; - err = 1; - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Available video inputs: ", LOG_LEVEL_V4L2); - while (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) >= 0) - { - err = 0; - mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vin.index, vin.name); - vin.index++; - } - if (err) - { - mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); - return -1; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); - - /* list available audio inputs */ - vaudio.index = 0; - err = 1; - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Available audio inputs: ", LOG_LEVEL_V4L2); - while (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) >= 0) - { - err = 0; - mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vaudio.index, vaudio.name); - vaudio.index++; - } - if (err) - { - mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); - return -1; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); - - /* list available norms */ - vs.index = 0; - mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available norms: ", LOG_LEVEL_V4L2); - while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) - { - err = 0; - mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vs.index, vs.name); - vs.index++; - } - if (err) - { - mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); - return -1; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); - - return 0; -} - -static int -v4l2_display_settings (struct pvr_t *pvr) -{ - struct v4l2_audio vaudio; - struct v4l2_standard vs; - struct v4l2_input vin; - v4l2_std_id std; - int input; - - if (!pvr) - return -1; - - if (pvr->dev_fd < 0) - return -1; - - /* get current video input */ - if (ioctl (pvr->dev_fd, VIDIOC_G_INPUT, &input) == 0) - { - vin.index = input; - if (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Video input: %s\n", LOG_LEVEL_V4L2, vin.name); - } - else - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - - /* get current audio input */ - if (ioctl (pvr->dev_fd, VIDIOC_G_AUDIO, &vaudio) == 0) - { - vaudio.index = input; - if (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Audio input: %s\n", LOG_LEVEL_V4L2, vaudio.name); - } - else - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - - /* get current video format */ - if (ioctl (pvr->dev_fd, VIDIOC_G_STD, &std) == 0) - { - vs.index = 0; - - while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) - { - if (vs.id == std) - { - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Norm: %s.\n", LOG_LEVEL_V4L2, vs.name); - break; - } - vs.index++; - } - } - else - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); - return -1; - } - - return 0; -} - -/* stream layer */ - -static void -pvr_stream_close (stream_t *stream) -{ - struct pvr_t *pvr; - - if (!stream) - return; - - pvr = (struct pvr_t *) stream->priv; - pvr_uninit (pvr); -} - -static int -pvr_stream_read (stream_t *stream, char *buffer, int size) -{ - struct pollfd pfds[1]; - struct pvr_t *pvr; - int rk, fd, pos; - - if (!stream || !buffer) - return 0; - - pvr = (struct pvr_t *) stream->priv; - fd = pvr->dev_fd; - pos = 0; - - if (fd < 0) - return 0; - - while (pos < size) - { - pfds[0].fd = fd; - pfds[0].events = POLLIN | POLLPRI; - - rk = size - pos; - - if (poll (pfds, 1, 500) <= 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s failed with errno %d when reading %d bytes\n", - LOG_LEVEL_PVR, errno, size-pos); - break; - } - - rk = read (fd, &buffer[pos], rk); - if (rk > 0) - { - pos += rk; - mp_msg (MSGT_OPEN, MSGL_DBG3, - "%s read (%d) bytes\n", LOG_LEVEL_PVR, pos); - } - } - - if (!pos) - mp_msg (MSGT_OPEN, MSGL_ERR, "%s read %d bytes\n", LOG_LEVEL_PVR, pos); - - return pos; -} - -static int -pvr_stream_open (stream_t *stream, int mode, void *opts, int *file_format) -{ - struct ivtv_ioctl_codec codec; - struct ivtv_driver_info info; - struct v4l2_capability vcap; - struct pvr_t *pvr = NULL; - - if (mode != STREAM_READ) - return STREAM_UNSUPORTED; - - pvr = pvr_init (); - - parse_v4l2_tv_options (pvr); - parse_ivtv_options (pvr); - - /* open device */ - pvr->dev_fd = open (pvr->video_dev, O_RDWR); - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Using device %s\n", LOG_LEVEL_PVR, pvr->video_dev); - if (pvr->dev_fd == -1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s error opening device %s\n", LOG_LEVEL_PVR, pvr->video_dev); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - /* query capabilities (i.e test V4L2 support) */ - if (ioctl (pvr->dev_fd, VIDIOC_QUERYCAP, &vcap) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s device is not V4L2 compliant (%s).\n", - LOG_LEVEL_PVR, strerror (errno)); - pvr_uninit (pvr); - return STREAM_ERROR; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Detected %s\n", LOG_LEVEL_PVR, vcap.card); - - /* get codec and initialize card (i.e test IVTV support) */ - if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s device is not IVTV compliant (%s).\n", - LOG_LEVEL_PVR, strerror (errno)); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - /* get ivtv driver info */ - if (ioctl (pvr->dev_fd, IVTV_IOC_G_DRIVER_INFO, &info) < 0) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s device is not IVTV compliant (%s).\n", - LOG_LEVEL_PVR, strerror (errno)); - pvr_uninit (pvr); - return STREAM_ERROR; - } - else - mp_msg (MSGT_OPEN, MSGL_INFO, - "%s Detected ivtv driver: %s\n", LOG_LEVEL_PVR, info.comment); - - /* list V4L2 capabilities */ - if (v4l2_list_capabilities (pvr) == -1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get v4l2 capabilities\n", LOG_LEVEL_PVR); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - /* apply V4L2 settings */ - if (set_v4l2_settings (pvr) == -1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set v4l2 settings\n", LOG_LEVEL_PVR); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - /* apply IVTV settings */ - if (set_ivtv_settings (pvr) == -1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't set ivtv settings\n", LOG_LEVEL_PVR); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - /* display current V4L2 settings */ - if (v4l2_display_settings (pvr) == -1) - { - mp_msg (MSGT_OPEN, MSGL_ERR, - "%s can't get v4l2 settings\n", LOG_LEVEL_PVR); - pvr_uninit (pvr); - return STREAM_ERROR; - } - - stream->priv = pvr; - stream->type = STREAMTYPE_PVR; - stream->fill_buffer = pvr_stream_read; - stream->close = pvr_stream_close; - - return STREAM_OK; -} - -stream_info_t stream_info_pvr = { - "PVR (V4L2/IVTV) Input", - "pvr", - "Benjamin Zores", - "", - pvr_stream_open, - { "pvr", NULL }, - NULL, - 1 -};
--- a/libmpdemux/stream_rtsp.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2006 Benjamin Zores - * based on previous Real RTSP support from Roberto Togni and xine team. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/types.h> -#include <ctype.h> -#include "config.h" -#ifndef HAVE_WINSOCK2 -#include <netinet/in.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#define closesocket close -#else -#include <winsock2.h> -#include <ws2tcpip.h> -#endif -#include <errno.h> - -#include "stream.h" -#include "librtsp/rtsp.h" -#include "librtsp/rtsp_session.h" - -#define RTSP_DEFAULT_PORT 554 - -extern int network_bandwidth; - -static int -rtsp_streaming_read (int fd, char *buffer, - int size, streaming_ctrl_t *stream_ctrl) -{ - return rtsp_session_read (stream_ctrl->data, buffer, size); -} - -static int -rtsp_streaming_start (stream_t *stream) -{ - int fd; - rtsp_session_t *rtsp; - char *mrl; - char *file; - int port; - int redirected, temp; - - if (!stream) - return -1; - - /* counter so we don't get caught in infinite redirections */ - temp = 5; - - do { - redirected = 0; - - fd = connect2Server (stream->streaming_ctrl->url->hostname, - port = (stream->streaming_ctrl->url->port ? - stream->streaming_ctrl->url->port : - RTSP_DEFAULT_PORT), 1); - - if (fd < 0 && !stream->streaming_ctrl->url->port) - fd = connect2Server (stream->streaming_ctrl->url->hostname, - port = 7070, 1); - - if (fd < 0) - return -1; - - file = stream->streaming_ctrl->url->file; - if (file[0] == '/') - file++; - - mrl = malloc (strlen (stream->streaming_ctrl->url->hostname) - + strlen (file) + 16); - - sprintf (mrl, "rtsp://%s:%i/%s", - stream->streaming_ctrl->url->hostname, port, file); - - rtsp = rtsp_session_start (fd, &mrl, file, - stream->streaming_ctrl->url->hostname, - port, &redirected, - stream->streaming_ctrl->bandwidth); - - if (redirected == 1) - { - url_free (stream->streaming_ctrl->url); - stream->streaming_ctrl->url = url_new (mrl); - closesocket (fd); - } - - free (mrl); - temp--; - } while ((redirected != 0) && (temp > 0)); - - if (!rtsp) - return -1; - - stream->fd = fd; - stream->streaming_ctrl->data = rtsp; - - stream->streaming_ctrl->streaming_read = rtsp_streaming_read; - stream->streaming_ctrl->streaming_seek = NULL; - stream->streaming_ctrl->prebuffer_size = 128*1024; // 640 KBytes - stream->streaming_ctrl->buffering = 1; - stream->streaming_ctrl->status = streaming_playing_e; - - return 0; -} - -static void -rtsp_streaming_close (struct stream_st *s) -{ - rtsp_session_t *rtsp = NULL; - - rtsp = (rtsp_session_t *) s->streaming_ctrl->data; - if (rtsp) - rtsp_session_end (rtsp); -} - -static int -rtsp_streaming_open (stream_t *stream, int mode, void *opts, int *file_format) -{ - URL_t *url; - extern int index_mode; - - mp_msg (MSGT_OPEN, MSGL_INFO, "STREAM_RTSP, URL: %s\n", stream->url); - stream->streaming_ctrl = streaming_ctrl_new (); - if (!stream->streaming_ctrl) - return STREAM_ERROR; - - stream->streaming_ctrl->bandwidth = network_bandwidth; - url = url_new (stream->url); - stream->streaming_ctrl->url = check4proxies (url); - - stream->fd = -1; - index_mode = -1; /* prevent most RTSP streams from locking due to -idx */ - if (rtsp_streaming_start (stream) < 0) - { - streaming_ctrl_free (stream->streaming_ctrl); - stream->streaming_ctrl = NULL; - return STREAM_UNSUPORTED; - } - - fixup_network_stream_cache (stream); - stream->type = STREAMTYPE_STREAM; - stream->close = rtsp_streaming_close; - - return STREAM_OK; -} - -stream_info_t stream_info_rtsp = { - "RTSP streaming", - "rtsp", - "Benjamin Zores, Roberto Togni", - "ported from xine", - rtsp_streaming_open, - {"rtsp", NULL}, - NULL, - 0 /* Urls are an option string */ -};
--- a/libmpdemux/stream_smb.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ - -#include "config.h" - -#include <libsmbclient.h> -#include <unistd.h> - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -static struct stream_priv_s { -} stream_priv_dflts = { -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -// URL definition -static m_option_t stream_opts_fields[] = { - { NULL, NULL, 0, 0, 0, 0, NULL } -}; - -static struct m_struct_st stream_opts = { - "smb", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static char smb_password[15]; -static char smb_username[15]; - -static void smb_auth_fn(const char *server, const char *share, - char *workgroup, int wgmaxlen, char *username, int unmaxlen, - char *password, int pwmaxlen) -{ - char temp[128]; - - strcpy(temp, "LAN"); - if (temp[strlen(temp) - 1] == 0x0a) - temp[strlen(temp) - 1] = 0x00; - - if (temp[0]) strncpy(workgroup, temp, wgmaxlen - 1); - - strcpy(temp, smb_username); - if (temp[strlen(temp) - 1] == 0x0a) - temp[strlen(temp) - 1] = 0x00; - - if (temp[0]) strncpy(username, temp, unmaxlen - 1); - - strcpy(temp, smb_password); - if (temp[strlen(temp) - 1] == 0x0a) - temp[strlen(temp) - 1] = 0x00; - - if (temp[0]) strncpy(password, temp, pwmaxlen - 1); -} - -static int seek(stream_t *s,off_t newpos) { - s->pos = newpos; - if(smbc_lseek(s->fd,s->pos,SEEK_SET)<0) { - s->eof=1; - return 0; - } - return 1; -} - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - int r = smbc_read(s->fd,buffer,max_len); - return (r <= 0) ? -1 : r; -} - -static int write_buffer(stream_t *s, char* buffer, int len) { - int r = smbc_write(s->fd,buffer,len); - return (r <= 0) ? -1 : r; -} - -static void close_f(stream_t *s){ - smbc_close(s->fd); -} - -static int open_f (stream_t *stream, int mode, void *opts, int* file_format) { - struct stream_priv_s *p = (struct stream_priv_s*)opts; - char *filename; - mode_t m = 0; - off_t len; - int fd, err; - - filename = stream->url; - - if(mode == STREAM_READ) - m = O_RDONLY; - else if (mode == STREAM_WRITE) //who's gonna do that ? - m = O_WRONLY; - else { - mp_msg(MSGT_OPEN, MSGL_ERR, "[smb] Unknown open mode %d\n", mode); - m_struct_free (&stream_opts, opts); - return STREAM_UNSUPORTED; - } - - if(!filename) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[smb] Bad url\n"); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - err = smbc_init(smb_auth_fn, 1); - if (err < 0) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_SMBInitError,err); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - fd = smbc_open(filename, m,0644); - if (fd < 0) { - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_SMBFileNotFound, filename); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - len = smbc_lseek(fd,0,SEEK_END); - smbc_lseek (fd, 0, SEEK_SET); - if (len <= 0) - stream->flags = 0; - else { - stream->flags = STREAM_READ | STREAM_SEEK; - stream->end_pos = len; - stream->seek = seek; - } - stream->type = STREAMTYPE_SMB; - stream->fd = fd; - stream->fill_buffer = fill_buffer; - stream->write_buffer = write_buffer; - stream->close = close_f; - - m_struct_free(&stream_opts, opts); - return STREAM_OK; -} - -stream_info_t stream_info_smb = { - "Server Message Block", - "smb", - "M. Tourne", - "based on the code from 'a bulgarian' (one says)", - open_f, - {"smb", NULL}, - &stream_opts, - 0 //Url is an option string -};
--- a/libmpdemux/stream_vcd.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ - -#include "config.h" - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <errno.h> - -#if defined(__FreeBSD__) || defined(__DragonFly__) -#include <sys/cdrio.h> -#include "vcd_read_fbsd.h" -#elif defined(__NetBSD__) || defined (__OpenBSD__) -#include "vcd_read_nbsd.h" -#elif defined(SYS_DARWIN) -#include "vcd_read_darwin.h" -#else -#include "vcd_read.h" -#endif - -extern char *cdrom_device; - -static struct stream_priv_s { - int track; - char* device; -} stream_priv_dflts = { - 1, - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - { "track", ST_OFF(track), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, - { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - /// For url parsing - { "hostname", ST_OFF(track), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, - { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static struct m_struct_st stream_opts = { - "vcd", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - if(s->pos > s->end_pos) /// don't past end of current track - return 0; - return vcd_read(s->priv,buffer); -} - -static int seek(stream_t *s,off_t newpos) { - s->pos = newpos; - vcd_set_msf(s->priv,s->pos/VCD_SECTOR_DATA); - return 1; -} - -static void close_s(stream_t *stream) { - free(stream->priv); -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - struct stream_priv_s* p = (struct stream_priv_s*)opts; - int ret,ret2,f; - mp_vcd_priv_t* vcd; -#ifdef __FreeBSD__ - int bsize = VCD_SECTOR_SIZE; -#endif - - if(mode != STREAM_READ) { - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPORTED; - } - - if (!p->device) { - if(cdrom_device) - p->device = strdup(cdrom_device); - else - p->device = strdup(DEFAULT_CDROM_DEVICE); - } - - f=open(p->device,O_RDONLY); - if(f<0){ - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CdDevNotfound,p->device); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - vcd = vcd_read_toc(f); - if(!vcd) { - mp_msg(MSGT_OPEN,MSGL_ERR,"Failed to get cd toc\n"); - close(f); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - ret2=vcd_get_track_end(vcd,p->track); - if(ret2<0){ - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (get)\n"); - close(f); - free(vcd); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - ret=vcd_seek_to_track(vcd,p->track); - if(ret<0){ - mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n"); - close(f); - free(vcd); - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - mp_msg(MSGT_OPEN,MSGL_V,"VCD start byte position: 0x%X end: 0x%X\n",ret,ret2); - -#ifdef __FreeBSD__ - if (ioctl (f, CDRIOCSETBLOCKSIZE, &bsize) == -1) { - mp_msg(MSGT_OPEN,MSGL_WARN,"Error in CDRIOCSETBLOCKSIZE"); - } -#endif - - stream->fd = f; - stream->type = STREAMTYPE_VCD; - stream->sector_size = VCD_SECTOR_DATA; - stream->start_pos=ret; - stream->end_pos=ret2; - stream->priv = vcd; - - stream->fill_buffer = fill_buffer; - stream->seek = seek; - stream->close = close_s; - - m_struct_free(&stream_opts,opts); - return STREAM_OK; -} - -stream_info_t stream_info_vcd = { - "Video CD", - "vcd", - "Albeu", - "based on the code from ???", - open_s, - { "vcd", NULL }, - &stream_opts, - 1 // Urls are an option string -};
--- a/libmpdemux/stream_vstream.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ -/* - * stream_vstream.c - * - * Copyright (C) Joey Parrish - * - * This file is part of MPlayer, a free movie player. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -/* - * If you have a tivo with the vstream server installed, (and most tivo - * hackers do,) then you can connect to it and stream ty files using - * this module. The url syntax is tivo://host/fsid or tivo://host/list - * to list the available recordings and their fsid's. - * This module depends on libvstream-client, which is available from - * http://armory.nicewarrior.org/projects/vstream-client . - * - */ - - -#include "config.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdarg.h> - -#include <stdlib.h> -#include <stdio.h> -#include <inttypes.h> -#include <errno.h> - -#include "mp_msg.h" -#include "stream.h" -#include "help_mp.h" -#include "m_option.h" -#include "m_struct.h" - -#include <vstream-client.h> - -void vstream_error(const char *format, ...) { - char buf[1024]; - va_list va; - va_start(va, format); - vsnprintf(buf, 1024, format, va); - va_end(va); - mp_msg(MSGT_STREAM, MSGL_ERR, buf); -} - -static struct stream_priv_s { - char* host; - char* fsid; -} stream_priv_dflts = { - NULL, - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static m_option_t stream_opts_fields[] = { - {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"filename", ST_OFF(fsid), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; - -static struct m_struct_st stream_opts = { - "vstream", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - struct stream_priv_s* p = (struct stream_priv_s*)s->priv; - int len = vstream_load_chunk(p->fsid, buffer, max_len, s->pos); - if (len <= 0) return 0; - return len; -} - -static int seek(stream_t *s,off_t newpos) { - s->pos = newpos; - return 1; -} - -static int control(struct stream_st *s,int cmd,void* arg) { - return STREAM_UNSUPORTED; -} - -static void close_s(struct stream_st *s) { -} - -static int open_s(stream_t *stream, int mode, void* opts, int* file_format) { - int f; - struct stream_priv_s* p = (struct stream_priv_s*)opts; - - if(mode != STREAM_READ) - return STREAM_UNSUPORTED; - - if(!p->host) { - mp_msg(MSGT_OPEN, MSGL_ERR, "We need a host name (ex: tivo://hostname/fsid)\n"); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - if(!p->fsid || strlen(p->fsid) == 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, "We need an fsid (ex: tivo://hostname/fsid)\n"); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - f = connect2Server(p->host, VSERVER_PORT, 1); - - if(f < 0) { - mp_msg(MSGT_OPEN, MSGL_ERR, "Connection to %s failed\n", p->host); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - stream->fd = f; - - vstream_set_socket_fd(f); - - if (!strcmp(p->fsid, "list")) { - vstream_list_streams(0); - return STREAM_ERROR; - } else if (!strcmp(p->fsid, "llist")) { - vstream_list_streams(1); - return STREAM_ERROR; - } - - if (vstream_start()) { - mp_msg(MSGT_OPEN, MSGL_ERR, "Cryptic internal error #1\n"); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - if (vstream_startstream(p->fsid)) { - mp_msg(MSGT_OPEN, MSGL_ERR, "Cryptic internal error #2\n"); - m_struct_free(&stream_opts, opts); - return STREAM_ERROR; - } - - stream->start_pos = 0; - stream->end_pos = vstream_streamsize(); - mp_msg(MSGT_OPEN, MSGL_DBG2, "Tivo stream size is %d\n", stream->end_pos); - - stream->priv = p; - stream->fill_buffer = fill_buffer; - stream->control = control; - stream->seek = seek; - stream->close = close_s; - stream->type = STREAMTYPE_VSTREAM; - - return STREAM_OK; -} - -stream_info_t stream_info_vstream = { - "vstream client", - "vstream", - "Joey", - "", - open_s, - { "tivo", NULL }, - &stream_opts, - 1 // Url is an option string -};
--- a/libmpdemux/tv.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,919 +0,0 @@ -/* - TV Interface for MPlayer - - (C) Alex Beregszaszi - - API idea based on libvo2 - - Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu) - to add support for audio, and bktr *BSD support. - -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <sys/time.h> - -#include "config.h" - -int tv_param_on = 0; - -#include "mp_msg.h" -#include "help_mp.h" - -#include "stream.h" -#include "demuxer.h" -#include "stheader.h" - -#include "libaf/af_format.h" -#include "libvo/img_format.h" -#include "libvo/fastmemcpy.h" - -#include "tv.h" - -#include "frequencies.h" - -/* some default values */ -int tv_param_audiorate = 44100; -int tv_param_noaudio = 0; -int tv_param_immediate = 0; -char *tv_param_freq = NULL; -char *tv_param_channel = NULL; -char *tv_param_norm = "pal"; -#ifdef HAVE_TV_V4L2 -int tv_param_normid = -1; -#endif -char *tv_param_chanlist = "europe-east"; -char *tv_param_device = NULL; -char *tv_param_driver = "dummy"; -int tv_param_width = -1; -int tv_param_height = -1; -int tv_param_input = 0; /* used in v4l and bttv */ -int tv_param_outfmt = -1; -float tv_param_fps = -1.0; -char **tv_param_channels = NULL; -int tv_param_audio_id = 0; -#if defined(HAVE_TV_V4L) -int tv_param_amode = -1; -int tv_param_volume = -1; -int tv_param_bass = -1; -int tv_param_treble = -1; -int tv_param_balance = -1; -int tv_param_forcechan = -1; -int tv_param_force_audio = 0; -int tv_param_buffer_size = -1; -int tv_param_mjpeg = 0; -int tv_param_decimation = 2; -int tv_param_quality = 90; -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) -int tv_param_alsa = 0; -#endif -char* tv_param_adevice = NULL; -#endif -int tv_param_brightness = 0; -int tv_param_contrast = 0; -int tv_param_hue = 0; -int tv_param_saturation = 0; -tv_channels_t *tv_channel_list; -tv_channels_t *tv_channel_current, *tv_channel_last; -char *tv_channel_last_real; - -/* ================== DEMUX_TV ===================== */ -/* - Return value: - 0 = EOF(?) or no stream - 1 = successfully read a packet -*/ -/* fill demux->video and demux->audio */ - -static int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds) -{ - tvi_handle_t *tvh=(tvi_handle_t*)(demux->priv); - demux_packet_t* dp; - unsigned int len=0; - - /* ================== ADD AUDIO PACKET =================== */ - - if (ds==demux->audio && tv_param_noaudio == 0 && - tvh->functions->control(tvh->priv, - TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) - { - len = tvh->functions->get_audio_framesize(tvh->priv); - - dp=new_demux_packet(len); - dp->flags|=1; /* Keyframe */ - dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len); - ds_add_packet(demux->audio,dp); - } - - /* ================== ADD VIDEO PACKET =================== */ - - if (ds==demux->video && tvh->functions->control(tvh->priv, - TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE) - { - len = tvh->functions->get_video_framesize(tvh->priv); - dp=new_demux_packet(len); - dp->flags|=1; /* Keyframe */ - dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len); - ds_add_packet(demux->video,dp); - } - - return 1; -} - -static int norm_from_string(tvi_handle_t *tvh, char* norm) -{ -#ifdef HAVE_TV_V4L2 - if (strcmp(tv_param_driver, "v4l2") != 0) { -#endif - if (!strcasecmp(norm, "pal")) - return TV_NORM_PAL; - else if (!strcasecmp(norm, "ntsc")) - return TV_NORM_NTSC; - else if (!strcasecmp(norm, "secam")) - return TV_NORM_SECAM; - else if (!strcasecmp(norm, "palnc")) - return TV_NORM_PALNC; - else if (!strcasecmp(norm, "palm")) - return TV_NORM_PALM; - else if (!strcasecmp(norm, "paln")) - return TV_NORM_PALN; - else if (!strcasecmp(norm, "ntscjp")) - return TV_NORM_NTSCJP; - else { - mp_msg(MSGT_TV, MSGL_V, "tv.c: norm_from_string(%s): Bogus norm parameter, setting PAL.\n", norm); - return TV_NORM_PAL; - } -#ifdef HAVE_TV_V4L2 - } else { - tvi_functions_t *funcs = tvh->functions; - char str[8]; - strncpy(str, norm, sizeof(str)-1); - str[sizeof(str)-1] = '\0'; - if (funcs->control(tvh->priv, TVI_CONTROL_SPC_GET_NORMID, str) != TVI_CONTROL_TRUE) - return 0; - return *(int *)str; - } -#endif -} - -static int open_tv(tvi_handle_t *tvh) -{ - int i; - tvi_functions_t *funcs = tvh->functions; - int tv_fmt_list[] = { - IMGFMT_YV12, - IMGFMT_I420, - IMGFMT_UYVY, - IMGFMT_YUY2, - IMGFMT_RGB32, - IMGFMT_RGB24, - IMGFMT_RGB16, - IMGFMT_RGB15 - }; - - if (funcs->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) != TVI_CONTROL_TRUE) - { - mp_msg(MSGT_TV, MSGL_ERR, "Error: No video input present!\n"); - return 0; - } - - if (tv_param_outfmt == -1) - for (i = 0; i < sizeof (tv_fmt_list) / sizeof (*tv_fmt_list); i++) - { - tv_param_outfmt = tv_fmt_list[i]; - if (funcs->control (tvh->priv, TVI_CONTROL_VID_SET_FORMAT, - &tv_param_outfmt) == TVI_CONTROL_TRUE) - break; - } - else - { - switch(tv_param_outfmt) - { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_UYVY: - case IMGFMT_YUY2: - case IMGFMT_RGB32: - case IMGFMT_RGB24: - case IMGFMT_BGR32: - case IMGFMT_BGR24: - case IMGFMT_BGR16: - case IMGFMT_BGR15: - break; - default: - mp_msg(MSGT_TV, MSGL_ERR, "==================================================================\n"); - mp_msg(MSGT_TV, MSGL_ERR, " WARNING: UNTESTED OR UNKNOWN OUTPUT IMAGE FORMAT REQUESTED (0x%x)\n", tv_param_outfmt); - mp_msg(MSGT_TV, MSGL_ERR, " This may cause buggy playback or program crash! Bug reports will\n"); - mp_msg(MSGT_TV, MSGL_ERR, " be ignored! You should try again with YV12 (which is the default\n"); - mp_msg(MSGT_TV, MSGL_ERR, " colorspace) and read the documentation!\n"); - mp_msg(MSGT_TV, MSGL_ERR, "==================================================================\n"); - } - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_FORMAT, &tv_param_outfmt); - } - - /* set some params got from cmdline */ - funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tv_param_input); - -#ifdef HAVE_TV_V4L2 - if (!strcmp(tv_param_driver, "v4l2") && tv_param_normid >= 0) { - mp_msg(MSGT_TV, MSGL_V, "Selected norm id: %d\n", tv_param_normid); - if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tv_param_normid) != TVI_CONTROL_TRUE) { - mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); - } - } else { -#endif - /* select video norm */ - tvh->norm = norm_from_string(tvh, tv_param_norm); - - mp_msg(MSGT_TV, MSGL_V, "Selected norm: %s\n", tv_param_norm); - if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { - mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); - } -#ifdef HAVE_TV_V4L2 - } -#endif - -#ifdef HAVE_TV_V4L1 - if ( tv_param_mjpeg ) - { - /* set width to expected value */ - if (tv_param_width == -1) - { - tv_param_width = 704/tv_param_decimation; - } - if (tv_param_height == -1) - { - if ( tvh->norm != TV_NORM_NTSC ) - tv_param_height = 576/tv_param_decimation; - else - tv_param_height = 480/tv_param_decimation; - } - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: width %d height %d\n", tv_param_width, tv_param_height); - } -#endif - - /* limits on w&h are norm-dependent -- JM */ - /* set width */ - if (tv_param_width != -1) - { - if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_WIDTH, &tv_param_width) == TVI_CONTROL_TRUE) - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH, &tv_param_width); - else - { - mp_msg(MSGT_TV, MSGL_ERR, "Unable to set requested width: %d\n", tv_param_width); - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &tv_param_width); - } - } - - /* set height */ - if (tv_param_height != -1) - { - if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_HEIGHT, &tv_param_height) == TVI_CONTROL_TRUE) - funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HEIGHT, &tv_param_height); - else - { - mp_msg(MSGT_TV, MSGL_ERR, "Unable to set requested height: %d\n", tv_param_height); - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &tv_param_height); - } - } - - if (funcs->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE) - { - mp_msg(MSGT_TV, MSGL_WARN, "Selected input hasn't got a tuner!\n"); - goto done; - } - - /* select channel list */ - for (i = 0; chanlists[i].name != NULL; i++) - { - if (!strcasecmp(chanlists[i].name, tv_param_chanlist)) - { - tvh->chanlist = i; - tvh->chanlist_s = chanlists[i].list; - break; - } - } - - if (tvh->chanlist == -1) - mp_msg(MSGT_TV, MSGL_WARN, "Unable to find selected channel list! (%s)\n", - tv_param_chanlist); - else - mp_msg(MSGT_TV, MSGL_V, "Selected channel list: %s (including %d channels)\n", - chanlists[tvh->chanlist].name, chanlists[tvh->chanlist].count); - - if (tv_param_freq && tv_param_channel) - { - mp_msg(MSGT_TV, MSGL_WARN, "You can't set frequency and channel simultaneously!\n"); - goto done; - } - - /* Handle channel names */ - if (tv_param_channels) { - char** channels = tv_param_channels; - mp_msg(MSGT_TV, MSGL_INFO, "TV channel names detected.\n"); - tv_channel_list = malloc(sizeof(tv_channels_t)); - tv_channel_list->index=1; - tv_channel_list->next=NULL; - tv_channel_list->prev=NULL; - tv_channel_current = tv_channel_list; - - while (*channels) { - char* tmp = *(channels++); - char* sep = strchr(tmp,'-'); - int i; - struct CHANLIST cl; - - if (!sep) continue; // Wrong syntax, but mplayer should not crash - - strlcpy(tv_channel_current->name, sep + 1, - sizeof(tv_channel_current->name)); - sep[0] = '\0'; - strncpy(tv_channel_current->number, tmp, 5); - - while ((sep=strchr(tv_channel_current->name, '_'))) - sep[0] = ' '; - - tv_channel_current->freq = 0; - for (i = 0; i < chanlists[tvh->chanlist].count; i++) { - cl = tvh->chanlist_s[i]; - if (!strcasecmp(cl.name, tv_channel_current->number)) { - tv_channel_current->freq=cl.freq; - break; - } - } - if (tv_channel_current->freq == 0) - mp_msg(MSGT_TV, MSGL_ERR, "Couldn't find frequency for channel %s (%s)\n", - tv_channel_current->number, tv_channel_current->name); - else { - sep = strchr(tv_channel_current->name, '-'); - if ( !sep ) sep = strchr(tv_channel_current->name, '+'); - - if ( sep ) { - i = atoi (sep+1); - if ( sep[0] == '+' ) tv_channel_current->freq += i * 100; - if ( sep[0] == '-' ) tv_channel_current->freq -= i * 100; - sep[0] = '\0'; - } - } - - /*mp_msg(MSGT_TV, MSGL_INFO, "-- Detected channel %s - %s (%5.3f)\n", - tv_channel_current->number, tv_channel_current->name, - (float)tv_channel_current->freq/1000);*/ - - tv_channel_current->next = malloc(sizeof(tv_channels_t)); - tv_channel_current->next->index = tv_channel_current->index + 1; - tv_channel_current->next->prev = tv_channel_current; - tv_channel_current->next->next = NULL; - tv_channel_current = tv_channel_current->next; - } - if (tv_channel_current->prev) - tv_channel_current->prev->next = NULL; - free(tv_channel_current); - } else - tv_channel_last_real = malloc(5); - - if (tv_channel_list) { - int i; - int channel = 0; - if (tv_param_channel) - { - if (isdigit(*tv_param_channel)) - /* if tv_param_channel begins with a digit interpret it as a number */ - channel = atoi(tv_param_channel); - else - { - /* if tv_param_channel does not begin with a digit - set the first channel that contains tv_param_channel in its name */ - - tv_channel_current = tv_channel_list; - while ( tv_channel_current ) { - if ( strstr(tv_channel_current->name, tv_param_channel) ) - break; - tv_channel_current = tv_channel_current->next; - } - if ( !tv_channel_current ) tv_channel_current = tv_channel_list; - } - } - else - channel = 1; - - if ( channel ) { - tv_channel_current = tv_channel_list; - for (i = 1; i < channel; i++) - if (tv_channel_current->next) - tv_channel_current = tv_channel_current->next; - } - - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, - tv_channel_current->name, (float)tv_channel_current->freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); - tv_channel_last = tv_channel_current; - } else { - /* we need to set frequency */ - if (tv_param_freq) - { - unsigned long freq = atof(tv_param_freq)*16; - - /* set freq in MHz */ - funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); - - funcs->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); - mp_msg(MSGT_TV, MSGL_V, "Selected frequency: %lu (%.3f)\n", - freq, (float)freq/16); - } - - if (tv_param_channel) { - struct CHANLIST cl; - - mp_msg(MSGT_TV, MSGL_V, "Requested channel: %s\n", tv_param_channel); - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; - // printf("count%d: name: %s, freq: %d\n", - // i, cl.name, cl.freq); - if (!strcasecmp(cl.name, tv_param_channel)) - { - strcpy(tv_channel_last_real, cl.name); - tvh->channel = i; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", - cl.name, (float)cl.freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); - break; - } - } - } - } - - /* grep frequency in chanlist */ - { - unsigned long i2; - int freq; - - tv_get_freq(tvh, &i2); - - freq = (int) (((float)(i2/16))*1000)+250; - - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - if (tvh->chanlist_s[i].freq == freq) - { - tvh->channel = i+1; - break; - } - } - } - -done: - /* also start device! */ - return 1; -} - -static demuxer_t* demux_open_tv(demuxer_t *demuxer) -{ - tvi_handle_t *tvh; - sh_video_t *sh_video; - sh_audio_t *sh_audio = NULL; - tvi_functions_t *funcs; - - if(!(tvh=tv_begin())) return NULL; - if (!tv_init(tvh)) return NULL; - if (!open_tv(tvh)){ - tv_uninit(tvh); - return NULL; - } - funcs = tvh->functions; - demuxer->priv=tvh; - - sh_video = new_sh_video(demuxer, 0); - - /* get IMAGE FORMAT */ - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &sh_video->format); -// if (IMGFMT_IS_RGB(sh_video->format) || IMGFMT_IS_BGR(sh_video->format)) -// sh_video->format = 0x0; - - /* set FPS and FRAMETIME */ - - if(!sh_video->fps) - { - float tmp; - if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE) - sh_video->fps = 25.0f; /* on PAL */ - else sh_video->fps = tmp; - } - - if (tv_param_fps != -1.0f) - sh_video->fps = tv_param_fps; - - sh_video->frametime = 1.0f/sh_video->fps; - - /* If playback only mode, go to immediate mode, fail silently */ - if(tv_param_immediate == 1) - { - funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0); - tv_param_noaudio = 1; - } - - /* disable TV audio if -nosound is present */ - if (!demuxer->audio || demuxer->audio->id == -2) { - tv_param_noaudio = 1; - } - - /* set width */ - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w); - - /* set height */ - funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h); - - demuxer->video->sh = sh_video; - sh_video->ds = demuxer->video; - demuxer->video->id = 0; - demuxer->seekable = 0; - - /* here comes audio init */ - if (tv_param_noaudio == 0 && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) - { - int audio_format; - int sh_audio_format; - char buf[128]; - - /* yeah, audio is present */ - - funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, - &tv_param_audiorate); - - if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE) - goto no_audio; - - switch(audio_format) - { - case AF_FORMAT_U8: - case AF_FORMAT_S8: - case AF_FORMAT_U16_LE: - case AF_FORMAT_U16_BE: - case AF_FORMAT_S16_LE: - case AF_FORMAT_S16_BE: - case AF_FORMAT_S32_LE: - case AF_FORMAT_S32_BE: - sh_audio_format = 0x1; /* PCM */ - break; - case AF_FORMAT_IMA_ADPCM: - case AF_FORMAT_MU_LAW: - case AF_FORMAT_A_LAW: - case AF_FORMAT_MPEG2: - case AF_FORMAT_AC3: - default: - mp_msg(MSGT_TV, MSGL_ERR, "Audio type '%s (%x)' unsupported!\n", - af_fmt2str(audio_format, buf, 128), audio_format); - goto no_audio; - } - - sh_audio = new_sh_audio(demuxer, 0); - - funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, - &sh_audio->samplerate); - funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE, - &sh_audio->samplesize); - funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, - &sh_audio->channels); - - sh_audio->format = sh_audio_format; - sh_audio->sample_format = audio_format; - - sh_audio->i_bps = sh_audio->o_bps = - sh_audio->samplerate * sh_audio->samplesize * - sh_audio->channels; - - // emulate WF for win32 codecs: - sh_audio->wf = malloc(sizeof(WAVEFORMATEX)); - sh_audio->wf->wFormatTag = sh_audio->format; - sh_audio->wf->nChannels = sh_audio->channels; - sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8; - sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; - sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels; - sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps; - - mp_msg(MSGT_DECVIDEO, MSGL_V, " TV audio: %d channels, %d bits, %d Hz\n", - sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample, - sh_audio->wf->nSamplesPerSec); - - demuxer->audio->sh = sh_audio; - sh_audio->ds = demuxer->audio; - demuxer->audio->id = 0; - } -no_audio: - - if(!(funcs->start(tvh->priv))){ - // start failed :( - tv_uninit(tvh); - return NULL; - } - - /* set color eq */ - tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tv_param_brightness); - tv_set_color_options(tvh, TV_COLOR_HUE, tv_param_hue); - tv_set_color_options(tvh, TV_COLOR_SATURATION, tv_param_saturation); - tv_set_color_options(tvh, TV_COLOR_CONTRAST, tv_param_contrast); - - return demuxer; -} - -static void demux_close_tv(demuxer_t *demuxer) -{ - tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv); - tvh->functions->uninit(tvh->priv); -} - -/* ================== STREAM_TV ===================== */ -tvi_handle_t *tvi_init_dummy(char *device); -tvi_handle_t *tvi_init_v4l(char *device, char *adevice); -tvi_handle_t *tvi_init_v4l2(char *device, char *adevice); -tvi_handle_t *tvi_init_bsdbt848(char *device); - -tvi_handle_t *tv_begin(void) -{ - if (!strcmp(tv_param_driver, "dummy")) - return tvi_init_dummy(tv_param_device); -#ifdef HAVE_TV_V4L1 - if (!strcmp(tv_param_driver, "v4l")) - return tvi_init_v4l(tv_param_device, tv_param_adevice); -#endif -#ifdef HAVE_TV_V4L2 - if (!strcmp(tv_param_driver, "v4l2")) - return tvi_init_v4l2(tv_param_device, tv_param_adevice); -#endif -#ifdef HAVE_TV_BSDBT848 - if (!strcmp(tv_param_driver, "bsdbt848")) - return tvi_init_bsdbt848(tv_param_device); -#endif - - mp_msg(MSGT_TV, MSGL_ERR, "No such driver: %s\n", tv_param_driver); - return(NULL); -} - -int tv_init(tvi_handle_t *tvh) -{ - mp_msg(MSGT_TV, MSGL_INFO, "Selected driver: %s\n", tvh->info->short_name); - mp_msg(MSGT_TV, MSGL_INFO, " name: %s\n", tvh->info->name); - mp_msg(MSGT_TV, MSGL_INFO, " author: %s\n", tvh->info->author); - if (tvh->info->comment) - mp_msg(MSGT_TV, MSGL_INFO, " comment: %s\n", tvh->info->comment); - - return(tvh->functions->init(tvh->priv)); -} - -int tv_uninit(tvi_handle_t *tvh) -{ - return(tvh->functions->uninit(tvh->priv)); -} - -/* utilities for mplayer (not mencoder!!) */ -int tv_set_color_options(tvi_handle_t *tvh, int opt, int value) -{ - tvi_functions_t *funcs = tvh->functions; - - switch(opt) - { - case TV_COLOR_BRIGHTNESS: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_BRIGHTNESS, &value); - case TV_COLOR_HUE: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HUE, &value); - case TV_COLOR_SATURATION: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_SATURATION, &value); - case TV_COLOR_CONTRAST: - return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_CONTRAST, &value); - default: - mp_msg(MSGT_TV, MSGL_WARN, "Unknown color option (%d) specified!\n", opt); - } - - return(TVI_CONTROL_UNKNOWN); -} - -int tv_get_color_options(tvi_handle_t *tvh, int opt, int* value) -{ - tvi_functions_t *funcs = tvh->functions; - - switch(opt) - { - case TV_COLOR_BRIGHTNESS: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_BRIGHTNESS, value); - case TV_COLOR_HUE: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HUE, value); - case TV_COLOR_SATURATION: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_SATURATION, value); - case TV_COLOR_CONTRAST: - return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_CONTRAST, value); - default: - mp_msg(MSGT_TV, MSGL_WARN, "Unknown color option (%d) specified!\n", opt); - } - - return(TVI_CONTROL_UNKNOWN); -} - -int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq) -{ - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) - { - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, freq); - mp_msg(MSGT_TV, MSGL_V, "Current frequency: %lu (%.3f)\n", - *freq, (float)*freq/16); - } - return(1); -} - -int tv_set_freq(tvi_handle_t *tvh, unsigned long freq) -{ - if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) - { -// unsigned long freq = atof(tv_param_freq)*16; - - /* set freq in MHz */ - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); - - tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); - mp_msg(MSGT_TV, MSGL_V, "Current frequency: %lu (%.3f)\n", - freq, (float)freq/16); - } - return(1); -} - -int tv_step_channel_real(tvi_handle_t *tvh, int direction) -{ - struct CHANLIST cl; - - if (direction == TV_CHANNEL_LOWER) - { - if (tvh->channel-1 >= 0) - { - strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - cl = tvh->chanlist_s[--tvh->channel]; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", - cl.name, (float)cl.freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); - } - } - - if (direction == TV_CHANNEL_HIGHER) - { - if (tvh->channel+1 < chanlists[tvh->chanlist].count) - { - strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - cl = tvh->chanlist_s[++tvh->channel]; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", - cl.name, (float)cl.freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); - } - } - return(1); -} - -int tv_step_channel(tvi_handle_t *tvh, int direction) { - if (tv_channel_list) { - if (direction == TV_CHANNEL_HIGHER) { - tv_channel_last = tv_channel_current; - if (tv_channel_current->next) - tv_channel_current = tv_channel_current->next; - else - tv_channel_current = tv_channel_list; - tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", - tv_channel_current->number, tv_channel_current->name, (float)tv_channel_current->freq/1000); - } - if (direction == TV_CHANNEL_LOWER) { - tv_channel_last = tv_channel_current; - if (tv_channel_current->prev) - tv_channel_current = tv_channel_current->prev; - else - while (tv_channel_current->next) - tv_channel_current = tv_channel_current->next; - tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", - tv_channel_current->number, tv_channel_current->name, (float)tv_channel_current->freq/1000); - } - } else tv_step_channel_real(tvh, direction); - return(1); -} - -int tv_set_channel_real(tvi_handle_t *tvh, char *channel) { - int i; - struct CHANLIST cl; - - strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; -// printf("count%d: name: %s, freq: %d\n", -// i, cl.name, cl.freq); - if (!strcasecmp(cl.name, channel)) - { - tvh->channel = i; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", - cl.name, (float)cl.freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); - break; - } - } - return(1); -} - -int tv_set_channel(tvi_handle_t *tvh, char *channel) { - int i, channel_int; - - if (tv_channel_list) { - tv_channel_last = tv_channel_current; - channel_int = atoi(channel); - tv_channel_current = tv_channel_list; - for (i = 1; i < channel_int; i++) - if (tv_channel_current->next) - tv_channel_current = tv_channel_current->next; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, - tv_channel_current->name, (float)tv_channel_current->freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); - } else tv_set_channel_real(tvh, channel); - return(1); -} - -int tv_last_channel(tvi_handle_t *tvh) { - - if (tv_channel_list) { - tv_channels_t *tmp; - - tmp = tv_channel_last; - tv_channel_last = tv_channel_current; - tv_channel_current = tmp; - - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, - tv_channel_current->name, (float)tv_channel_current->freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); - } else { - int i; - struct CHANLIST cl; - - for (i = 0; i < chanlists[tvh->chanlist].count; i++) - { - cl = tvh->chanlist_s[i]; - if (!strcasecmp(cl.name, tv_channel_last_real)) - { - strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); - tvh->channel = i; - mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", - cl.name, (float)cl.freq/1000); - tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); - break; - } - } - } - return(1); -} - -int tv_step_norm(tvi_handle_t *tvh) -{ - tvh->norm++; - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, - &tvh->norm) != TVI_CONTROL_TRUE) { - tvh->norm = 0; - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, - &tvh->norm) != TVI_CONTROL_TRUE) { - mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); - return 0; - } - } - return(1); -} - -int tv_step_chanlist(tvi_handle_t *tvh) -{ - return(1); -} - -int tv_set_norm(tvi_handle_t *tvh, char* norm) -{ - tvh->norm = norm_from_string(tvh, norm); - - mp_msg(MSGT_TV, MSGL_V, "Selected norm: %s\n", tv_param_norm); - if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { - mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); - return 0; - } - return(1); -} - -demuxer_desc_t demuxer_desc_tv = { - "Tv card demuxer", - "tv", - "TV", - "Alex Beregszaszi, Charles R. Henrich", - "?", - DEMUXER_TYPE_TV, - 0, // no autodetect - NULL, - demux_tv_fill_buffer, - demux_open_tv, - demux_close_tv, - NULL, - NULL -};
--- a/libmpdemux/tv.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -#ifndef TV_H -#define TV_H - -extern int tv_param_on; - -#ifdef USE_TV -//#include "libao2/afmt.h" -//#include "libvo/img_format.h" -//#include "libvo/fastmemcpy.h" -//#include "mp_msg.h" - -extern char *tv_param_freq; -extern char *tv_param_channel; -extern char *tv_param_chanlist; -extern char *tv_param_norm; -#ifdef HAVE_TV_V4L2 -extern int tv_param_normid; -#endif -extern char *tv_param_device; -extern char *tv_param_driver; -extern int tv_param_width; -extern int tv_param_height; -extern int tv_param_input; -extern int tv_param_outfmt; -extern float tv_param_fps; -extern char **tv_param_channels; -extern int tv_param_noaudio; -extern int tv_param_immediate; -extern int tv_param_audiorate; -extern int tv_param_audio_id; -#if defined(HAVE_TV_V4L) -extern int tv_param_amode; -extern int tv_param_volume; -extern int tv_param_bass; -extern int tv_param_treble; -extern int tv_param_balance; -extern int tv_param_forcechan; -extern int tv_param_force_audio; -extern int tv_param_buffer_size; -extern int tv_param_mjpeg; -extern int tv_param_decimation; -extern int tv_param_quality; -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) -extern int tv_param_alsa; -#endif -extern char* tv_param_adevice; -#endif -extern int tv_param_brightness; -extern int tv_param_contrast; -extern int tv_param_hue; -extern int tv_param_saturation; - -typedef struct tvi_info_s -{ - const char *name; - const char *short_name; - const char *author; - const char *comment; -} tvi_info_t; - -typedef struct tvi_functions_s -{ - int (*init)(); - int (*uninit)(); - int (*control)(); - int (*start)(); - double (*grab_video_frame)(); -#ifdef HAVE_TV_BSDBT848 - double (*grabimmediate_video_frame)(); -#endif - int (*get_video_framesize)(); - double (*grab_audio_frame)(); - int (*get_audio_framesize)(); -} tvi_functions_t; - -typedef struct tvi_handle_s { - tvi_info_t *info; - tvi_functions_t *functions; - void *priv; - int seq; - - /* specific */ - int norm; - int chanlist; - const struct CHANLIST *chanlist_s; - int channel; -} tvi_handle_t; - -typedef struct tv_channels_s { - int index; - char number[5]; - char name[20]; - int freq; - struct tv_channels_s *next; - struct tv_channels_s *prev; -} tv_channels_t; - -extern tv_channels_t *tv_channel_list; -extern tv_channels_t *tv_channel_current, *tv_channel_last; -extern char *tv_channel_last_real; - -#define TVI_CONTROL_FALSE 0 -#define TVI_CONTROL_TRUE 1 -#define TVI_CONTROL_NA -1 -#define TVI_CONTROL_UNKNOWN -2 - -/* ======================== CONTROLS =========================== */ - -/* GENERIC controls */ -#define TVI_CONTROL_IS_AUDIO 0x1 -#define TVI_CONTROL_IS_VIDEO 0x2 -#define TVI_CONTROL_IS_TUNER 0x3 -#define TVI_CONTROL_IMMEDIATE 0x4 - -/* VIDEO controls */ -#define TVI_CONTROL_VID_GET_FPS 0x101 -#define TVI_CONTROL_VID_GET_PLANES 0x102 -#define TVI_CONTROL_VID_GET_BITS 0x103 -#define TVI_CONTROL_VID_CHK_BITS 0x104 -#define TVI_CONTROL_VID_SET_BITS 0x105 -#define TVI_CONTROL_VID_GET_FORMAT 0x106 -#define TVI_CONTROL_VID_CHK_FORMAT 0x107 -#define TVI_CONTROL_VID_SET_FORMAT 0x108 -#define TVI_CONTROL_VID_GET_WIDTH 0x109 -#define TVI_CONTROL_VID_CHK_WIDTH 0x110 -#define TVI_CONTROL_VID_SET_WIDTH 0x111 -#define TVI_CONTROL_VID_GET_HEIGHT 0x112 -#define TVI_CONTROL_VID_CHK_HEIGHT 0x113 -#define TVI_CONTROL_VID_SET_HEIGHT 0x114 -#define TVI_CONTROL_VID_GET_BRIGHTNESS 0x115 -#define TVI_CONTROL_VID_SET_BRIGHTNESS 0x116 -#define TVI_CONTROL_VID_GET_HUE 0x117 -#define TVI_CONTROL_VID_SET_HUE 0x118 -#define TVI_CONTROL_VID_GET_SATURATION 0x119 -#define TVI_CONTROL_VID_SET_SATURATION 0x11a -#define TVI_CONTROL_VID_GET_CONTRAST 0x11b -#define TVI_CONTROL_VID_SET_CONTRAST 0x11c -#define TVI_CONTROL_VID_GET_PICTURE 0x11d -#define TVI_CONTROL_VID_SET_PICTURE 0x11e - -/* TUNER controls */ -#define TVI_CONTROL_TUN_GET_FREQ 0x201 -#define TVI_CONTROL_TUN_SET_FREQ 0x202 -#define TVI_CONTROL_TUN_GET_TUNER 0x203 /* update priv->tuner struct for used input */ -#define TVI_CONTROL_TUN_SET_TUNER 0x204 /* update priv->tuner struct for used input */ -#define TVI_CONTROL_TUN_GET_NORM 0x205 -#define TVI_CONTROL_TUN_SET_NORM 0x206 - -/* AUDIO controls */ -#define TVI_CONTROL_AUD_GET_FORMAT 0x301 -#define TVI_CONTROL_AUD_GET_SAMPLERATE 0x302 -#define TVI_CONTROL_AUD_GET_SAMPLESIZE 0x303 -#define TVI_CONTROL_AUD_GET_CHANNELS 0x304 -#define TVI_CONTROL_AUD_SET_SAMPLERATE 0x305 - -/* SPECIFIC controls */ -#define TVI_CONTROL_SPC_GET_INPUT 0x401 /* set input channel (tv,s-video,composite..) */ -#define TVI_CONTROL_SPC_SET_INPUT 0x402 /* set input channel (tv,s-video,composite..) */ -#define TVI_CONTROL_SPC_GET_NORMID 0x403 /* get normid from norm name */ - -extern tvi_handle_t *tv_begin(void); -extern int tv_init(tvi_handle_t *tvh); -extern int tv_uninit(tvi_handle_t *tvh); - -int tv_set_color_options(tvi_handle_t *tvh, int opt, int val); -int tv_get_color_options(tvi_handle_t *tvh, int opt, int* val); -#define TV_COLOR_BRIGHTNESS 1 -#define TV_COLOR_HUE 2 -#define TV_COLOR_SATURATION 3 -#define TV_COLOR_CONTRAST 4 - -int tv_step_channel_real(tvi_handle_t *tvh, int direction); -int tv_step_channel(tvi_handle_t *tvh, int direction); -#define TV_CHANNEL_LOWER 1 -#define TV_CHANNEL_HIGHER 2 - -int tv_last_channel(tvi_handle_t *tvh); - -int tv_set_channel_real(tvi_handle_t *tvh, char *channel); -int tv_set_channel(tvi_handle_t *tvh, char *channel); - -int tv_step_norm(tvi_handle_t *tvh); -int tv_step_chanlist(tvi_handle_t *tvh); - -int tv_set_freq(tvi_handle_t *tvh, unsigned long freq); -int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq); - -int tv_set_norm(tvi_handle_t *tvh, char* norm); - -#define TV_NORM_PAL 1 -#define TV_NORM_NTSC 2 -#define TV_NORM_SECAM 3 -#define TV_NORM_PALNC 4 -#define TV_NORM_PALM 5 -#define TV_NORM_PALN 6 -#define TV_NORM_NTSCJP 7 - -#endif /* USE_TV */ - -#endif /* TV_H */
--- a/libmpdemux/tvi_bsdbt848.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,846 +0,0 @@ -/* - (C)2002 Charles R. Henrich (henrich@msu.edu) - *BSD (hopefully, requires working driver!) BrookTree capture support. - - Still in (active) development! - - v1.1 Mar 13 2002 Fully functional, need to move ring buffer to - the kernel driver. - v1.0 Feb 19 2002 First Release, need to add support for changing - audio parameters. -*/ - -#include "config.h" - -#define RINGSIZE 8 -#define FRAGSIZE 4096 /* (2^12 see SETFRAGSIZE below) */ - -#define TRUE (1==1) -#define FALSE (1==0) - -#define PAL_WIDTH 768 -#define PAL_HEIGHT 576 -#define PAL_FPS 25 - -#define NTSC_WIDTH 640 -#define NTSC_HEIGHT 480 -#define NTSC_FPS 29.97 - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/filio.h> -#include <sys/time.h> -#include <signal.h> -#include <string.h> - -#include <sys/param.h> -#ifdef __NetBSD__ -#include <dev/ic/bt8xx.h> -#include <sys/audioio.h> -#elif defined(__DragonFly__) -#include <dev/video/meteor/ioctl_meteor.h> -#include <dev/video/bktr/ioctl_bt848.h> -#elif __FreeBSD_version >= 502100 -#include <dev/bktr/ioctl_meteor.h> -#include <dev/bktr/ioctl_bt848.h> -#else -#include <machine/ioctl_meteor.h> -#include <machine/ioctl_bt848.h> -#endif - -#ifdef HAVE_SYS_SOUNDCARD_H -#include <sys/soundcard.h> -#else -#ifdef HAVE_SOUNDCARD_H -#include <soundcard.h> -#else -#include <machine/soundcard.h> -#endif -#endif - -#include "libaf/af_format.h" -#include "libvo/img_format.h" -#include "tv.h" - -/* information about this file */ -static tvi_info_t info = { - "Brooktree848 Support", - "bsdbt848", - "Charles Henrich", - "in development" -}; - -typedef struct { - int dirty; - double timestamp; - char *buf; -} RBFRAME; - -/* private data's */ -typedef struct { - -/* Audio */ - char *dspdev; - int dspready; - int dspfd; - int dspsamplesize; - int dspstereo; - int dspspeed; - int dspfmt; - int dspframesize; - int dsprate; - long long dspbytesread; - -/* Video */ - char *btdev; - int videoready; - int btfd; - int source; - float maxfps; - float fps; - int iformat; - int maxheight; - int maxwidth; - struct meteor_geomet geom; - struct meteor_capframe capframe; - -/* Frame Buffer */ - - int framebufsize; - float timestamp; - int curpaintframe; - int curbufframe; - unsigned char *livebuf; - RBFRAME framebuf[RINGSIZE]; - -/* Inputs */ - - int input; - -/* Tuner */ - - char *tunerdev; - int tunerfd; - int tunerready; - u_long tunerfreq; - struct bktr_chnlset cset; - -/* Other */ - - int immediatemode; - double starttime; - -} priv_t; - -#include "tvi_def.h" - -static priv_t *G_private=NULL; - -static int getinput(int innumber); - -static void processframe(int signal) -{ -struct timeval curtime; - -if(G_private->immediatemode == TRUE) return; - -gettimeofday(&curtime, NULL); - -if(G_private->framebuf[G_private->curpaintframe].dirty == TRUE) - { - memcpy(G_private->framebuf[G_private->curpaintframe].buf, - G_private->livebuf, G_private->framebufsize); - - G_private->framebuf[G_private->curpaintframe].dirty = FALSE; - - G_private->framebuf[G_private->curpaintframe].timestamp = - curtime.tv_sec + curtime.tv_usec*.000001; - - G_private->curpaintframe++; - - if(G_private->curpaintframe >= RINGSIZE) G_private->curpaintframe = 0; - } - -return; -} - -/* handler creator - entry point ! */ -tvi_handle_t *tvi_init_bsdbt848(char *device) -{ - return(new_handle()); -} - -static int control(priv_t *priv, int cmd, void *arg) -{ - switch(cmd) - { - -/* Tuner Controls */ - - case TVI_CONTROL_IS_TUNER: - if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_TUN_GET_FREQ: - { - if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0) - { - perror("GETFREQ:ioctl"); - return(TVI_CONTROL_FALSE); - } - - (int)*(void **)arg = priv->tunerfreq; - return(TVI_CONTROL_TRUE); - } - - case TVI_CONTROL_TUN_SET_FREQ: - { - priv->tunerfreq = (int)*(void **)arg; - - if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0) - { - perror("SETFREQ:ioctl"); - return(0); - } - - return(TVI_CONTROL_TRUE); - } - - case TVI_CONTROL_TUN_GET_TUNER: - case TVI_CONTROL_TUN_SET_TUNER: - -/* Inputs */ - - case TVI_CONTROL_SPC_GET_INPUT: - { - if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0) - { - perror("GINPUT:ioctl"); - return(TVI_CONTROL_FALSE); - } - - (int)*(void **)arg = priv->input; - return(TVI_CONTROL_TRUE); - } - - case TVI_CONTROL_SPC_SET_INPUT: - { - priv->input = getinput((int)*(void **)arg); - - if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) - { - perror("tunerfreq:ioctl"); - return(0); - } - - return(TVI_CONTROL_TRUE); - } - -/* Audio Controls */ - - case TVI_CONTROL_IS_AUDIO: - if(priv->dspready == FALSE) return TVI_CONTROL_FALSE; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_AUD_GET_FORMAT: - { - (int)*(void **)arg = AF_FORMAT_S16_LE; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_CHANNELS: - { - (int)*(void **)arg = 2; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_SET_SAMPLERATE: - { - int dspspeed = (int)*(void **)arg; - - if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1) - { - perror("invalidaudiorate"); - return(TVI_CONTROL_FALSE); - } - - priv->dspspeed = dspspeed; - - priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/ - priv->fps * (priv->dspstereo+1); - priv->dsprate = priv->dspspeed * priv->dspsamplesize/8* - (priv->dspstereo+1); - - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_SAMPLERATE: - { - (int)*(void **)arg = priv->dspspeed; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_SAMPLESIZE: - { - (int)*(void **)arg = priv->dspsamplesize/8; - return(TVI_CONTROL_TRUE); - } - -/* Video Controls */ - - case TVI_CONTROL_IS_VIDEO: - if(priv->videoready == FALSE) return TVI_CONTROL_FALSE; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_TUN_SET_NORM: - { - int req_mode = (int)*(void **)arg; - u_short tmp_fps; - - priv->iformat = METEOR_FMT_AUTOMODE; - - if(req_mode == TV_NORM_PAL) - { - priv->iformat = METEOR_FMT_PAL; - priv->maxheight = PAL_HEIGHT; - priv->maxwidth = PAL_WIDTH; - priv->maxfps = PAL_FPS; - priv->fps = PAL_FPS; - - if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; - - if(priv->geom.rows > priv->maxheight) - { - priv->geom.rows = priv->maxheight; - } - - if(priv->geom.columns > priv->maxwidth) - { - priv->geom.columns = priv->maxwidth; - } - } - - if(req_mode == TV_NORM_NTSC) - { - priv->iformat = METEOR_FMT_NTSC; - priv->maxheight = NTSC_HEIGHT; - priv->maxwidth = NTSC_WIDTH; - priv->maxfps = NTSC_FPS; - priv->fps = NTSC_FPS; - - priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/ - priv->fps * (priv->dspstereo+1); - priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 * - (priv->dspstereo+1); - - if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; - - if(priv->geom.rows > priv->maxheight) - { - priv->geom.rows = priv->maxheight; - } - - if(priv->geom.columns > priv->maxwidth) - { - priv->geom.columns = priv->maxwidth; - } - } - - if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM; - - if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) - { - perror("format:ioctl"); - return(TVI_CONTROL_FALSE); - } - - if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) - { - perror("geo:ioctl"); - return(0); - } - - tmp_fps = priv->fps; - if(ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) - { - perror("fps:ioctl"); - return(0); - } - -#ifdef BT848_SAUDIO - if(priv->tunerready == TRUE && - ioctl(priv->tunerfd, BT848_SAUDIO, &tv_param_audio_id) < 0) - { - perror("audioid:ioctl"); - } -#endif - - return(TVI_CONTROL_TRUE); - } - - case TVI_CONTROL_VID_GET_FORMAT: - (int)*(void **)arg = IMGFMT_UYVY; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_VID_SET_FORMAT: - { - int req_fmt = (int)*(void **)arg; - - if(req_fmt != IMGFMT_UYVY) return(TVI_CONTROL_FALSE); - - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_VID_SET_WIDTH: - priv->geom.columns = (int)*(void **)arg; - - if(priv->geom.columns > priv->maxwidth) - { - priv->geom.columns = priv->maxwidth; - } - - if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) - { - perror("width:ioctl"); - return(0); - } - - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_VID_GET_WIDTH: - (int)*(void **)arg = priv->geom.columns; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_VID_SET_HEIGHT: - priv->geom.rows = (int)*(void **)arg; - - if(priv->geom.rows > priv->maxheight) - { - priv->geom.rows = priv->maxheight; - } - - if(priv->geom.rows <= priv->maxheight / 2) - { - priv->geom.oformat |= METEOR_GEO_EVEN_ONLY; - } - - if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) - { - perror("height:ioctl"); - return(0); - } - - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_VID_GET_HEIGHT: - (int)*(void **)arg = priv->geom.rows; - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_VID_GET_FPS: - *(float *)arg = priv->fps; - return(TVI_CONTROL_TRUE); - -/* - case TVI_CONTROL_VID_SET_FPS: - priv->fps = (int)*(void **)arg; - - if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; - - if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) - { - perror("fps:ioctl"); - return(0); - } - - return(TVI_CONTROL_TRUE); -*/ - - case TVI_CONTROL_VID_CHK_WIDTH: - case TVI_CONTROL_VID_CHK_HEIGHT: - return(TVI_CONTROL_TRUE); - - case TVI_CONTROL_IMMEDIATE: - priv->immediatemode = TRUE; - return(TVI_CONTROL_TRUE); - } - - return(TVI_CONTROL_UNKNOWN); -} - -static int init(priv_t *priv) -{ -int marg; -int count; -u_short tmp_fps; - -G_private = priv; /* Oooh, sick */ - -/* Video Configuration */ - -priv->videoready = TRUE; -priv->btdev = strdup("/dev/bktr0"); -priv->immediatemode = FALSE; -priv->iformat = METEOR_FMT_PAL; -priv->maxheight = PAL_HEIGHT; -priv->maxwidth = PAL_WIDTH; -priv->maxfps = PAL_FPS; -priv->source = METEOR_INPUT_DEV0; -priv->fps = priv->maxfps; - -priv->starttime=0; -priv->curpaintframe=0; -priv->curbufframe=0; - -priv->geom.columns = priv->maxwidth; -priv->geom.rows = priv->maxheight; -priv->geom.frames = 1; -priv->geom.oformat = METEOR_GEO_YUV_PACKED; - -priv->btfd = open(priv->btdev, O_RDONLY); - -if(priv->btfd < 0) - { - perror("bktr open"); - priv->videoready = FALSE; - } - -if(priv->videoready == TRUE && - ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) - { - perror("FMT:ioctl"); - } - -if(priv->videoready == TRUE && - ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0) - { - perror("SINPUT:ioctl"); - } - -tmp_fps = priv->fps; -if(priv->videoready == TRUE && - ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) - { - perror("SFPS:ioctl"); - } - -if(priv->videoready == TRUE && - ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) - { - perror("SGEO:ioctl"); - } - -if(priv->videoready == TRUE) - { - priv->framebufsize = (priv->geom.columns * priv->geom.rows * 2); - - priv->livebuf = (u_char *)mmap((caddr_t)0, priv->framebufsize, PROT_READ, - MAP_SHARED, priv->btfd, (off_t)0); - - if(priv->livebuf == (u_char *) MAP_FAILED) - { - perror("mmap"); - priv->videoready = FALSE; - } - - for(count=0;count<RINGSIZE;count++) - { - priv->framebuf[count].buf = malloc(priv->framebufsize); - - if(priv->framebuf[count].buf == NULL) - { - perror("framebufmalloc"); - priv->videoready = FALSE; - break; - } - - priv->framebuf[count].dirty = TRUE; - priv->framebuf[count].timestamp = 0; - } - } - -/* Tuner Configuration */ - -priv->tunerdev = strdup("/dev/tuner0"); -priv->tunerready = TRUE; - -priv->tunerfd = open(priv->tunerdev, O_RDONLY); - -if(priv->tunerfd < 0) - { - perror("tune open"); - priv->tunerready = FALSE; - } - -/* Audio Configuration */ - -priv->dspready = TRUE; -#ifdef __NetBSD__ -priv->dspdev = strdup("/dev/sound"); -#else -priv->dspdev = strdup("/dev/dsp"); -#endif -priv->dspsamplesize = 16; -priv->dspstereo = 1; -priv->dspspeed = 44100; -priv->dspfmt = AFMT_S16_LE; -priv->dspbytesread = 0; -priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1); -priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps * - (priv->dspstereo+1); - -if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0) - { - perror("dsp open"); - priv->dspready = FALSE; - } - -marg = (256 << 16) | 12; - -if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 ) - { - perror("setfrag"); - priv->dspready = FALSE; - } - -if((priv->dspready == TRUE) && - ((ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) || - (ioctl(priv->dspfd, SNDCTL_DSP_STEREO, &priv->dspstereo) == -1) || - (ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &priv->dspspeed) == -1) || - (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1))) - { - perror ("configuration of dsp failed"); - close(priv->dspfd); - priv->dspready = FALSE; - } - -return(1); -} - -/* that's the real start, we'got the format parameters (checked with control) */ -static int start(priv_t *priv) -{ -int tmp; -struct timeval curtime; -int marg; - -fprintf(stderr,"START\n"); -if(priv->videoready == FALSE) return(0); - -signal(SIGUSR1, processframe); -signal(SIGALRM, processframe); - -marg = SIGUSR1; - -if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0) - { - perror("METEORSSIGNAL failed"); - return(0); - } - -read(priv->dspfd, &tmp, 2); - -gettimeofday(&curtime, NULL); - -priv->starttime = curtime.tv_sec + (curtime.tv_usec *.000001); - -marg = METEOR_CAP_CONTINOUS; - -if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0) - { - perror("METEORCAPTUR failed"); - return(0); - } - -return(1); -} - -static int uninit(priv_t *priv) -{ -int marg; - -if(priv->videoready == FALSE) return(0); - -marg = METEOR_SIG_MODE_MASK; - -if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 ) - { - perror("METEORSSIGNAL"); - return(0); - } - -marg = METEOR_CAP_STOP_CONT; - -if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 ) - { - perror("METEORCAPTUR STOP"); - return(0); - } - -close(priv->btfd); -close(priv->dspfd); - -priv->dspfd = -1; -priv->btfd = -1; - -priv->dspready = priv->videoready = FALSE; - -return(1); -} - - -static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) -{ -struct timeval curtime; -sigset_t sa_mask; - -if(priv->videoready == FALSE) return(0); - -alarm(1); -sigfillset(&sa_mask); -sigdelset(&sa_mask,SIGINT); -sigdelset(&sa_mask,SIGUSR1); -sigdelset(&sa_mask,SIGALRM); -sigsuspend(&sa_mask); -alarm(0); - -memcpy(buffer, priv->livebuf, len); - -/* PTS = 0, show the frame NOW, this routine is only used in playback mode - without audio capture .. */ - -return(0); -} - -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ -struct timeval curtime; -double timestamp=0; -sigset_t sa_mask; - -if(priv->videoready == FALSE) return(0); - -if(priv->immediatemode == TRUE) - { - return grabimmediate_video_frame(priv, buffer, len); - } - -while(priv->framebuf[priv->curbufframe].dirty == TRUE) - { - alarm(1); - sigemptyset(&sa_mask); - sigsuspend(&sa_mask); - alarm(0); - } - -memcpy(buffer, priv->framebuf[priv->curbufframe].buf, len); -timestamp = priv->framebuf[priv->curbufframe].timestamp; -priv->framebuf[priv->curbufframe].dirty = TRUE; - -priv->curbufframe++; -if(priv->curbufframe >= RINGSIZE) priv->curbufframe = 0; - -return(timestamp-priv->starttime); -} - -static int get_video_framesize(priv_t *priv) -{ -return(priv->geom.columns*priv->geom.rows*16/8); -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ -struct timeval curtime; -double curpts; -double timeskew; -int bytesavail; -int bytesread; -int ret; - -if(priv->dspready == FALSE) return 0; - -gettimeofday(&curtime, NULL); - -/* Get exactly one frame of audio, which forces video sync to audio.. */ - -bytesread=read(priv->dspfd, buffer, len); - -while(bytesread < len) - { - ret=read(priv->dspfd, &buffer[bytesread], len-bytesread); - - if(ret == -1) - { - perror("Audio read failed!"); - return 0; - } - - bytesread+=ret; - } - -priv->dspbytesread += bytesread; - -curpts = curtime.tv_sec + curtime.tv_usec * .000001; - -timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime); - -if(timeskew > .125/priv->fps) - { - priv->starttime -= timeskew; - } -else - { - if(timeskew < -.125/priv->fps) - { - priv->starttime -= timeskew; - } - } - -return(priv->dspbytesread * 1.0 / priv->dsprate); -} - -static int get_audio_framesize(priv_t *priv) -{ -int bytesavail; -#ifdef __NetBSD__ -struct audio_info auinf; -#endif - -if(priv->dspready == FALSE) return 0; - -#ifdef __NetBSD__ -if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0) - { - perror("AUDIO_GETINFO"); - return(TVI_CONTROL_FALSE); - } -else - bytesavail = auinf.record.seek; /* *priv->dspsamplesize; */ -#else -if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0) - { - perror("FIONREAD"); - return(TVI_CONTROL_FALSE); - } -#endif - -/* When mencoder wants audio data, it wants data.. - it won't go do anything else until it gets it :( */ - -if(bytesavail == 0) return FRAGSIZE; - -return(bytesavail); -} - -static int getinput(int innumber) -{ -switch(innumber) - { - case 0: return METEOR_INPUT_DEV0; /* RCA */ - case 1: return METEOR_INPUT_DEV1; /* Tuner */ - case 2: return METEOR_INPUT_DEV2; /* In 1 */ - case 3: return METEOR_INPUT_DEV3; /* In 2 */ - case 4: return METEOR_INPUT_DEV_RGB; /* RGB */ - case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid */ - } - -return 0; -}
--- a/libmpdemux/tvi_def.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -#include <stdlib.h> /* malloc */ -#include <string.h> /* memset */ - -static int init(priv_t *priv); -static int uninit(priv_t *priv); -static int control(priv_t *priv, int cmd, void *arg); -static int start(priv_t *priv); -static double grab_video_frame(priv_t *priv, char *buffer, int len); -#ifdef HAVE_TV_BSDBT848 -static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len); -#endif -static int get_video_framesize(priv_t *priv); -static double grab_audio_frame(priv_t *priv, char *buffer, int len); -static int get_audio_framesize(priv_t *priv); - -static tvi_functions_t functions = -{ - init, - uninit, - control, - start, - grab_video_frame, -#ifdef HAVE_TV_BSDBT848 - grabimmediate_video_frame, -#endif - get_video_framesize, - grab_audio_frame, - get_audio_framesize -}; - -static tvi_handle_t *new_handle(void) -{ - tvi_handle_t *h = (tvi_handle_t *)malloc(sizeof(tvi_handle_t)); - - if (!h) - return(NULL); - h->priv = (priv_t *)malloc(sizeof(priv_t)); - if (!h->priv) - { - free(h); - return(NULL); - } - memset(h->priv, 0, sizeof(priv_t)); - h->info = &info; - h->functions = &functions; - h->seq = 0; - h->chanlist = -1; - h->chanlist_s = NULL; - h->norm = -1; - h->channel = -1; - return(h); -} - -static void free_handle(tvi_handle_t *h) -{ - if (h) { - if (h->priv) - free(h->priv); - free(h); - } -}
--- a/libmpdemux/tvi_dummy.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - Only a sample! -*/ - -#include "config.h" - -#include <stdio.h> -#include "libvo/img_format.h" -#include "tv.h" - -/* information about this file */ -static tvi_info_t info = { - "NULL-TV", - "dummy", - "alex", - NULL -}; - -/* private data's */ -typedef struct { - int width; - int height; -} priv_t; - -#include "tvi_def.h" - -/* handler creator - entry point ! */ -tvi_handle_t *tvi_init_dummy(char *device) -{ - return(new_handle()); -} - -/* initialisation */ -static int init(priv_t *priv) -{ - priv->width = 320; - priv->height = 200; - return(1); -} - -/* that's the real start, we'got the format parameters (checked with control) */ -static int start(priv_t *priv) -{ - return(1); -} - -static int uninit(priv_t *priv) -{ - return(1); -} - -static int control(priv_t *priv, int cmd, void *arg) -{ - switch(cmd) - { - case TVI_CONTROL_IS_VIDEO: - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_FORMAT: -// *(int *)arg = IMGFMT_YV12; - *(int *)arg = IMGFMT_YV12; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_SET_FORMAT: - { -// int req_fmt = *(int *)arg; - int req_fmt = *(int *)arg; - if (req_fmt != IMGFMT_YV12) - return(TVI_CONTROL_FALSE); - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_VID_SET_WIDTH: - priv->width = *(int *)arg; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_WIDTH: - *(int *)arg = priv->width; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_SET_HEIGHT: - priv->height = *(int *)arg; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_HEIGHT: - *(int *)arg = priv->height; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_CHK_WIDTH: - case TVI_CONTROL_VID_CHK_HEIGHT: - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_TUN_SET_NORM: - return(TVI_CONTROL_TRUE); - } - return(TVI_CONTROL_UNKNOWN); -} - -#ifdef HAVE_TV_BSDBT848 -static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0xCC, len); - return(1); -} -#endif - -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0x42, len); - return(1); -} - -static int get_video_framesize(priv_t *priv) -{ - /* YV12 */ - return(priv->width*priv->height*12/8); -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0x42, len); - return(1); -} - -static int get_audio_framesize(priv_t *priv) -{ - return(1); -}
--- a/libmpdemux/tvi_v4l.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1759 +0,0 @@ -/* - Video 4 Linux input - - (C) Alex Beregszaszi - - Some ideas are based on xawtv/libng's grab-v4l.c written by - Gerd Knorr <kraxel@bytesex.org> - - Multithreading, a/v sync and native ALSA support by - Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz> - - Mjpeg hardware encoding support by - Iván Szántó <szivan@freemail.hu> - - CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! -*/ - -#include "config.h" - -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/time.h> - -/* Necessary to prevent collisions between <linux/time.h> and <sys/time.h> when V4L2 is installed. */ -#define _LINUX_TIME_H - -#include <linux/videodev.h> -#include <unistd.h> -#include <sys/mman.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> -#ifdef HAVE_SYS_SYSINFO_H -#include <sys/sysinfo.h> -#endif - -#include "mp_msg.h" -#include "libaf/af_format.h" -#include "libvo/img_format.h" -#include "libvo/fastmemcpy.h" -#include "libvo/videodev_mjpeg.h" - -#include "tv.h" - -#include "audio_in.h" - -static tvi_info_t info = { - "Video 4 Linux input", - "v4l", - "Alex Beregszaszi", - "under development" -}; - -#define PAL_WIDTH 768 -#define PAL_HEIGHT 576 -#define PAL_FPS 25 - -#define NTSC_WIDTH 640 -#define NTSC_HEIGHT 480 -#define NTSC_FPS (30000.0/1001.0) - -#define MAX_AUDIO_CHANNELS 10 - -#define VID_BUF_SIZE_IMMEDIATE 2 -#define VIDEO_AVG_BUFFER_SIZE 600 - -typedef struct { - /* general */ - char *video_device; - int video_fd; - struct video_capability capability; - struct video_channel *channels; - int act_channel; - struct video_tuner tuner; - - /* video */ - struct video_picture picture; - int format; /* output format */ - int width; - int height; - int bytesperline; - float fps; - - struct video_mbuf mbuf; - unsigned char *mmap; - struct video_mmap *buf; - int nbuf; - - /* audio */ - char *audio_device; - audio_in_t audio_in; - - int audio_id; - struct video_audio audio[MAX_AUDIO_CHANNELS]; - int audio_channels[MAX_AUDIO_CHANNELS]; - - /* buffering stuff */ - int immediate_mode; - - int audio_buffer_size; - int aud_skew_cnt; - unsigned char *audio_ringbuffer; - long long *audio_skew_buffer; - volatile int audio_head; - volatile int audio_tail; - volatile int audio_cnt; - volatile long long audio_skew; - volatile double audio_skew_factor; - volatile long long audio_skew_measure_time; - volatile int audio_drop; - - int first; - int video_buffer_size_max; - volatile int video_buffer_size_current; - unsigned char **video_ringbuffer; - long long *video_timebuffer; - long long *video_avg_buffer; - int video_avg_ptr; - int video_interval_sum; - volatile int video_head; - volatile int video_tail; - volatile int video_cnt; - - volatile int shutdown; - - pthread_t audio_grabber_thread; - pthread_t video_grabber_thread; - pthread_mutex_t audio_starter; - pthread_mutex_t skew_mutex; - pthread_mutex_t video_buffer_mutex; - - long long starttime; - double audio_secs_per_block; - long long audio_skew_total; - long audio_recv_blocks_total; - long audio_sent_blocks_total; - long mjpeg_bufsize; - -} priv_t; - -#include "tvi_def.h" - -static const char *device_cap2name[] = { - "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", - "frameram", "scales", "monochrome", "subcapture", "mpeg-decoder", - "mpeg-encoder", "mjpeg-decoder", "mjpeg-encoder", NULL -}; - -static const char *device_palette2name[] = { - "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422", - "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p", - "yuv420p", "yuv410p" -}; -#define PALETTE(x) ((x < sizeof(device_palette2name)/sizeof(char*)) ? device_palette2name[x] : "UNKNOWN") - -static const char *norm2name(int mode) -{ - switch (mode) { - case VIDEO_MODE_PAL: - return "pal"; - case VIDEO_MODE_SECAM: - return "secam"; - case VIDEO_MODE_NTSC: - return "ntsc"; - case VIDEO_MODE_AUTO: - return "auto"; - default: - return "unknown"; - } -}; - -static const char *audio_mode2name(int mode) -{ - switch (mode) { - case VIDEO_SOUND_MONO: - return "mono"; - case VIDEO_SOUND_STEREO: - return "stereo"; - case VIDEO_SOUND_LANG1: - return "language1"; - case VIDEO_SOUND_LANG2: - return "language2"; - default: - return "unknown"; - } -}; - -static void *audio_grabber(void *data); -static void *video_grabber(void *data); - -static int palette2depth(int palette) -{ - switch(palette) - { - /* component */ - case VIDEO_PALETTE_RGB555: - return(15); - case VIDEO_PALETTE_RGB565: - return(16); - case VIDEO_PALETTE_RGB24: - return(24); - case VIDEO_PALETTE_RGB32: - return(32); - /* planar */ - case VIDEO_PALETTE_YUV411P: - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_YUV410P: - return(12); - /* packed */ - case VIDEO_PALETTE_YUV422P: - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_UYVY: - case VIDEO_PALETTE_YUV420: - case VIDEO_PALETTE_YUV411: - return(16); - } - return(-1); -} - -static int format2palette(int format) -{ - switch(format) - { - case IMGFMT_BGR15: - return(VIDEO_PALETTE_RGB555); - case IMGFMT_BGR16: - return(VIDEO_PALETTE_RGB565); - case IMGFMT_BGR24: - return(VIDEO_PALETTE_RGB24); - case IMGFMT_BGR32: - return(VIDEO_PALETTE_RGB32); - case IMGFMT_YV12: - case IMGFMT_I420: - return(VIDEO_PALETTE_YUV420P); - case IMGFMT_YUY2: - return(VIDEO_PALETTE_YUV422); - case IMGFMT_UYVY: - return(VIDEO_PALETTE_UYVY); - } - return(-1); -} - -// sets and sanitizes audio buffer/block sizes -static void setup_audio_buffer_sizes(priv_t *priv) -{ - int bytes_per_sample = priv->audio_in.bytes_per_sample; - - // make the audio buffer at least 5 seconds long - priv->audio_buffer_size = 1 + 5*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; - - // make the skew buffer at least 1 second long - priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; - - mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", - priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); -} - -tvi_handle_t *tvi_init_v4l(char *device, char *adevice) -{ - tvi_handle_t *h; - priv_t *priv; - - h = new_handle(); - if (!h) - return(NULL); - - priv = h->priv; - - /* set video device name */ - if (!device) - priv->video_device = strdup("/dev/video0"); - else - priv->video_device = strdup(device); - - /* set video device name */ - if (!adevice) - priv->audio_device = NULL; - else { - priv->audio_device = strdup(adevice); - } - - /* allocation failed */ - if (!priv->video_device) { - free_handle(h); - return(NULL); - } - - return(h); -} - -/* retrieves info about audio channels from the BTTV */ -static void init_v4l_audio(priv_t *priv) -{ - int i; - int reqmode; - - if (!priv->capability.audios) return; - - /* audio chanlist */ - - mp_msg(MSGT_TV, MSGL_V, " Audio devices: %d\n", priv->capability.audios); - - mp_msg(MSGT_TV, MSGL_V, "Video capture card reports the audio setup as follows:\n"); - for (i = 0; i < priv->capability.audios; i++) - { - if (i >= MAX_AUDIO_CHANNELS) - { - mp_msg(MSGT_TV, MSGL_ERR, "no space for more audio channels (increase in source!) (%d > %d)\n", - i, MAX_AUDIO_CHANNELS); - i = priv->capability.audios; - break; - } - - priv->audio[i].audio = i; - if (ioctl(priv->video_fd, VIDIOCGAUDIO, &priv->audio[i]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get audio failed: %s\n", strerror(errno)); - break; - } - - /* mute all channels */ - priv->audio[i].flags |= VIDEO_AUDIO_MUTE; - reqmode = -1; - if (tv_param_amode >= 0) { - switch (tv_param_amode) { - case 0: - reqmode = VIDEO_SOUND_MONO; - break; - case 1: - reqmode = VIDEO_SOUND_STEREO; - break; - case 2: - reqmode = VIDEO_SOUND_LANG1; - break; - case 3: - reqmode = VIDEO_SOUND_LANG2; - break; - default: - mp_msg(MSGT_TV, MSGL_ERR, "Unknown audio mode requested.\n"); - break; - } - if (reqmode >= 0) priv->audio[i].mode = reqmode; - } - ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[i]); - - // get the parameters back - if (ioctl(priv->video_fd, VIDIOCGAUDIO, &priv->audio[i]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get audio failed: %s\n", strerror(errno)); - break; - } - - switch(priv->audio[i].mode) - { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_LANG1: - case VIDEO_SOUND_LANG2: - priv->audio_channels[i] = 1; - break; - case VIDEO_SOUND_STEREO: - priv->audio_channels[i] = 2; - break; - default: - mp_msg(MSGT_TV, MSGL_ERR, "Card reports an unknown audio mode !\n"); - mp_msg(MSGT_TV, MSGL_ERR, "Trying two channel audio. Use forcechan to override.\n"); - priv->audio_channels[i] = 2; - break; - } - - if (reqmode >= 0 && priv->audio[i].mode != reqmode) { - mp_msg(MSGT_TV, MSGL_ERR, "Audio mode setup warning!\n"); - mp_msg(MSGT_TV, MSGL_ERR, "Requested mode was %s, but v4l still reports %s.\n", - audio_mode2name(reqmode), audio_mode2name(priv->audio[i].mode)); - mp_msg(MSGT_TV, MSGL_ERR, "You may need \"forcechan\" option to force stereo/mono audio recording.\n"); - } - - /* display stuff */ - mp_msg(MSGT_TV, MSGL_V, " %d: %s: ", priv->audio[i].audio, - priv->audio[i].name); - if (priv->audio[i].flags & VIDEO_AUDIO_MUTABLE) { - mp_msg(MSGT_TV, MSGL_V, "muted=%s ", - (priv->audio[i].flags & VIDEO_AUDIO_MUTE) ? "yes" : "no"); - } - mp_msg(MSGT_TV, MSGL_V, "vol=%d bass=%d treble=%d balance=%d mode=%s", - priv->audio[i].volume, priv->audio[i].bass, priv->audio[i].treble, - priv->audio[i].balance, audio_mode2name(priv->audio[i].mode)); - mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[i]); - - if (tv_param_forcechan >= 0) - priv->audio_channels[i] = tv_param_forcechan; - - // we'll call VIDIOCSAUDIO again when starting capture - // let's set audio mode to requested mode again for the case - // when VIDIOCGAUDIO just cannot report the mode correctly - if (reqmode >= 0) priv->audio[i].mode = reqmode; - } -} - -#if !defined(__LINUX_VIDEODEV2_H) && !defined(VIDIOC_QUERYCAP) -struct v4l2_capability -{ - __u8 driver[16]; /* i.e. "bttv" */ - __u8 card[32]; /* i.e. "Hauppauge WinTV" */ - __u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */ - __u32 version; /* should use KERNEL_VERSION() */ - __u32 capabilities; /* Device capabilities */ - __u32 reserved[4]; -}; - -#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) -#endif - -static int init(priv_t *priv) -{ - int i; - - if (tv_param_immediate == 1) - tv_param_noaudio = 1; - - priv->video_ringbuffer = NULL; - priv->video_timebuffer = NULL; - priv->video_avg_buffer = NULL; - priv->audio_ringbuffer = NULL; - priv->audio_skew_buffer = NULL; - - priv->video_fd = open(priv->video_device, O_RDWR); - mp_msg(MSGT_TV, MSGL_DBG2, "Video fd: %d, %p\n", priv->video_fd, - priv->video_device); - if (priv->video_fd == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "unable to open '%s': %s\n", - priv->video_device, strerror(errno)); - goto err; - } - - /* check for v4l2 */ - if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) == 0) { - mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); - mp_msg(MSGT_TV, MSGL_ERR, " WARNING: YOU ARE USING V4L DEMUXER WITH V4L2 DRIVERS!!!\n"); - mp_msg(MSGT_TV, MSGL_ERR, " As the V4L1 compatibility layer is broken, this may not work.\n"); - mp_msg(MSGT_TV, MSGL_ERR, " If you encounter any problems, use driver=v4l2 instead.\n"); - mp_msg(MSGT_TV, MSGL_ERR, " Bugreports on driver=v4l with v4l2 drivers will be ignored.\n"); - mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); - } - - /* get capabilities (priv->capability is needed!) */ - if (ioctl(priv->video_fd, VIDIOCGCAP, &priv->capability) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); - goto err; - } - - fcntl(priv->video_fd, F_SETFD, FD_CLOEXEC); - - mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.name); - mp_msg(MSGT_TV, MSGL_INFO, " Capabilites: "); - for (i = 0; device_cap2name[i] != NULL; i++) - if (priv->capability.type & (1 << i)) - mp_msg(MSGT_TV, MSGL_INFO, "%s ", device_cap2name[i]); - mp_msg(MSGT_TV, MSGL_INFO, "\n"); - mp_msg(MSGT_TV, MSGL_INFO, " Device type: %d\n", priv->capability.type); - mp_msg(MSGT_TV, MSGL_INFO, " Supported sizes: %dx%d => %dx%d\n", - priv->capability.minwidth, priv->capability.minheight, - priv->capability.maxwidth, priv->capability.maxheight); - priv->width = priv->capability.minwidth; - priv->height = priv->capability.minheight; - - /* somewhere here could disable tv_param_mjpeg, if it is not a capability */ - - /* initialize if necessary */ - if ( tv_param_mjpeg ) - { - struct mjpeg_params bparm; - struct mjpeg_requestbuffers breq; /* buffer requests */ - - if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, - " MJP: Error getting video parameters: %s\n", strerror(errno)); - goto err; - } - - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: previous params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", - bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, - bparm.decimation, bparm.field_per_buff); - - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", - bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); - - bparm.input = tv_param_input; /* tv */ - if (!strcasecmp(tv_param_norm, "pal")) - bparm.norm = 0; /* PAL */ - else if (!strcasecmp(tv_param_norm, "ntsc")) - bparm.norm = 1; /* NTSC */ - else if (!strcasecmp(tv_param_norm, "secam")) - bparm.norm = 2; /* SECAM */ - bparm.quality = tv_param_quality; - bparm.decimation = tv_param_decimation; - - mp_msg(MSGT_TV, MSGL_INFO, " MJP: setting params to decimation: %d, quality: %d\n", - bparm.decimation, bparm.quality); - - if (ioctl(priv->video_fd, MJPIOC_S_PARAMS, &bparm) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, - " MJP: Error setting video parameters: %s\n", strerror(errno)); - goto err; - } - - if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, - " MJP: Error getting video parameters: %s\n", strerror(errno)); - goto err; - } - - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: current params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", - bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, - bparm.decimation, bparm.field_per_buff); - - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", - bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); - - - breq.count = 64; - priv -> nbuf = breq.count; - priv->mbuf.frames = priv -> nbuf; - priv->mjpeg_bufsize = 256*1024; - if (tv_param_buffer_size >= 0) { - priv->mjpeg_bufsize = tv_param_buffer_size*1024; - } - breq.size = priv -> mjpeg_bufsize; - if (ioctl(priv->video_fd, MJPIOC_REQBUFS,&(breq)) < 0) - { - mp_msg (MSGT_TV, MSGL_ERR, - " MJP: Error requesting video buffers: %s\n", strerror(errno)); - goto err; - } - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: Got %ld buffers of size %ld KB\n", - breq.count, breq.size/1024); - - priv -> mmap = mmap(0, breq.count * breq.size, - PROT_READ|PROT_WRITE, MAP_SHARED, priv->video_fd, 0); - if (priv -> mmap == MAP_FAILED) - { - mp_msg(MSGT_TV, MSGL_INFO, - " MJP: Error mapping video buffers: %s\n", strerror(errno)); - goto err; - } - } - - mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels); - priv->channels = calloc(priv->capability.channels, sizeof(struct video_channel)); - if (!priv->channels) - goto malloc_failed; - memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels); - for (i = 0; i < priv->capability.channels; i++) - { - priv->channels[i].channel = i; - if (ioctl(priv->video_fd, VIDIOCGCHAN, &priv->channels[i]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); - break; - } - mp_msg(MSGT_TV, MSGL_INFO, " %d: %s: %s%s%s%s (tuner:%d, norm:%s)\n", i, - priv->channels[i].name, - (priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", - (priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", - (priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "", - (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "", - priv->channels[i].tuners, - norm2name(priv->channels[i].norm)); - } - priv->act_channel = 0; - - if (!(priv->capability.type & VID_TYPE_CAPTURE)) - { - mp_msg(MSGT_TV, MSGL_ERR, "Only grabbing supported (for overlay use another program)\n"); - goto err; - } - - if ( !tv_param_mjpeg ) - { - /* map grab buffer */ - if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get mbuf failed: %s\n", strerror(errno)); - goto err; - } - - mp_msg(MSGT_TV, MSGL_V, "mbuf: size=%d, frames=%d\n", - priv->mbuf.size, priv->mbuf.frames); - priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE, - MAP_SHARED, priv->video_fd, 0); - if (priv->mmap == (unsigned char *)-1) - { - mp_msg(MSGT_TV, MSGL_ERR, "Unable to map memory for buffers: %s\n", strerror(errno)); - goto err; - } - mp_msg(MSGT_TV, MSGL_DBG2, "our buffer: %p\n", priv->mmap); - - /* num of buffers */ - priv->nbuf = priv->mbuf.frames; - - /* video buffers */ - priv->buf = calloc(priv->nbuf, sizeof(struct video_mmap)); - if (!priv->buf) - goto malloc_failed; - memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap)); - } - - /* init v4l audio even when we don't capture */ - init_v4l_audio(priv); - - if (!priv->capability.audios && !tv_param_force_audio) tv_param_noaudio = 1; - - /* audio init */ - if (!tv_param_noaudio) { - -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - if (tv_param_alsa) - audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); - else - audio_in_init(&priv->audio_in, AUDIO_IN_OSS); -#else - audio_in_init(&priv->audio_in, AUDIO_IN_OSS); -#endif - - if (priv->audio_device) { - audio_in_set_device(&priv->audio_in, priv->audio_device); - } - - if (tv_param_audio_id < priv->capability.audios) - priv->audio_id = tv_param_audio_id; - else - priv->audio_id = 0; - audio_in_set_samplerate(&priv->audio_in, 44100); - if (priv->capability.audios) { - audio_in_set_channels(&priv->audio_in, priv->audio_channels[priv->audio_id]); - } else { - if (tv_param_forcechan >= 0) { - audio_in_set_channels(&priv->audio_in, tv_param_forcechan); - } else { - audio_in_set_channels(&priv->audio_in, 2); - } - } - if (audio_in_setup(&priv->audio_in) < 0) return 0; - setup_audio_buffer_sizes(priv); - } - - return(1); - -malloc_failed: - if (priv->channels) - free(priv->channels); - if (priv->buf) - free(priv->buf); -err: - if (priv->video_fd != -1) - close(priv->video_fd); - return(0); -} - -static int uninit(priv_t *priv) -{ - unsigned long num; - priv->shutdown = 1; - - mp_msg(MSGT_TV, MSGL_V, "Waiting for threads to finish... "); - if (!tv_param_noaudio) { - pthread_join(priv->audio_grabber_thread, NULL); - pthread_mutex_destroy(&priv->audio_starter); - pthread_mutex_destroy(&priv->skew_mutex); - } - pthread_mutex_destroy(&priv->video_buffer_mutex); - pthread_join(priv->video_grabber_thread, NULL); - mp_msg(MSGT_TV, MSGL_V, "done\n"); - - if (priv->capability.audios) { - priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; - ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); - } - - if ( tv_param_mjpeg ) - { - num = -1; - if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, "\n MJP: ioctl MJPIOC_QBUF_CAPT failed: %s\n", strerror(errno)); - } - } - else - { - // We need to munmap as close don't close mem mappings - if(munmap(priv->mmap,priv->mbuf.size)) - mp_msg(MSGT_TV, MSGL_ERR, "Munmap failed: %s\n",strerror(errno)); - } - - if(close(priv->video_fd)) - mp_msg(MSGT_TV, MSGL_ERR, "Close tv failed: %s\n",strerror(errno)); - - audio_in_uninit(&priv->audio_in); - - if (priv->video_ringbuffer) { - int i; - for (i = 0; i < priv->video_buffer_size_current; i++) { - free(priv->video_ringbuffer[i]); - } - free(priv->video_ringbuffer); - } - - if (priv->video_timebuffer) - free(priv->video_timebuffer); - if (priv->video_avg_buffer) - free(priv->video_avg_buffer); - if (!tv_param_noaudio) { - if (priv->audio_ringbuffer) - free(priv->audio_ringbuffer); - if (priv->audio_skew_buffer) - free(priv->audio_skew_buffer); - } - - return(1); -} - -static int get_capture_buffer_size(priv_t *priv) -{ - int bufsize, cnt; - - if (tv_param_buffer_size >= 0) { - bufsize = tv_param_buffer_size*1024*1024; - } else { -#ifdef HAVE_SYS_SYSINFO_H - struct sysinfo si; - - sysinfo(&si); - if (si.totalram<2*1024*1024) { - bufsize = 1024*1024; - } else { - bufsize = si.totalram/2; - } -#else - bufsize = 16*1024*1024; -#endif - } - - cnt = bufsize/(priv->height*priv->bytesperline); - if (cnt < 2) cnt = 2; - - return cnt; -} - -static int start(priv_t *priv) -{ - int i; - int bytes_per_sample; - - if (ioctl(priv->video_fd, VIDIOCGPICT, &priv->picture) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); - return(0); - } - - priv->picture.palette = format2palette(priv->format); - priv->picture.depth = palette2depth(priv->picture.palette); - - if (priv->format != IMGFMT_BGR15) { - priv->bytesperline = priv->width * priv->picture.depth / 8; - } else { - priv->bytesperline = priv->width * 2; - } - - mp_msg(MSGT_TV, MSGL_V, "Picture values:\n"); - mp_msg(MSGT_TV, MSGL_V, " Depth: %d, Palette: %s (Format: %s)\n", priv->picture.depth, - PALETTE(priv->picture.palette), vo_format_name(priv->format)); - mp_msg(MSGT_TV, MSGL_V, " Brightness: %d, Hue: %d, Colour: %d, Contrast: %d\n", - priv->picture.brightness, priv->picture.hue, - priv->picture.colour, priv->picture.contrast); - - - if (ioctl(priv->video_fd, VIDIOCSPICT, &priv->picture) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set picture failed: %s\n", strerror(errno)); - } - - if ( !tv_param_mjpeg ) - { - priv->nbuf = priv->mbuf.frames; - for (i=0; i < priv->nbuf; i++) - { - priv->buf[i].format = priv->picture.palette; - priv->buf[i].frame = i; - priv->buf[i].width = priv->width; - priv->buf[i].height = priv->height; - mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]); - } - } - -#if 0 - { - struct video_play_mode pmode; - - pmode.mode = VID_PLAY_NORMAL; - pmode.p1 = 1; - pmode.p2 = 0; - if (ioctl(priv->video_fd, VIDIOCSPLAYMODE, &pmode) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set play mode failed: %s\n", strerror(errno)); -// return(0); - } - } -#endif - -#if 0 - { - struct video_window win; - - win.x = 0; - win.y = 0; - win.width = priv->width; - win.height = priv->height; - win.chromakey = -1; - win.flags = 0; - //win.clipcount = 0; - - ioctl(priv->video_fd, VIDIOCSWIN, &win); - } - - // initialize video capture - if (ioctl(priv->video_fd, VIDIOCCAPTURE, &one) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "FATAL: ioctl ccapture failed: %s\n", strerror(errno)); - return(0); - } -#endif - - /* setup audio parameters */ - if (!tv_param_noaudio) { - setup_audio_buffer_sizes(priv); - bytes_per_sample = priv->audio_in.bytes_per_sample; - priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); - if (!priv->audio_skew_buffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); - return 0; - } - - priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); - if (!priv->audio_ringbuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); - return 0; - } - - priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample); - priv->audio_head = 0; - priv->audio_tail = 0; - priv->audio_cnt = 0; - priv->audio_drop = 0; - priv->audio_skew = 0; - priv->audio_skew_total = 0; - priv->audio_recv_blocks_total = 0; - priv->audio_sent_blocks_total = 0; - } - - /* setup video parameters */ - if (priv->immediate_mode) { - priv->video_buffer_size_max = VID_BUF_SIZE_IMMEDIATE; - } else { - priv->video_buffer_size_max = get_capture_buffer_size(priv); - } - priv->video_buffer_size_current = 0; - - if (!tv_param_noaudio) { - if (priv->video_buffer_size_max < 3.0*priv->fps*priv->audio_secs_per_block) { - mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" - "You will probably experience heavy framedrops.\n"); - } - } - - mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", - priv->video_buffer_size_max, - priv->video_buffer_size_max*priv->height*priv->bytesperline/(1024*1024)); - - priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(unsigned char*)); - if (!priv->video_ringbuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); - return 0; - } - for (i = 0; i < priv->video_buffer_size_max; i++) - priv->video_ringbuffer[i] = NULL; - - priv->video_timebuffer = calloc(priv->video_buffer_size_max, sizeof(long long)); - if (!priv->video_timebuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); - return 0; - } - priv->video_avg_buffer = malloc(sizeof(long long) * VIDEO_AVG_BUFFER_SIZE); - if (!priv->video_avg_buffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate period buffer: %s\n", strerror(errno)); - return 0; - } - priv->video_interval_sum = (1e6/priv->fps)*VIDEO_AVG_BUFFER_SIZE; - for (i = 0; i < VIDEO_AVG_BUFFER_SIZE; i++) { - priv->video_avg_buffer[i] = 1e6/priv->fps; - } - - priv->video_avg_ptr = 0; - - priv->video_head = 0; - priv->video_tail = 0; - priv->video_cnt = 0; - priv->first = 1; - - if (priv->capability.audios) { - /* enable audio */ - if (tv_param_volume >= 0) - priv->audio[priv->audio_id].volume = tv_param_volume; - if (tv_param_bass >= 0) - priv->audio[priv->audio_id].bass = tv_param_bass; - if (tv_param_treble >= 0) - priv->audio[priv->audio_id].treble = tv_param_treble; - if (tv_param_balance >= 0) - priv->audio[priv->audio_id].balance = tv_param_balance; - priv->audio[priv->audio_id].flags &= ~VIDEO_AUDIO_MUTE; - mp_msg(MSGT_TV, MSGL_V, "Enabling tv audio. Requested setup is:\n"); - mp_msg(MSGT_TV, MSGL_V, "id=%d vol=%d bass=%d treble=%d balance=%d mode=%s", - priv->audio_id, - priv->audio[priv->audio_id].volume, priv->audio[priv->audio_id].bass, priv->audio[priv->audio_id].treble, - priv->audio[priv->audio_id].balance, audio_mode2name(priv->audio[priv->audio_id].mode)); - mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[priv->audio_id]); - ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); - } - - /* launch capture threads */ - priv->shutdown = 0; - if (!tv_param_noaudio) { - pthread_mutex_init(&priv->audio_starter, NULL); - pthread_mutex_init(&priv->skew_mutex, NULL); - pthread_mutex_lock(&priv->audio_starter); - pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); - } - pthread_mutex_init(&priv->video_buffer_mutex, NULL); - /* we'll launch the video capture later, when a first request for a frame arrives */ - - return(1); -} - - -static int control(priv_t *priv, int cmd, void *arg) -{ - mp_msg(MSGT_TV, MSGL_DBG2, "\ndebug: control(priv=%p, cmd=%d, arg=%p)\n", - priv, cmd, arg); - switch(cmd) - { - /* ========== GENERIC controls =========== */ - case TVI_CONTROL_IS_VIDEO: - { - if (priv->capability.type & VID_TYPE_CAPTURE) - return(TVI_CONTROL_TRUE); - return(TVI_CONTROL_FALSE); - } - case TVI_CONTROL_IS_AUDIO: - if (tv_param_force_audio) return(TVI_CONTROL_TRUE); - if (priv->channels[priv->act_channel].flags & VIDEO_VC_AUDIO) - { - return(TVI_CONTROL_TRUE); - } - return(TVI_CONTROL_FALSE); - case TVI_CONTROL_IS_TUNER: - { -// if (priv->capability.type & VID_TYPE_TUNER) - if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) - return(TVI_CONTROL_TRUE); - return(TVI_CONTROL_FALSE); - } - - /* ========== VIDEO controls =========== */ - case TVI_CONTROL_VID_GET_FORMAT: - { - int output_fmt = -1; - - output_fmt = priv->format; - if ( tv_param_mjpeg ) - { - mp_msg(MSGT_TV, MSGL_INFO, " MJP: setting sh_video->format to mjpg\n"); - output_fmt = 0x47504a4d; - output_fmt = 0x67706a6d; - *(int *)arg = output_fmt; - mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", "mjpg"); - } - else - { - *(int *)arg = output_fmt; - mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", vo_format_name(output_fmt)); - } - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_VID_SET_FORMAT: - priv->format = *(int *)arg; - // !HACK! v4l uses BGR format instead of RGB - // and we have to correct this. Fortunately, - // tv.c reads later the format back so we - // can persuade it to use what we want. - if (IMGFMT_IS_RGB(priv->format)) { - priv->format &= ~IMGFMT_RGB_MASK; - priv->format |= IMGFMT_BGR; - } - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_PLANES: - *(int *)arg = 1; /* FIXME, also not needed at this time */ - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_BITS: - *(int *)arg = palette2depth(format2palette(priv->format)); - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_WIDTH: - *(int *)arg = priv->width; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_CHK_WIDTH: - { - int req_width = *(int *)arg; - - mp_msg(MSGT_TV, MSGL_V, "Requested width: %d\n", req_width); - if ((req_width >= priv->capability.minwidth) && - (req_width <= priv->capability.maxwidth)) - return(TVI_CONTROL_TRUE); - return(TVI_CONTROL_FALSE); - } - case TVI_CONTROL_VID_SET_WIDTH: - priv->width = *(int *)arg; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_HEIGHT: - *(int *)arg = priv->height; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_CHK_HEIGHT: - { - int req_height = *(int *)arg; - - mp_msg(MSGT_TV, MSGL_V, "Requested height: %d\n", req_height); - if ((req_height >= priv->capability.minheight) && - (req_height <= priv->capability.maxheight)) - return(TVI_CONTROL_TRUE); - return(TVI_CONTROL_FALSE); - } - case TVI_CONTROL_VID_SET_HEIGHT: - priv->height = *(int *)arg; - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_GET_PICTURE: - if (ioctl(priv->video_fd, VIDIOCGPICT, &priv->picture) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_SET_PICTURE: - if (ioctl(priv->video_fd, VIDIOCSPICT, &priv->picture) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_VID_SET_BRIGHTNESS: - priv->picture.brightness = (327*(*(int *)arg+100)) + 68; - return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); - case TVI_CONTROL_VID_SET_HUE: - priv->picture.hue = (327*(*(int *)arg+100)) + 68; - return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); - case TVI_CONTROL_VID_SET_SATURATION: - priv->picture.colour = (327*(*(int *)arg+100)) + 68; - return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); - case TVI_CONTROL_VID_SET_CONTRAST: - priv->picture.contrast = (327*(*(int *)arg+100)) + 68; - return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); - case TVI_CONTROL_VID_GET_BRIGHTNESS: - if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; - *(int*)arg = ((int)priv->picture.brightness-68)/327-100; - return 1; - case TVI_CONTROL_VID_GET_HUE: - if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; - *(int*)arg = ((int)priv->picture.hue-68)/327-100; - return 1; - case TVI_CONTROL_VID_GET_SATURATION: - if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; - *(int*)arg = ((int)priv->picture.colour-68)/327-100; - return 1; - case TVI_CONTROL_VID_GET_CONTRAST: - if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; - *(int*)arg = ((int)priv->picture.contrast-68)/327-100; - return 1; - case TVI_CONTROL_VID_GET_FPS: - *(float *)arg=priv->fps; - return(TVI_CONTROL_TRUE); - - /* ========== TUNER controls =========== */ - case TVI_CONTROL_TUN_GET_FREQ: - { - unsigned long freq; - - if (ioctl(priv->video_fd, VIDIOCGFREQ, &freq) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get freq failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - - /* tuner uses khz not mhz ! */ -// if (priv->tuner.flags & VIDEO_TUNER_LOW) -// freq /= 1000; - *(unsigned long *)arg = freq; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_TUN_SET_FREQ: - { - /* argument is in MHz ! */ - unsigned long freq = *(unsigned long *)arg; - - if (priv->capability.audios) { - priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; - ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); - } - - mp_msg(MSGT_TV, MSGL_V, "requested frequency: %.3f\n", (float)freq/16); - - /* tuner uses khz not mhz ! */ -// if (priv->tuner.flags & VIDEO_TUNER_LOW) -// freq *= 1000; -// mp_msg(MSGT_TV, MSGL_V, " requesting from driver: freq=%.3f\n", (float)freq/16); - if (ioctl(priv->video_fd, VIDIOCSFREQ, &freq) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set freq failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - usleep(100000); // wait to suppress noise during switching - - if (priv->capability.audios) { - priv->audio[priv->audio_id].flags &= ~VIDEO_AUDIO_MUTE; - ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); - } - - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_TUN_GET_TUNER: - { - if (ioctl(priv->video_fd, VIDIOCGTUNER, &priv->tuner) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get tuner failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - - mp_msg(MSGT_TV, MSGL_V, "Tuner (%s) range: %lu -> %lu\n", priv->tuner.name, - priv->tuner.rangelow, priv->tuner.rangehigh); - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_TUN_SET_TUNER: - { - if (ioctl(priv->video_fd, VIDIOCSTUNER, &priv->tuner) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set tuner failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_TUN_SET_NORM: - { - int req_mode = *(int *)arg; - - if ((req_mode != TV_NORM_PAL) && (req_mode != TV_NORM_NTSC) && (req_mode != TV_NORM_SECAM) - && (req_mode != TV_NORM_PALNC) && (req_mode != TV_NORM_PALM) && (req_mode != TV_NORM_PALN) - && (req_mode != TV_NORM_NTSCJP)) { - mp_msg(MSGT_TV, MSGL_ERR, "Unknown norm!\n"); - return(TVI_CONTROL_FALSE); - } - - if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) { - int prev_mode; - - control(priv, TVI_CONTROL_TUN_GET_TUNER, 0); - if (((req_mode == TV_NORM_PAL - || req_mode == TV_NORM_PALNC - || req_mode == TV_NORM_PALN) && !(priv->tuner.flags & VIDEO_TUNER_PAL)) || - ((req_mode == TV_NORM_NTSC - || req_mode == TV_NORM_NTSCJP - || req_mode == TV_NORM_PALM) && !(priv->tuner.flags & VIDEO_TUNER_NTSC)) || - ((req_mode == TV_NORM_SECAM) && !(priv->tuner.flags & VIDEO_TUNER_SECAM))) - { - mp_msg(MSGT_TV, MSGL_ERR, "Tuner isn't capable to set norm!\n"); - return(TVI_CONTROL_FALSE); - } - - prev_mode = priv->tuner.mode; - - switch(req_mode) { - case TV_NORM_PAL: - case TV_NORM_PALNC: - case TV_NORM_PALN: - priv->tuner.mode = VIDEO_MODE_PAL; - break; - case TV_NORM_NTSC: - case TV_NORM_NTSCJP: - case TV_NORM_PALM: - priv->tuner.mode = VIDEO_MODE_NTSC; - break; - case TV_NORM_SECAM: - priv->tuner.mode = VIDEO_MODE_SECAM; - break; - } - - if (control(priv, TVI_CONTROL_TUN_SET_TUNER, &priv->tuner) != TVI_CONTROL_TRUE) { - // norm setting failed, but maybe it's only because it's fixed - if (priv->tuner.mode != prev_mode) return(TVI_CONTROL_FALSE); // no it really failed - } - - } - - switch(req_mode) { - case TV_NORM_PAL: - priv->channels[priv->act_channel].norm = VIDEO_MODE_PAL; - break; - case TV_NORM_NTSC: - priv->channels[priv->act_channel].norm = VIDEO_MODE_NTSC; - break; - case TV_NORM_SECAM: - priv->channels[priv->act_channel].norm = VIDEO_MODE_SECAM; - break; - case TV_NORM_PALNC: - priv->channels[priv->act_channel].norm = 3; - break; - case TV_NORM_PALM: - priv->channels[priv->act_channel].norm = 4; - break; - case TV_NORM_PALN: - priv->channels[priv->act_channel].norm = 5; - break; - case TV_NORM_NTSCJP: - priv->channels[priv->act_channel].norm = 6; - break; - } - if (ioctl(priv->video_fd, VIDIOCSCHAN, &priv->channels[priv->act_channel]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set chan failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - - if (ioctl(priv->video_fd, VIDIOCGCAP, &priv->capability) == -1) { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - - if(req_mode == TV_NORM_PAL || req_mode == TV_NORM_SECAM || req_mode == TV_NORM_PALN || req_mode == TV_NORM_PALNC) { - priv->fps = PAL_FPS; - } - - if(req_mode == TV_NORM_NTSC || req_mode == TV_NORM_NTSCJP || req_mode == TV_NORM_PALM) { - priv->fps = NTSC_FPS; - } - - if(priv->height > priv->capability.maxheight) { - priv->height = priv->capability.maxheight; - } - - if(priv->width > priv->capability.maxwidth) { - priv->width = priv->capability.maxwidth; - } - - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_TUN_GET_NORM: - { - *(int *)arg = priv->tuner.mode; - - return(TVI_CONTROL_TRUE); - } - - /* ========== AUDIO controls =========== */ - case TVI_CONTROL_AUD_GET_FORMAT: - { - *(int *)arg = AF_FORMAT_S16_LE; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_CHANNELS: - { - *(int *)arg = priv->audio_in.channels; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_SAMPLERATE: - { - *(int *)arg = priv->audio_in.samplerate; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_GET_SAMPLESIZE: - { - *(int *)arg = priv->audio_in.bytes_per_sample; - return(TVI_CONTROL_TRUE); - } - case TVI_CONTROL_AUD_SET_SAMPLERATE: - { - if (audio_in_set_samplerate(&priv->audio_in, *(int *)arg) < 0) return TVI_CONTROL_FALSE; - setup_audio_buffer_sizes(priv); - return(TVI_CONTROL_TRUE); - } - /* ========== SPECIFIC controls =========== */ - case TVI_CONTROL_SPC_GET_INPUT: - { - int req_chan = *(int *)arg; - int i; - - for (i = 0; i < priv->capability.channels; i++) - { - if (priv->channels[i].channel == req_chan) - break; - } - - priv->act_channel = i; - - if (ioctl(priv->video_fd, VIDIOCGCHAN, &priv->channels[i]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - return(TVI_CONTROL_TRUE); - } - - case TVI_CONTROL_SPC_SET_INPUT: - { - struct video_channel chan; - int req_chan = *(int *)arg; - int i; - - if (req_chan >= priv->capability.channels) - { - mp_msg(MSGT_TV, MSGL_ERR, "Invalid input requested: %d, valid: 0-%d\n", - req_chan, priv->capability.channels - 1); - return(TVI_CONTROL_FALSE); - } - - for (i = 0; i < priv->capability.channels; i++) - { - if (priv->channels[i].channel == req_chan) - chan = priv->channels[i]; - } - - if (ioctl(priv->video_fd, VIDIOCSCHAN, &chan) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "ioctl set chan failed: %s\n", strerror(errno)); - return(TVI_CONTROL_FALSE); - } - mp_msg(MSGT_TV, MSGL_INFO, "Using input '%s'\n", chan.name); - - priv->act_channel = i; - - /* update tuner state */ -// if (priv->capability.type & VID_TYPE_TUNER) - if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) - control(priv, TVI_CONTROL_TUN_GET_TUNER, 0); - - /* update local channel list */ - control(priv, TVI_CONTROL_SPC_GET_INPUT, &req_chan); - return(TVI_CONTROL_TRUE); - case TVI_CONTROL_IMMEDIATE: - priv->immediate_mode = 1; - return(TVI_CONTROL_TRUE); - } - } - - return(TVI_CONTROL_UNKNOWN); -} - -// copies a video frame -// for RGB (i.e. BGR in mplayer) flips the image upside down -// for YV12 swaps the 2nd and 3rd plane -static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *source) -{ - int i; - unsigned char *sptr; - - // YV12 uses VIDEO_PALETTE_YUV420P, but the planes are swapped - if (priv->format == IMGFMT_YV12) { - memcpy(dest, source, priv->width * priv->height); - memcpy(dest+priv->width * priv->height*5/4, source+priv->width * priv->height, priv->width * priv->height/4); - memcpy(dest+priv->width * priv->height, source+priv->width * priv->height*5/4, priv->width * priv->height/4); - return; - } - - switch (priv->picture.palette) { - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - sptr = source + (priv->height-1)*priv->bytesperline; - for (i = 0; i < priv->height; i++) { - memcpy(dest, sptr, priv->bytesperline); - dest += priv->bytesperline; - sptr -= priv->bytesperline; - } - break; - case VIDEO_PALETTE_UYVY: - case VIDEO_PALETTE_YUV420P: - default: - memcpy(dest, source, priv->bytesperline * priv->height); - } - -} - -// maximum skew change, in frames -#define MAX_SKEW_DELTA 0.6 -static void *video_grabber(void *data) -{ -#define MAXTOL (priv->nbuf) - priv_t *priv = (priv_t*)data; - struct timeval curtime; - long long skew, prev_skew, xskew, interval, prev_interval; - int frame; - int i; - int framecount; - int tolerance; - unsigned long num; - - /* start the capture process */ - - if ( tv_param_mjpeg ) - { - mp_msg(MSGT_TV, MSGL_INFO, " MJP: gonna capture ! \n"); - for (i=0; i < priv->nbuf; i++) { - num = i; - if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, - "\n MJP: ioctl MJPIOC_QBUF_CAPT b failed: %s\n", strerror(errno)); - } - } - } - else - { - for (i=0; i < priv->nbuf; i++) { - if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[i]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno)); - } - } - } - - gettimeofday(&curtime, NULL); - priv->starttime = (long long)1e6*curtime.tv_sec + curtime.tv_usec; - priv->audio_skew_measure_time = 0; - pthread_mutex_unlock(&priv->audio_starter); - xskew = 0; - skew = 0; - interval = 0; - - prev_interval = 0; - prev_skew = 0; - - tolerance = MAXTOL; - - for (framecount = 0; !priv->shutdown;) - { - for (i = 0; i < priv->nbuf && !priv->shutdown; i++, framecount++) { - - if (priv->immediate_mode) { - while (priv->video_cnt == priv->video_buffer_size_max) { - usleep(10000); - if (priv->shutdown) { - return NULL; - } - } - } - - frame = i; - - if ( tv_param_mjpeg ) - { - while (ioctl(priv->video_fd, MJPIOC_SYNC, &priv->buf[frame].frame) < 0 && - (errno == EAGAIN || errno == EINTR)); - - } - else - { - while (ioctl(priv->video_fd, VIDIOCSYNC, &priv->buf[frame].frame) < 0 && - (errno == EAGAIN || errno == EINTR)); - } - mp_dbg(MSGT_TV, MSGL_DBG3, "\npicture sync failed\n"); - - gettimeofday(&curtime, NULL); - if (!priv->immediate_mode) { - interval = (long long)1e6*curtime.tv_sec + curtime.tv_usec - priv->starttime; - } else { - interval = (long long)1e6*framecount/priv->fps; - } - - if (!priv->immediate_mode) { - long long period, orig_interval; - - if (tolerance == 0) { - if (interval - prev_interval == 0) { - mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta = 0\n"); - } else if ((interval - prev_interval < (long long)0.85e6/priv->fps) - || (interval - prev_interval > (long long)1.15e6/priv->fps) ) { - mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta ~ %.1lf fps\n", - (double)1e6/(interval - prev_interval)); - } - } - - // correct the rate fluctuations on a small scale - orig_interval = interval; - period = priv->video_interval_sum/VIDEO_AVG_BUFFER_SIZE; - if (interval - prev_interval > 105*period/100) { - if (tolerance > 0) { - mp_msg(MSGT_TV, MSGL_DBG3, "correcting timestamp\n"); - interval = prev_interval + priv->video_interval_sum/VIDEO_AVG_BUFFER_SIZE; - tolerance--; - } else { - mp_msg(MSGT_TV, MSGL_DBG3, "bad - frames were dropped\n"); - tolerance = MAXTOL; - } - } else { - if (tolerance < MAXTOL) { - mp_msg(MSGT_TV, MSGL_DBG3, "fluctuation overcome\n"); - } - tolerance = MAXTOL; - } - - priv->video_interval_sum -= priv->video_avg_buffer[priv->video_avg_ptr]; - priv->video_avg_buffer[priv->video_avg_ptr++] = orig_interval-prev_interval; - priv->video_interval_sum += orig_interval-prev_interval; - if (priv->video_avg_ptr >= VIDEO_AVG_BUFFER_SIZE) priv->video_avg_ptr = 0; - -// fprintf(stderr, "fps: %lf\n", (double)1e6*VIDEO_AVG_BUFFER_SIZE/priv->video_interval_sum); - - // interpolate the skew in time - pthread_mutex_lock(&priv->skew_mutex); - xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; - pthread_mutex_unlock(&priv->skew_mutex); - // correct extreme skew changes to avoid (especially) moving backwards in time - if (xskew - prev_skew > (interval - prev_interval)*MAX_SKEW_DELTA) { - skew = prev_skew + (interval - prev_interval)*MAX_SKEW_DELTA; - } else if (xskew - prev_skew < -(interval - prev_interval)*MAX_SKEW_DELTA) { - skew = prev_skew - (interval - prev_interval)*MAX_SKEW_DELTA; - } else { - skew = xskew; - } - } - - mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n", - (interval != prev_interval) ? (double)1e6/(interval - prev_interval) : -1, - (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); - mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); - - prev_skew = skew; - prev_interval = interval; - - /* allocate a new buffer, if needed */ - pthread_mutex_lock(&priv->video_buffer_mutex); - if (priv->video_buffer_size_current < priv->video_buffer_size_max) { - if (priv->video_cnt == priv->video_buffer_size_current) { - unsigned char *newbuf = calloc(priv->bytesperline, priv->height); - if (newbuf) { - memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, - (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *)); - memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail, - (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long)); - priv->video_ringbuffer[priv->video_tail] = newbuf; - if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; - priv->video_buffer_size_current++; - } - } - } - pthread_mutex_unlock(&priv->video_buffer_mutex); - - if (priv->video_cnt == priv->video_buffer_size_current) { - if (!priv->immediate_mode) { - mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); - } - } else { - if (priv->immediate_mode) { - priv->video_timebuffer[priv->video_tail] = interval; - } else { - // compensate for audio skew - // negative skew => there are more audio samples, increase interval - // positive skew => less samples, shorten the interval - priv->video_timebuffer[priv->video_tail] = interval - skew; - } - - if ( tv_param_mjpeg ) - copy_frame(priv, priv->video_ringbuffer[priv->video_tail], - priv->mmap+(priv->mjpeg_bufsize)*i); - else - copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->mmap+priv->mbuf.offsets[frame]); - priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; - priv->video_cnt++; - } - - if ( tv_param_mjpeg ) - { - num = frame; - if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) - { - mp_msg(MSGT_TV, MSGL_ERR, "\n MJP: ioctl MJPIOC_QBUF_CAPT end failed: %s\n", - strerror(errno)); - continue; - } - } - else - { - if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[frame]) == -1) - { - mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno)); - continue; - } - } - - } - - } - mp_msg(MSGT_TV, MSGL_INFO, " MJP: returning! \n"); - return NULL; -} - -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ - double interval; - - if (priv->first) { - pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); - priv->first = 0; - } - - while (priv->video_cnt == 0) { - usleep(10000); - } - - pthread_mutex_lock(&priv->video_buffer_mutex); - interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; - memcpy(buffer, priv->video_ringbuffer[priv->video_head], len); - priv->video_cnt--; - priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; - pthread_mutex_unlock(&priv->video_buffer_mutex); - - return interval; -} - -static int get_video_framesize(priv_t *priv) -{ - return(priv->bytesperline * priv->height); -} - -static void *audio_grabber(void *data) -{ - priv_t *priv = (priv_t*)data; - struct timeval tv; - int i, audio_skew_ptr = 0; - long long current_time, prev_skew = 0; - - pthread_mutex_lock(&priv->audio_starter); - - audio_in_start_capture(&priv->audio_in); - for (i = 0; i < priv->aud_skew_cnt; i++) - priv->audio_skew_buffer[i] = 0; - - for (; !priv->shutdown;) - { - if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) - continue; - - gettimeofday(&tv, NULL); - - priv->audio_recv_blocks_total++; - current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->starttime; - - priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; - priv->audio_skew_buffer[audio_skew_ptr] = current_time - - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total; - priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; - audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; - - pthread_mutex_lock(&priv->skew_mutex); - // linear interpolation - here we interpolate current skew value - // from the moving average, which we expect to be in the middle - // of the interval - if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { - priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; - priv->audio_skew += (priv->audio_skew*priv->aud_skew_cnt)/(2*priv->audio_recv_blocks_total-priv->aud_skew_cnt); - } else { - // this smoothes the evolution of audio_skew at startup a bit - priv->audio_skew = ((priv->aud_skew_cnt+priv->audio_recv_blocks_total)*priv->audio_skew_total)/(priv->aud_skew_cnt*priv->audio_recv_blocks_total); - } - // current skew factor (assuming linearity) - // used for further interpolation in video_grabber - // probably overkill but seems to be necessary for - // stress testing by dropping half of the audio frames ;) - // especially when using ALSA with large block sizes - // where audio_skew remains a long while behind - if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { - priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); - } else { - priv->audio_skew_factor = 0.0; - } - - priv->audio_skew_measure_time = current_time; - prev_skew = priv->audio_skew; - pthread_mutex_unlock(&priv->skew_mutex); - - if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { - mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); - priv->audio_drop++; - } else { - priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; - priv->audio_cnt++; - } - } - return NULL; -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ - mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", - priv, buffer, len); - - if (priv->first) { - pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); - priv->first = 0; - } - - // compensate for dropped audio frames - if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { - priv->audio_drop--; - priv->audio_sent_blocks_total++; - memset(buffer, 0, len); - return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; - } - - while (priv->audio_head == priv->audio_tail) { - usleep(10000); - } - memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); - priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; - priv->audio_cnt--; - priv->audio_sent_blocks_total++; - return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; -} - -static int get_audio_framesize(priv_t *priv) -{ - return(priv->audio_in.blocksize); -}
--- a/libmpdemux/tvi_v4l2.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1746 +0,0 @@ -/* -** Video 4 Linux 2 input -** -** This file is part of MPlayer, see http://mplayerhq.hu/ for info. -** -** (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de> -** (c) 2003 Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz> -** -** File licensed under the GPL, see http://www.fsf.org/ for more info. -** -** Some ideas are based on works from -** Alex Beregszaszi <alex@fsn.hu> -** Gerd Knorr <kraxel@bytesex.org> -** -** CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! -*/ - -/* - -known issues: -- norm setting isn't consistent with tvi_v4l -- the same for volume/bass/treble/balance - -*/ - -#include "config.h" - -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdio.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#ifdef HAVE_SYS_SYSINFO_H -#include <sys/sysinfo.h> -#endif -#include <linux/types.h> -#include <linux/videodev2.h> -#include "mp_msg.h" -#include "libvo/img_format.h" -#include "libaf/af_format.h" -#include "tv.h" -#include "audio_in.h" - -/* information about this file */ -static tvi_info_t info = { - "Video 4 Linux 2 input", - "v4l2", - "Martin Olschewski <olschewski@zpr.uni-koeln.de>", - "first try, more to come ;-)" -}; - -struct map { - struct v4l2_buffer buf; - void *addr; - size_t len; -}; - -#define BUFFER_COUNT 6 - -/* private data */ -typedef struct { - /* video */ - char *video_dev; - int video_fd; - int mp_format; - struct v4l2_capability capability; - struct v4l2_input input; - struct v4l2_format format; - struct v4l2_standard standard; - struct v4l2_tuner tuner; - struct map *map; - int mapcount; - int frames; - volatile long long first_frame; - long long curr_frame; - /* audio video interleaving ;-) */ - volatile int streamon; - pthread_t audio_grabber_thread; - pthread_mutex_t skew_mutex; - - /* 2nd level video buffers */ - int first; - int immediate_mode; - - int video_buffer_size_max; - volatile int video_buffer_size_current; - unsigned char **video_ringbuffer; - long long *video_timebuffer; - volatile int video_head; - volatile int video_tail; - volatile int video_cnt; - pthread_t video_grabber_thread; - pthread_mutex_t video_buffer_mutex; - - /* audio */ - char *audio_dev; - audio_in_t audio_in; - - long long audio_start_time; - int audio_buffer_size; - int aud_skew_cnt; - unsigned char *audio_ringbuffer; - long long *audio_skew_buffer; - long long *audio_skew_delta_buffer; - volatile int audio_head; - volatile int audio_tail; - volatile int audio_cnt; - volatile long long audio_skew; - volatile double audio_skew_factor; - volatile long long audio_skew_measure_time; - volatile int audio_drop; - volatile int shutdown; - - int audio_inited; - double audio_secs_per_block; - long long audio_usecs_per_block; - long long audio_skew_total; - long long audio_skew_delta_total; - long audio_recv_blocks_total; - long audio_sent_blocks_total; - pthread_mutex_t audio_mutex; - int audio_insert_null_samples; - volatile long audio_null_blocks_inserted; - volatile long long dropped_frames_timeshift; - long long dropped_frames_compensated; -} priv_t; - -#include "tvi_def.h" - -static void *audio_grabber(void *data); -static void *video_grabber(void *data); - -/**********************************************************************\ - - Only few of the fourccs are the same in v4l2 and mplayer: - - IMGFMT_YVU9 == V4L2_PIX_FMT_YVU410 - IMGFMT_YV12 == V4L2_PIX_FMT_YVU420 - IMGFMT_NV12 == V4L2_PIX_FMT_NV12 - IMGFMT_422P == V4L2_PIX_FMT_YUV422P - IMGFMT_411P == V4L2_PIX_FMT_YUV411P - IMGFMT_UYVY == V4L2_PIX_FMT_UYVY - IMGFMT_Y41P == V4L2_PIX_FMT_Y41P - - This may be an useful translation table for some others: - - IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332 - IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555 - IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565 - IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24 - IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32 - IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24 - IMGFMT_BGR32 == V4L2_PIX_FMT_BGR32 - IMGFMT_Y800 == V4L2_PIX_FMT_GREY - IMGFMT_IF09 == V4L2_PIX_FMT_YUV410 - IMGFMT_I420 == V4L2_PIX_FMT_YUV420 - IMGFMT_YUY2 == V4L2_PIX_FMT_YUYV - -\**********************************************************************/ - -/* -** Translate a mplayer fourcc to a video4linux2 pixel format. -*/ -static int fcc_mp2vl(int fcc) -{ - switch (fcc) { - case IMGFMT_RGB8: return V4L2_PIX_FMT_RGB332; - case IMGFMT_BGR15: return V4L2_PIX_FMT_RGB555; - case IMGFMT_BGR16: return V4L2_PIX_FMT_RGB565; - case IMGFMT_RGB24: return V4L2_PIX_FMT_RGB24; - case IMGFMT_RGB32: return V4L2_PIX_FMT_RGB32; - case IMGFMT_BGR24: return V4L2_PIX_FMT_BGR24; - case IMGFMT_BGR32: return V4L2_PIX_FMT_BGR32; - case IMGFMT_Y800: return V4L2_PIX_FMT_GREY; - case IMGFMT_IF09: return V4L2_PIX_FMT_YUV410; - case IMGFMT_I420: return V4L2_PIX_FMT_YUV420; - case IMGFMT_YUY2: return V4L2_PIX_FMT_YUYV; - case IMGFMT_YV12: return V4L2_PIX_FMT_YVU420; - case IMGFMT_UYVY: return V4L2_PIX_FMT_UYVY; - } - return fcc; -} - -/* -** Translate a video4linux2 fourcc aka pixel format to mplayer. -*/ -static int fcc_vl2mp(int fcc) -{ - switch (fcc) { - case V4L2_PIX_FMT_RGB332: return IMGFMT_RGB8; - case V4L2_PIX_FMT_RGB555: return IMGFMT_BGR15; - case V4L2_PIX_FMT_RGB565: return IMGFMT_BGR16; - case V4L2_PIX_FMT_RGB24: return IMGFMT_RGB24; - case V4L2_PIX_FMT_RGB32: return IMGFMT_RGB32; - case V4L2_PIX_FMT_BGR24: return IMGFMT_BGR24; - case V4L2_PIX_FMT_BGR32: return IMGFMT_BGR32; - case V4L2_PIX_FMT_GREY: return IMGFMT_Y800; - case V4L2_PIX_FMT_YUV410: return IMGFMT_IF09; - case V4L2_PIX_FMT_YUV420: return IMGFMT_I420; - case V4L2_PIX_FMT_YVU420: return IMGFMT_YV12; - case V4L2_PIX_FMT_YUYV: return IMGFMT_YUY2; - case V4L2_PIX_FMT_UYVY: return IMGFMT_UYVY; - } - return fcc; -} - -/* -** Translate a video4linux2 fourcc aka pixel format -** to a human readable string. -*/ -static const char *pixfmt2name(int pixfmt) -{ - static char unknown[24]; - - switch (pixfmt) { - case V4L2_PIX_FMT_RGB332: return "RGB332"; - case V4L2_PIX_FMT_RGB555: return "RGB555"; - case V4L2_PIX_FMT_RGB565: return "RGB565"; - case V4L2_PIX_FMT_RGB555X: return "RGB555X"; - case V4L2_PIX_FMT_RGB565X: return "RGB565X"; - case V4L2_PIX_FMT_BGR24: return "BGR24"; - case V4L2_PIX_FMT_RGB24: return "RGB24"; - case V4L2_PIX_FMT_BGR32: return "BGR32"; - case V4L2_PIX_FMT_RGB32: return "RGB32"; - case V4L2_PIX_FMT_GREY: return "GREY"; - case V4L2_PIX_FMT_YVU410: return "YVU410"; - case V4L2_PIX_FMT_YVU420: return "YVU420"; - case V4L2_PIX_FMT_YUYV: return "YUYV"; - case V4L2_PIX_FMT_UYVY: return "UYVY"; -/* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */ -/* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */ - case V4L2_PIX_FMT_YUV422P: return "YUV422P"; - case V4L2_PIX_FMT_YUV411P: return "YUV411P"; - case V4L2_PIX_FMT_Y41P: return "Y41P"; - case V4L2_PIX_FMT_NV12: return "NV12"; - case V4L2_PIX_FMT_NV21: return "NV21"; - case V4L2_PIX_FMT_YUV410: return "YUV410"; - case V4L2_PIX_FMT_YUV420: return "YUV420"; - case V4L2_PIX_FMT_YYUV: return "YYUV"; - case V4L2_PIX_FMT_HI240: return "HI240"; - case V4L2_PIX_FMT_WNVA: return "WNVA"; - } - sprintf(unknown, "unknown (0x%x)", pixfmt); - return unknown; -} - - -/* -** Gives the depth of a video4linux2 fourcc aka pixel format in bits. -*/ -static int pixfmt2depth(int pixfmt) -{ - switch (pixfmt) { - case V4L2_PIX_FMT_RGB332: - return 8; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB555X: - case V4L2_PIX_FMT_RGB565X: - return 16; - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_RGB24: - return 24; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_RGB32: - return 32; - case V4L2_PIX_FMT_GREY: - return 8; - case V4L2_PIX_FMT_YVU410: - return 9; - case V4L2_PIX_FMT_YVU420: - return 12; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUV411P: - return 16; - case V4L2_PIX_FMT_Y41P: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - return 12; - case V4L2_PIX_FMT_YUV410: - return 9; - case V4L2_PIX_FMT_YUV420: - return 12; - case V4L2_PIX_FMT_YYUV: - return 16; - case V4L2_PIX_FMT_HI240: - return 8; - - } - return 0; -} - -static int amode2v4l(int amode) -{ - switch (amode) { - case 0: - return V4L2_TUNER_MODE_MONO; - case 1: - return V4L2_TUNER_MODE_STEREO; - case 2: - return V4L2_TUNER_MODE_LANG1; - case 3: - return V4L2_TUNER_MODE_LANG2; - default: - return -1; - } -} - - -// sets and sanitizes audio buffer/block sizes -static void setup_audio_buffer_sizes(priv_t *priv) -{ - int bytes_per_sample = priv->audio_in.bytes_per_sample; - double fps = (double)priv->standard.frameperiod.denominator / - priv->standard.frameperiod.numerator; - int seconds = priv->video_buffer_size_max/fps; - - if (seconds < 5) seconds = 5; - if (seconds > 500) seconds = 500; - - // make the audio buffer at least as the video buffer capacity (or 5 seconds) long - priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; - - // make the skew buffer at least 1 second long - priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate - *priv->audio_in.channels - *bytes_per_sample/priv->audio_in.blocksize; - if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; - - mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", - priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); -} - -static void init_audio(priv_t *priv) -{ - if (priv->audio_inited) return; - - if (!tv_param_noaudio) { -#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) - if (tv_param_alsa) - audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); - else - audio_in_init(&priv->audio_in, AUDIO_IN_OSS); -#else - audio_in_init(&priv->audio_in, AUDIO_IN_OSS); -#endif - - if (priv->audio_dev) { - audio_in_set_device(&priv->audio_in, priv->audio_dev); - } - - audio_in_set_samplerate(&priv->audio_in, 44100); - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) { - audio_in_set_channels(&priv->audio_in, 2); - } else { - audio_in_set_channels(&priv->audio_in, 1); - } - } else { - if (tv_param_forcechan >= 0) { - audio_in_set_channels(&priv->audio_in, tv_param_forcechan); - } else { - audio_in_set_channels(&priv->audio_in, 2); - } - } - - if (audio_in_setup(&priv->audio_in) < 0) return; - - priv->audio_inited = 1; - } -} - -#if 0 -/* -** the number of milliseconds elapsed between time0 and time1 -*/ -static size_t difftv(struct timeval time1, struct timeval time0) -{ - return (time1.tv_sec - time0.tv_sec) * 1000 + - (time1.tv_usec - time0.tv_usec) / 1000; -} -#endif - -/* -** Get current video capture format. -*/ -static int getfmt(priv_t *priv) -{ - int i; - - priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if ((i = ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get format failed: %s\n", - info.short_name, strerror(errno)); - } - return i; -} - - -/* -** Get current video capture standard. -*/ -static int getstd(priv_t *priv) -{ - v4l2_std_id id; - int i=0; - - if (ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get standard failed: %s\n", - info.short_name, strerror(errno)); - return -1; - } - do { - priv->standard.index = i++; - if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { - return -1; - } - } while (priv->standard.id != id); - return 0; -} - -/***********************************************************************\ - * * - * * - * Interface to mplayer * - * * - * * -\***********************************************************************/ - -static int set_mute(priv_t *priv, int value) -{ - struct v4l2_control control; - control.id = V4L2_CID_AUDIO_MUTE; - control.value = value; - if (ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) { - mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set mute failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - return 1; -} - -/* -** MPlayer uses values from -100 up to 100 for controls. -** Here they are scaled to what the tv card needs and applied. -*/ -static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) { - struct v4l2_queryctrl qctrl; - - qctrl.id = control->id; - if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - - if (val_signed) { - if (control->value < 0) { - control->value = qctrl.default_value + control->value * - (qctrl.default_value - qctrl.minimum) / 100; - } else { - control->value = qctrl.default_value + control->value * - (qctrl.maximum - qctrl.default_value) / 100; - } - } else { - if (control->value < 50) { - control->value = qctrl.default_value + (control->value-50) * - (qctrl.default_value - qctrl.minimum) / 50; - } else { - control->value = qctrl.default_value + (control->value-50) * - (qctrl.maximum - qctrl.default_value) / 50; - } - } - - - if (ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) { - mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl set %s %d failed: %s\n", - info.short_name, qctrl.name, control->value, strerror(errno)); - return TVI_CONTROL_FALSE; - } - mp_msg(MSGT_TV, MSGL_V, "%s: set %s: %d [%d, %d]\n", info.short_name, - qctrl.name, control->value, qctrl.minimum, qctrl.maximum); - - return TVI_CONTROL_TRUE; -} - - -/* -** Scale the control values back to what mplayer needs. -*/ -static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) { - struct v4l2_queryctrl qctrl; - - qctrl.id = control->id; - if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - - if (ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) { - mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl get %s failed: %s\n", - info.short_name, qctrl.name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - mp_msg(MSGT_TV, MSGL_V, "%s: get %s: %d [%d, %d]\n", info.short_name, - qctrl.name, control->value, qctrl.minimum, qctrl.maximum); - - if (val_signed) { - if (control->value < qctrl.default_value) { - control->value = (control->value - qctrl.default_value) * 100 / - (qctrl.default_value - qctrl.minimum); - } else { - control->value = (control->value - qctrl.default_value) * 100 / - (qctrl.maximum - qctrl.default_value); - } - } else { - if (control->value < qctrl.default_value) { - control->value = (control->value - qctrl.default_value) * 50 / - (qctrl.default_value - qctrl.minimum) + 50; - } else { - control->value = (control->value - qctrl.default_value) * 50 / - (qctrl.maximum - qctrl.default_value) + 50; - } - } - - return TVI_CONTROL_TRUE; -} - -static int control(priv_t *priv, int cmd, void *arg) -{ - struct v4l2_control control; - struct v4l2_frequency frequency; - - switch(cmd) { - case TVI_CONTROL_IS_VIDEO: - return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? - TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; - case TVI_CONTROL_IS_AUDIO: - if (tv_param_force_audio) return TVI_CONTROL_TRUE; - case TVI_CONTROL_IS_TUNER: - return priv->capability.capabilities & V4L2_CAP_TUNER? - TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; - case TVI_CONTROL_IMMEDIATE: - priv->immediate_mode = 1; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_FPS: - *(float *)arg = (float)priv->standard.frameperiod.denominator / - priv->standard.frameperiod.numerator; - mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name, - *(float *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_BITS: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat); - mp_msg(MSGT_TV, MSGL_V, "%s: get depth: %d\n", info.short_name, - *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_FORMAT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat); - mp_msg(MSGT_TV, MSGL_V, "%s: get format: %s\n", info.short_name, - pixfmt2name(priv->format.fmt.pix.pixelformat)); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_FORMAT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg); - priv->format.fmt.pix.field = V4L2_FIELD_ANY; - - priv->mp_format = *(int *)arg; - mp_msg(MSGT_TV, MSGL_V, "%s: set format: %s\n", info.short_name, - pixfmt2name(priv->format.fmt.pix.pixelformat)); - if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers - might even always return the default parameters -> update the format here*/ - priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_WIDTH: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = priv->format.fmt.pix.width; - mp_msg(MSGT_TV, MSGL_V, "%s: get width: %d\n", info.short_name, - *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_CHK_WIDTH: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_WIDTH: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.width = *(int *)arg; - mp_msg(MSGT_TV, MSGL_V, "%s: set width: %d\n", info.short_name, - *(int *)arg); - if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set width failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_HEIGHT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - *(int *)arg = priv->format.fmt.pix.height; - mp_msg(MSGT_TV, MSGL_V, "%s: get height: %d\n", info.short_name, - *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_CHK_HEIGHT: - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_SET_HEIGHT: - if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; - priv->format.fmt.pix.height = *(int *)arg; - priv->format.fmt.pix.field = V4L2_FIELD_ANY; - mp_msg(MSGT_TV, MSGL_V, "%s: set height: %d\n", info.short_name, - *(int *)arg); - if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set height failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_VID_GET_BRIGHTNESS: - control.id = V4L2_CID_BRIGHTNESS; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_BRIGHTNESS: - control.id = V4L2_CID_BRIGHTNESS; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_HUE: - control.id = V4L2_CID_HUE; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_HUE: - control.id = V4L2_CID_HUE; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_SATURATION: - control.id = V4L2_CID_SATURATION; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_SATURATION: - control.id = V4L2_CID_SATURATION; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_VID_GET_CONTRAST: - control.id = V4L2_CID_CONTRAST; - if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { - *(int *)arg = control.value; - return TVI_CONTROL_TRUE; - } - return TVI_CONTROL_FALSE; - case TVI_CONTROL_VID_SET_CONTRAST: - control.id = V4L2_CID_CONTRAST; - control.value = *(int *)arg; - return set_control(priv, &control, 1); - case TVI_CONTROL_TUN_GET_FREQ: - frequency.tuner = 0; - frequency.type = V4L2_TUNER_ANALOG_TV; - if (ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) { - mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl get frequency failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - *(int *)arg = frequency.frequency; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_FREQ: -#if 0 - set_mute(priv, 1); - usleep(100000); // wait to suppress noise during switching -#endif - frequency.tuner = 0; - frequency.type = V4L2_TUNER_ANALOG_TV; - frequency.frequency = *(int *)arg; - if (ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) { - mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set frequency failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } -#if 0 - usleep(100000); // wait to suppress noise during switching - set_mute(priv, 0); -#endif - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_GET_TUNER: - mp_msg(MSGT_TV, MSGL_V, "%s: get tuner\n",info.short_name); - if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_TUNER: - mp_msg(MSGT_TV, MSGL_V, "%s: set tuner\n",info.short_name); - if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_GET_NORM: - *(int *)arg = priv->standard.index; - return TVI_CONTROL_TRUE; - case TVI_CONTROL_TUN_SET_NORM: - priv->standard.index = *(int *)arg; - if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum norm failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - mp_msg(MSGT_TV, MSGL_V, "%s: set norm: %s\n", info.short_name, priv->standard.name); - if (ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set norm failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_SPC_GET_NORMID: - { - int i; - for (i = 0;; i++) { - struct v4l2_standard standard; - memset(&standard, 0, sizeof(standard)); - standard.index = i; - if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) - return TVI_CONTROL_FALSE; - if (!strcasecmp(standard.name, (char *)arg)) { - *(int *)arg = i; - return TVI_CONTROL_TRUE; - } - } - return TVI_CONTROL_FALSE; - } - case TVI_CONTROL_SPC_GET_INPUT: - if (ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_SPC_SET_INPUT: - mp_msg(MSGT_TV, MSGL_V, "%s: set input: %d\n", info.short_name, *(int *)arg); - priv->input.index = *(int *)arg; - if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum input failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - if (ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set input failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_FORMAT: - init_audio(priv); - if (!priv->audio_inited) return TVI_CONTROL_FALSE; - *(int *)arg = AF_FORMAT_S16_LE; - mp_msg(MSGT_TV, MSGL_V, "%s: get audio format: %d\n", - info.short_name, *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_SAMPLERATE: - init_audio(priv); - if (!priv->audio_inited) return TVI_CONTROL_FALSE; - *(int *)arg = priv->audio_in.samplerate; - mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplerate: %d\n", - info.short_name, *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_SAMPLESIZE: - init_audio(priv); - if (!priv->audio_inited) return TVI_CONTROL_FALSE; - *(int *)arg = priv->audio_in.bytes_per_sample; - mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplesize: %d\n", - info.short_name, *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_GET_CHANNELS: - init_audio(priv); - if (!priv->audio_inited) return TVI_CONTROL_FALSE; - *(int *)arg = priv->audio_in.channels; - mp_msg(MSGT_TV, MSGL_V, "%s: get audio channels: %d\n", - info.short_name, *(int *)arg); - return TVI_CONTROL_TRUE; - case TVI_CONTROL_AUD_SET_SAMPLERATE: - init_audio(priv); - mp_msg(MSGT_TV, MSGL_V, "%s: set audio samplerate: %d\n", - info.short_name, *(int *)arg); - if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; -// setup_audio_buffer_sizes(priv); - return TVI_CONTROL_TRUE; - } - mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd); - return(TVI_CONTROL_UNKNOWN); -} - - -#define PRIV ((priv_t *) (tvi_handle->priv)) - -/* handler creator - entry point ! */ -tvi_handle_t *tvi_init_v4l2(char *video_dev, char *audio_dev) -{ - tvi_handle_t *tvi_handle; - - /* new_handle initializes priv with memset 0 */ - tvi_handle = new_handle(); - if (!tvi_handle) { - return NULL; - } - PRIV->video_fd = -1; - - PRIV->video_dev = strdup(video_dev? video_dev: "/dev/video0"); - if (!PRIV->video_dev) { - free_handle(tvi_handle); - return NULL; - } - - if (audio_dev) { - PRIV->audio_dev = strdup(audio_dev); - if (!PRIV->audio_dev) { - free(PRIV->video_dev); - free_handle(tvi_handle); - return NULL; - } - } - - return tvi_handle; -} - -#undef PRIV - - -static int uninit(priv_t *priv) -{ - int i, frames, dropped = 0; - - priv->shutdown = 1; - if(priv->video_grabber_thread) - pthread_join(priv->video_grabber_thread, NULL); - pthread_mutex_destroy(&priv->video_buffer_mutex); - - if (priv->streamon) { - struct v4l2_buffer buf; - - /* get performance */ - frames = 1 + (priv->curr_frame - priv->first_frame + - priv->standard.frameperiod.numerator * 500000 / - priv->standard.frameperiod.denominator) * - priv->standard.frameperiod.denominator / - priv->standard.frameperiod.numerator / 1000000; - dropped = frames - priv->frames; - - /* turn off streaming */ - if (ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamoff failed: %s\n", - info.short_name, strerror(errno)); - } - priv->streamon = 0; - - /* unqueue all remaining buffers */ - memset(&buf,0,sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf)); - } - - /* unmap all buffers */ - for (i = 0; i < priv->mapcount; i++) { - if (munmap(priv->map[i].addr, priv->map[i].len) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n", - info.short_name, strerror(errno)); - } - } - - /* stop audio thread */ - if (!tv_param_noaudio && priv->audio_grabber_thread) { - pthread_join(priv->audio_grabber_thread, NULL); - pthread_mutex_destroy(&priv->skew_mutex); - pthread_mutex_destroy(&priv->audio_mutex); - } - - set_mute(priv, 1); - - /* free memory and close device */ - free(priv->map); priv->map = NULL; - priv->mapcount = 0; - if(priv->video_fd!=-1)close(priv->video_fd); priv->video_fd = -1; - free(priv->video_dev); priv->video_dev = NULL; - - if (priv->video_ringbuffer) { - int i; - for (i = 0; i < priv->video_buffer_size_current; i++) { - free(priv->video_ringbuffer[i]); - } - free(priv->video_ringbuffer); - } - if (priv->video_timebuffer) - free(priv->video_timebuffer); - if (!tv_param_noaudio) { - if (priv->audio_ringbuffer) - free(priv->audio_ringbuffer); - if (priv->audio_skew_buffer) - free(priv->audio_skew_buffer); - if (priv->audio_skew_delta_buffer) - free(priv->audio_skew_delta_buffer); - } - - /* show some nice statistics ;-) */ - mp_msg(MSGT_TV, MSGL_INFO, - "%s: %d frames successfully processed, %d frames dropped.\n", - info.short_name, priv->frames, dropped); - mp_msg(MSGT_TV, MSGL_V, "%s: up to %u video frames buffered.\n", - info.short_name, priv->video_buffer_size_current); - return 1; -} - - -/* initialisation */ -static int init(priv_t *priv) -{ - int i; - - priv->audio_ringbuffer = NULL; - priv->audio_skew_buffer = NULL; - priv->audio_skew_delta_buffer = NULL; - - priv->audio_inited = 0; - - /* Open the video device. */ - priv->video_fd = open(priv->video_dev, O_RDWR); - if (priv->video_fd < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: unable to open '%s': %s\n", - info.short_name, priv->video_dev, strerror(errno)); - uninit(priv); - return 0; - } - mp_msg(MSGT_TV, MSGL_DBG2, "%s: video fd: %s: %d\n", - info.short_name, priv->video_dev, priv->video_fd); - - /* - ** Query the video capabilities and current settings - ** for further control calls. - */ - if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query capabilities failed: %s\n", - info.short_name, strerror(errno)); - uninit(priv); - return 0; - } - - if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) - { - mp_msg(MSGT_TV, MSGL_ERR, "Device %s is not a video capture device.\n", - priv->video_dev); - return 0; - } - - if (getfmt(priv) < 0) { - uninit(priv); - return 0; - } - getstd(priv); - /* - ** if this device has got a tuner query it's settings - ** otherwise set some nice defaults - */ - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", - info.short_name, strerror(errno)); - uninit(priv); - return 0; - } - } - mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.card); - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - mp_msg(MSGT_TV, MSGL_INFO, " Tuner cap:%s%s%s\n", - (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", - (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", - (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); - mp_msg(MSGT_TV, MSGL_INFO, " Tuner rxs:%s%s%s%s\n", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", - (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); - } - mp_msg(MSGT_TV, MSGL_INFO, " Capabilites:%s%s%s%s%s%s%s%s%s%s%s\n", - priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? - " video capture": "", - priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT? - " video output": "", - priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY? - " video overlay": "", - priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE? - " VBI capture device": "", - priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT? - " VBI output": "", - priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE? - " RDS data capture": "", - priv->capability.capabilities & V4L2_CAP_TUNER? - " tuner": "", - priv->capability.capabilities & V4L2_CAP_AUDIO? - " audio": "", - priv->capability.capabilities & V4L2_CAP_READWRITE? - " read/write": "", - priv->capability.capabilities & V4L2_CAP_ASYNCIO? - " async i/o": "", - priv->capability.capabilities & V4L2_CAP_STREAMING? - " streaming": ""); - mp_msg(MSGT_TV, MSGL_INFO, " supported norms:"); - for (i = 0;; i++) { - struct v4l2_standard standard; - memset(&standard, 0, sizeof(standard)); - standard.index = i; - if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) - break; - mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, standard.name); - } - mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:"); - for (i = 0; 1; i++) { - struct v4l2_input input; - - input.index = i; - if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { - break; - } - mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, input.name); - } - if (ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", - info.short_name, strerror(errno)); - } - mp_msg(MSGT_TV, MSGL_INFO, "\n Current input: %d\n", i); - for (i = 0; ; i++) { - struct v4l2_fmtdesc fmtdesc; - - fmtdesc.index = i; - fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { - break; - } - mp_msg(MSGT_TV, MSGL_V, " Format %-6s (%2d bits, %s): %s\n", - pixfmt2name(fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), - fmtdesc.description, vo_format_name(fcc_vl2mp(fmtdesc.pixelformat))); - } - mp_msg(MSGT_TV, MSGL_INFO, " Current format: %s\n", - pixfmt2name(priv->format.fmt.pix.pixelformat)); - - /* set some nice defaults */ - if (getfmt(priv) < 0) return 0; - priv->format.fmt.pix.width = 640; - priv->format.fmt.pix.height = 480; - if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", - info.short_name, strerror(errno)); - uninit(priv); - return 0; - } - -// if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !tv_param_force_audio) tv_param_noaudio = 1; - - if (priv->capability.capabilities & V4L2_CAP_TUNER) { - struct v4l2_control control; - if (tv_param_amode >= 0) { - mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); - priv->tuner.audmode = amode2v4l(tv_param_amode); - if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", - info.short_name, strerror(errno)); - return TVI_CONTROL_FALSE; - } - } - mp_msg(MSGT_TV, MSGL_INFO, "%s: current audio mode is :%s%s%s%s\n", info.short_name, - (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", - (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); - - if (tv_param_volume >= 0) { - control.id = V4L2_CID_AUDIO_VOLUME; - control.value = tv_param_volume; - set_control(priv, &control, 0); - } - if (tv_param_bass >= 0) { - control.id = V4L2_CID_AUDIO_BASS; - control.value = tv_param_bass; - set_control(priv, &control, 0); - } - if (tv_param_treble >= 0) { - control.id = V4L2_CID_AUDIO_TREBLE; - control.value = tv_param_treble; - set_control(priv, &control, 0); - } - if (tv_param_balance >= 0) { - control.id = V4L2_CID_AUDIO_BALANCE; - control.value = tv_param_balance; - set_control(priv, &control, 0); - } - } - - return 1; -} - -static int get_capture_buffer_size(priv_t *priv) -{ - int bufsize, cnt; - int w = priv->format.fmt.pix.width; - int h = priv->format.fmt.pix.height; - int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); - int bytesperline = w*d/8; - - if (tv_param_buffer_size >= 0) { - bufsize = tv_param_buffer_size*1024*1024; - } else { -#ifdef HAVE_SYS_SYSINFO_H - struct sysinfo si; - - sysinfo(&si); - if (si.totalram<2*1024*1024) { - bufsize = 1024*1024; - } else { - bufsize = si.totalram/2; - } -#else - bufsize = 16*1024*1024; -#endif - } - - cnt = bufsize/(h*bytesperline); - if (cnt < 2) cnt = 2; - - return cnt; -} - -/* that's the real start, we'got the format parameters (checked with control) */ -static int start(priv_t *priv) -{ - struct v4l2_requestbuffers request; - int i; - - /* setup audio parameters */ - - init_audio(priv); - if (!tv_param_noaudio && !priv->audio_inited) return 0; - - /* we need this to size the audio buffer properly */ - if (priv->immediate_mode) { - priv->video_buffer_size_max = 2; - } else { - priv->video_buffer_size_max = get_capture_buffer_size(priv); - } - - if (!tv_param_noaudio) { - setup_audio_buffer_sizes(priv); - priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); - if (!priv->audio_skew_buffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); - return 0; - } - priv->audio_skew_delta_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); - if (!priv->audio_skew_delta_buffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); - return 0; - } - - priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); - if (!priv->audio_ringbuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); - return 0; - } - - priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate - *priv->audio_in.channels - *priv->audio_in.bytes_per_sample); - priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; - priv->audio_head = 0; - priv->audio_tail = 0; - priv->audio_cnt = 0; - priv->audio_drop = 0; - priv->audio_skew = 0; - priv->audio_skew_total = 0; - priv->audio_skew_delta_total = 0; - priv->audio_recv_blocks_total = 0; - priv->audio_sent_blocks_total = 0; - priv->audio_null_blocks_inserted = 0; - priv->audio_insert_null_samples = 0; - priv->dropped_frames_timeshift = 0; - priv->dropped_frames_compensated = 0; - - pthread_mutex_init(&priv->skew_mutex, NULL); - pthread_mutex_init(&priv->audio_mutex, NULL); - } - - /* setup video parameters */ - if (!tv_param_noaudio) { - if (priv->video_buffer_size_max < (3*priv->standard.frameperiod.denominator) / - priv->standard.frameperiod.numerator - *priv->audio_secs_per_block) { - mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" - "You will probably experience heavy framedrops.\n"); - } - } - - { - int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; - - mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", - priv->video_buffer_size_max, - priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); - } - - priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(unsigned char*)); - if (!priv->video_ringbuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); - return 0; - } - for (i = 0; i < priv->video_buffer_size_max; i++) - priv->video_ringbuffer[i] = NULL; - priv->video_timebuffer = calloc(priv->video_buffer_size_max, sizeof(long long)); - if (!priv->video_timebuffer) { - mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); - return 0; - } - - pthread_mutex_init(&priv->video_buffer_mutex, NULL); - - priv->video_head = 0; - priv->video_tail = 0; - priv->video_cnt = 0; - - /* request buffers */ - if (priv->immediate_mode) { - request.count = 2; - } else { - request.count = BUFFER_COUNT; - } - - request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - request.memory = V4L2_MEMORY_MMAP; - if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - - /* query buffers */ - if (!(priv->map = calloc(request.count, sizeof(struct map)))) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - - /* map and queue buffers */ - for (i = 0; i < request.count; i++) { - memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); - priv->map[i].buf.index = i; - priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - priv->map[i].buf.memory = V4L2_MEMORY_MMAP; - if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", - info.short_name, strerror(errno)); - free(priv->map); - priv->map = NULL; - return 0; - } - priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | - PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); - if (priv->map[i].addr == MAP_FAILED) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", - info.short_name, strerror(errno)); - priv->map[i].len = 0; - return 0; - } - priv->map[i].len = priv->map[i].buf.length; - /* count up to make sure this is correct everytime */ - priv->mapcount++; - - if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - } - - /* start audio thread */ - priv->shutdown = 0; - priv->audio_skew_measure_time = 0; - priv->first_frame = 0; - priv->audio_skew = 0; - priv->first = 1; - - set_mute(priv, 0); - - return 1; -} - - -#ifdef HAVE_TV_BSDBT848 -static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) -{ - memset(buffer, 0xCC, len); - return(1); -} -#endif /* HAVE_TV_BSDBT848 */ - -// copies a video frame -static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *source) -{ - int w = priv->format.fmt.pix.width; - int h = priv->format.fmt.pix.height; - int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); - int bytesperline = w*d/8; - - memcpy(dest, source, bytesperline * h); -} - -// maximum skew change, in frames -#define MAX_SKEW_DELTA 0.6 -static void *video_grabber(void *data) -{ - priv_t *priv = (priv_t*)data; - long long skew, prev_skew, xskew, interval, prev_interval, delta; - int i; - int framesize = priv->format.fmt.pix.height*priv->format.fmt.pix.width* - pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; - fd_set rdset; - struct timeval timeout; - struct v4l2_buffer buf; - - xskew = 0; - skew = 0; - interval = 0; - prev_interval = 0; - prev_skew = 0; - - mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name); - if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - priv->streamon = 1; - - if (!tv_param_noaudio) { - pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); - } - - for (priv->frames = 0; !priv->shutdown;) - { - int ret; - - if (priv->immediate_mode) { - while (priv->video_cnt == priv->video_buffer_size_max) { - usleep(10000); - if (priv->shutdown) { - return NULL; - } - } - } - - FD_ZERO (&rdset); - FD_SET (priv->video_fd, &rdset); - - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); - if (i < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n", - info.short_name, strerror(errno)); - continue; - } - else if (i == 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name); - continue; - } - else if (!FD_ISSET(priv->video_fd, &rdset)) { - continue; - } - - memset(&buf,0,sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); - - if (ret < 0) { - /* - if there's no signal, the buffer might me dequeued - so we query all the buffers to see which one we should - put back to queue - - observed with saa7134 0.2.8 - don't know if is it a bug or (mis)feature - */ - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n", - info.short_name, strerror(errno), buf.index); - for (i = 0; i < priv->mapcount; i++) { - memset(&buf,0,sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.index = i; - ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); - if (ret < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n", - info.short_name, strerror(errno), buf.index); - return 0; - } - if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { - if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - } - } - continue; - } - - /* store the timestamp of the very first frame as reference */ - if (!priv->frames++) { - if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); - priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec; - if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); - } - priv->curr_frame = (long long)buf.timestamp.tv_sec*1e6+buf.timestamp.tv_usec; -// fprintf(stderr, "idx = %d, ts = %lf\n", buf.index, (double)(priv->curr_frame) / 1e6); - - interval = priv->curr_frame - priv->first_frame; - delta = interval - prev_interval; - - if (!priv->immediate_mode) { - // interpolate the skew in time - if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); - xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; - if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); - // correct extreme skew changes to avoid (especially) moving backwards in time - if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { - skew = prev_skew + delta*MAX_SKEW_DELTA; - } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { - skew = prev_skew - delta*MAX_SKEW_DELTA; - } else { - skew = xskew; - } - } - - mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n", - delta ? (double)1e6/delta : -1, - (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); - mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); - - prev_skew = skew; - prev_interval = interval; - - /* allocate a new buffer, if needed */ - pthread_mutex_lock(&priv->video_buffer_mutex); - if (priv->video_buffer_size_current < priv->video_buffer_size_max) { - if (priv->video_cnt == priv->video_buffer_size_current) { - unsigned char *newbuf = malloc(framesize); - if (newbuf) { - memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, - (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *)); - memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail, - (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long)); - priv->video_ringbuffer[priv->video_tail] = newbuf; - if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; - priv->video_buffer_size_current++; - } - } - } - pthread_mutex_unlock(&priv->video_buffer_mutex); - - if (priv->video_cnt == priv->video_buffer_size_current) { - if (!priv->immediate_mode) { - mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); - if (priv->audio_insert_null_samples) { - pthread_mutex_lock(&priv->audio_mutex); - priv->dropped_frames_timeshift += delta; - pthread_mutex_unlock(&priv->audio_mutex); - } - } - } else { - if (priv->immediate_mode) { - priv->video_timebuffer[priv->video_tail] = 0; - } else { - // compensate for audio skew - // negative skew => there are more audio samples, increase interval - // positive skew => less samples, shorten the interval - priv->video_timebuffer[priv->video_tail] = interval - skew; - if (priv->audio_insert_null_samples && priv->video_timebuffer[priv->video_tail] > 0) { - pthread_mutex_lock(&priv->audio_mutex); - priv->video_timebuffer[priv->video_tail] += - (priv->audio_null_blocks_inserted - - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) - *priv->audio_usecs_per_block; - pthread_mutex_unlock(&priv->audio_mutex); - } - } - - copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->map[buf.index].addr); - priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; - priv->video_cnt++; - } - if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { - mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", - info.short_name, strerror(errno)); - return 0; - } - } - return NULL; -} - -#define MAX_LOOP 50 -static double grab_video_frame(priv_t *priv, char *buffer, int len) -{ - double interval; - int loop_cnt = 0; - - if (priv->first) { - pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); - priv->first = 0; - } - - while (priv->video_cnt == 0) { - usleep(10000); - if (loop_cnt++ > MAX_LOOP) return 0; - } - - pthread_mutex_lock(&priv->video_buffer_mutex); - interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; - memcpy(buffer, priv->video_ringbuffer[priv->video_head], len); - priv->video_cnt--; - priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; - pthread_mutex_unlock(&priv->video_buffer_mutex); - - return interval; -} - -static int get_video_framesize(priv_t *priv) -{ - return priv->format.fmt.pix.sizeimage; -} - -//#define DOUBLESPEED -#ifdef DOUBLESPEED -// for testing purposes only -static void read_doublespeed(priv_t *priv) -{ - char *bufx = calloc(priv->audio_in.blocksize, 2); - short *s; - short *d; - int i; - - audio_in_read_chunk(&priv->audio_in, bufx); - audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize); - - s = bufx; - d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize; - for (i = 0; i < priv->audio_in.blocksize/2; i++) { - *d++ = *s++; - *s++; - } - -} -#endif - -static void *audio_grabber(void *data) -{ - priv_t *priv = (priv_t*)data; - struct timeval tv; - int i, audio_skew_ptr = 0; - long long current_time, prev_skew = 0, prev_skew_uncorr = 0; - long long start_time_avg; - - gettimeofday(&tv, NULL); - start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; - audio_in_start_capture(&priv->audio_in); - for (i = 0; i < priv->aud_skew_cnt; i++) - priv->audio_skew_buffer[i] = 0; - for (i = 0; i < priv->aud_skew_cnt; i++) - priv->audio_skew_delta_buffer[i] = 0; - - for (; !priv->shutdown;) - { -#ifdef DOUBLESPEED - read_doublespeed(priv); -#else - if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) - continue; -#endif - pthread_mutex_lock(&priv->skew_mutex); - if (priv->first_frame == 0) { - // there is no first frame yet (unlikely to happen) - gettimeofday(&tv, NULL); - start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; -// fprintf(stderr, "warning - first frame not yet available!\n"); - pthread_mutex_unlock(&priv->skew_mutex); - continue; - } - pthread_mutex_unlock(&priv->skew_mutex); - - gettimeofday(&tv, NULL); - - priv->audio_recv_blocks_total++; - current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; - - if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { - start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; - priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); - } - -// fprintf(stderr, "spb = %lf, bs = %d, skew = %lf\n", priv->audio_secs_per_block, priv->audio_in.blocksize, -// (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); - - // put the current skew into the ring buffer - priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; - priv->audio_skew_buffer[audio_skew_ptr] = current_time - - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; - priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; - - pthread_mutex_lock(&priv->skew_mutex); - - // skew calculation - - // compute the sliding average of the skews - if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { - priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; - } else { - priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; - } - - // put the current skew change (skew-prev_skew) into the ring buffer - priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; - priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; - priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; - prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value - - audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer - - // sliding average approximates the value in the middle of the interval - // so interpolate the skew value further to the current time - priv->audio_skew += priv->audio_skew_delta_total/2; - - // now finally, priv->audio_skew contains fairly good approximation - // of the current value - - // current skew factor (assuming linearity) - // used for further interpolation in video_grabber - // probably overkill but seems to be necessary for - // stress testing by dropping half of the audio frames ;) - // especially when using ALSA with large block sizes - // where audio_skew remains a long while behind - if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { - priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); - } else { - priv->audio_skew_factor = 0.0; - } - - priv->audio_skew_measure_time = current_time; - prev_skew = priv->audio_skew; - priv->audio_skew += priv->audio_start_time - priv->first_frame; - pthread_mutex_unlock(&priv->skew_mutex); - -// fprintf(stderr, "audio_skew = %lf, delta = %lf\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); - - pthread_mutex_lock(&priv->audio_mutex); - if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { - mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); - priv->audio_drop++; - } else { - priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; - priv->audio_cnt++; - } - pthread_mutex_unlock(&priv->audio_mutex); - } - return NULL; -} - -static double grab_audio_frame(priv_t *priv, char *buffer, int len) -{ - mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", - priv, buffer, len); - - // hack: if grab_audio_frame is called first, it means we are used by mplayer - // => switch to the mode which outputs audio immediately, even if - // it should be silence - if (priv->first) priv->audio_insert_null_samples = 1; - - pthread_mutex_lock(&priv->audio_mutex); - while (priv->audio_insert_null_samples - && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { - // some frames were dropped - drop the corresponding number of audio blocks - if (priv->audio_drop) { - priv->audio_drop--; - } else { - if (priv->audio_head == priv->audio_tail) break; - priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; - } - priv->dropped_frames_compensated += priv->audio_usecs_per_block; - } - - // compensate for dropped audio frames - if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { - priv->audio_drop--; - memset(buffer, 0, len); - goto out; - } - - if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { - // return silence to avoid desync and stuttering - memset(buffer, 0, len); - priv->audio_null_blocks_inserted++; - goto out; - } - - pthread_mutex_unlock(&priv->audio_mutex); - while (priv->audio_head == priv->audio_tail) { - // this is mencoder => just wait until some audio is available - usleep(10000); - } - pthread_mutex_lock(&priv->audio_mutex); - memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); - priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; - priv->audio_cnt--; -out: - pthread_mutex_unlock(&priv->audio_mutex); - priv->audio_sent_blocks_total++; - return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; -} - -static int get_audio_framesize(priv_t *priv) -{ - return(priv->audio_in.blocksize); -}
--- a/libmpdemux/url.c Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,373 +0,0 @@ -/* - * URL Helper - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - * - */ - -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <ctype.h> -#include <inttypes.h> - -#include "url.h" -#include "mp_msg.h" -#include "help_mp.h" - -#ifndef SIZE_MAX -#define SIZE_MAX ((size_t)-1) -#endif - -URL_t* -url_new(const char* url) { - int pos1, pos2,v6addr = 0; - URL_t* Curl = NULL; - char *escfilename=NULL; - char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL; - int jumpSize = 3; - - if( url==NULL ) return NULL; - - if (strlen(url) > (SIZE_MAX / 3 - 1)) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - escfilename=malloc(strlen(url)*3+1); - if (!escfilename ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - - // Create the URL container - Curl = malloc(sizeof(URL_t)); - if( Curl==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - - // Initialisation of the URL container members - memset( Curl, 0, sizeof(URL_t) ); - - url_escape_string(escfilename,url); - - // Copy the url in the URL container - Curl->url = strdup(escfilename); - if( Curl->url==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - mp_msg(MSGT_OPEN,MSGL_V,"Filename for url is now %s\n",escfilename); - - // extract the protocol - ptr1 = strstr(escfilename, "://"); - if( ptr1==NULL ) { - // Check for a special case: "sip:" (without "//"): - if (strstr(escfilename, "sip:") == escfilename) { - ptr1 = (char *)&url[3]; // points to ':' - jumpSize = 1; - } else { - mp_msg(MSGT_NETWORK,MSGL_V,"Not an URL!\n"); - goto err_out; - } - } - pos1 = ptr1-escfilename; - Curl->protocol = malloc(pos1+1); - if( Curl->protocol==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - strncpy(Curl->protocol, escfilename, pos1); - Curl->protocol[pos1] = '\0'; - - // jump the "://" - ptr1 += jumpSize; - pos1 += jumpSize; - - // check if a username:password is given - ptr2 = strstr(ptr1, "@"); - ptr3 = strstr(ptr1, "/"); - if( ptr3!=NULL && ptr3<ptr2 ) { - // it isn't really a username but rather a part of the path - ptr2 = NULL; - } - if( ptr2!=NULL ) { - // We got something, at least a username... - int len = ptr2-ptr1; - Curl->username = malloc(len+1); - if( Curl->username==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - strncpy(Curl->username, ptr1, len); - Curl->username[len] = '\0'; - - ptr3 = strstr(ptr1, ":"); - if( ptr3!=NULL && ptr3<ptr2 ) { - // We also have a password - int len2 = ptr2-ptr3-1; - Curl->username[ptr3-ptr1]='\0'; - Curl->password = malloc(len2+1); - if( Curl->password==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - strncpy( Curl->password, ptr3+1, len2); - Curl->password[len2]='\0'; - } - ptr1 = ptr2+1; - pos1 = ptr1-escfilename; - } - - // before looking for a port number check if we have an IPv6 type numeric address - // in IPv6 URL the numeric address should be inside square braces. - ptr2 = strstr(ptr1, "["); - ptr3 = strstr(ptr1, "]"); - ptr4 = strstr(ptr1, "/"); - if( ptr2!=NULL && ptr3!=NULL && ptr2 < ptr3 && (!ptr4 || ptr4 > ptr3)) { - // we have an IPv6 numeric address - ptr1++; - pos1++; - ptr2 = ptr3; - v6addr = 1; - } else { - ptr2 = ptr1; - - } - - // look if the port is given - ptr2 = strstr(ptr2, ":"); - // If the : is after the first / it isn't the port - ptr3 = strstr(ptr1, "/"); - if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL; - if( ptr2==NULL ) { - // No port is given - // Look if a path is given - if( ptr3==NULL ) { - // No path/filename - // So we have an URL like http://www.hostname.com - pos2 = strlen(escfilename); - } else { - // We have an URL like http://www.hostname.com/file.txt - pos2 = ptr3-escfilename; - } - } else { - // We have an URL beginning like http://www.hostname.com:1212 - // Get the port number - Curl->port = atoi(ptr2+1); - pos2 = ptr2-escfilename; - } - if( v6addr ) pos2--; - // copy the hostname in the URL container - Curl->hostname = malloc(pos2-pos1+1); - if( Curl->hostname==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - strncpy(Curl->hostname, ptr1, pos2-pos1); - Curl->hostname[pos2-pos1] = '\0'; - - // Look if a path is given - ptr2 = strstr(ptr1, "/"); - if( ptr2!=NULL ) { - // A path/filename is given - // check if it's not a trailing '/' - if( strlen(ptr2)>1 ) { - // copy the path/filename in the URL container - Curl->file = strdup(ptr2); - if( Curl->file==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - } - } - // Check if a filename was given or set, else set it with '/' - if( Curl->file==NULL ) { - Curl->file = malloc(2); - if( Curl->file==NULL ) { - mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); - goto err_out; - } - strcpy(Curl->file, "/"); - } - - free(escfilename); - return Curl; -err_out: - if (escfilename) free(escfilename); - if (Curl) url_free(Curl); - return NULL; -} - -void -url_free(URL_t* url) { - if(!url) return; - if(url->url) free(url->url); - if(url->protocol) free(url->protocol); - if(url->hostname) free(url->hostname); - if(url->file) free(url->file); - if(url->username) free(url->username); - if(url->password) free(url->password); - free(url); -} - - -/* Replace escape sequences in an URL (or a part of an URL) */ -/* works like strcpy(), but without return argument */ -void -url_unescape_string(char *outbuf, const char *inbuf) -{ - unsigned char c,c1,c2; - int i,len=strlen(inbuf); - for (i=0;i<len;i++){ - c = inbuf[i]; - if (c == '%' && i<len-2) { //must have 2 more chars - c1 = toupper(inbuf[i+1]); // we need uppercase characters - c2 = toupper(inbuf[i+2]); - if ( ((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) && - ((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) ) { - if (c1>='0' && c1<='9') c1-='0'; - else c1-='A'-10; - if (c2>='0' && c2<='9') c2-='0'; - else c2-='A'-10; - c = (c1<<4) + c2; - i=i+2; //only skip next 2 chars if valid esc - } - } - *outbuf++ = c; - } - *outbuf++='\0'; //add nullterm to string -} - -static void -url_escape_string_part(char *outbuf, const char *inbuf) { - unsigned char c,c1,c2; - int i,len=strlen(inbuf); - - for (i=0;i<len;i++) { - c = inbuf[i]; - if ((c=='%') && i<len-2 ) { //need 2 more characters - c1=toupper(inbuf[i+1]); c2=toupper(inbuf[i+2]); // need uppercase chars - } else { - c1=129; c2=129; //not escape chars - } - - if( (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - (c >= 0x7f)) { - *outbuf++ = c; - } else if ( c=='%' && ((c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'F')) && - ((c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'F'))) { - // check if part of an escape sequence - *outbuf++=c; // already - - // dont escape again - mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_URL_StringAlreadyEscaped,c,c1,c2); - // error as this should not happen against RFC 2396 - // to escape a string twice - } else { - /* all others will be escaped */ - c1 = ((c & 0xf0) >> 4); - c2 = (c & 0x0f); - if (c1 < 10) c1+='0'; - else c1+='A'-10; - if (c2 < 10) c2+='0'; - else c2+='A'-10; - *outbuf++ = '%'; - *outbuf++ = c1; - *outbuf++ = c2; - } - } - *outbuf++='\0'; -} - -/* Replace specific characters in the URL string by an escape sequence */ -/* works like strcpy(), but without return argument */ -void -url_escape_string(char *outbuf, const char *inbuf) { - unsigned char c; - int i = 0,j,len = strlen(inbuf); - char* tmp,*unesc = NULL, *in; - - // Look if we have an ip6 address, if so skip it there is - // no need to escape anything in there. - tmp = strstr(inbuf,"://["); - if(tmp) { - tmp = strchr(tmp+4,']'); - if(tmp && (tmp[1] == '/' || tmp[1] == ':' || - tmp[1] == '\0')) { - i = tmp+1-inbuf; - strncpy(outbuf,inbuf,i); - outbuf += i; - tmp = NULL; - } - } - - while(i < len) { - // look for the next char that must be kept - for (j=i;j<len;j++) { - c = inbuf[j]; - if(c=='-' || c=='_' || c=='.' || c=='!' || c=='~' || /* mark characters */ - c=='*' || c=='\'' || c=='(' || c==')' || /* do not touch escape character */ - c==';' || c=='/' || c=='?' || c==':' || c=='@' || /* reserved characters */ - c=='&' || c=='=' || c=='+' || c=='$' || c==',') /* see RFC 2396 */ - break; - } - // we are on a reserved char, write it out - if(j == i) { - *outbuf++ = c; - i++; - continue; - } - // we found one, take that part of the string - if(j < len) { - if(!tmp) tmp = malloc(len+1); - strncpy(tmp,inbuf+i,j-i); - tmp[j-i] = '\0'; - in = tmp; - } else // take the rest of the string - in = (char*)inbuf+i; - - if(!unesc) unesc = malloc(len+1); - // unescape first to avoid escaping escape - url_unescape_string(unesc,in); - // then escape, including mark and other reserved chars - // that can come from escape sequences - url_escape_string_part(outbuf,unesc); - outbuf += strlen(outbuf); - i += strlen(in); - } - *outbuf = '\0'; - if(tmp) free(tmp); - if(unesc) free(unesc); -} - -#ifdef __URL_DEBUG -void -url_debug(const URL_t *url) { - if( url==NULL ) { - printf("URL pointer NULL\n"); - return; - } - if( url->url!=NULL ) { - printf("url=%s\n", url->url ); - } - if( url->protocol!=NULL ) { - printf("protocol=%s\n", url->protocol ); - } - if( url->hostname!=NULL ) { - printf("hostname=%s\n", url->hostname ); - } - printf("port=%d\n", url->port ); - if( url->file!=NULL ) { - printf("file=%s\n", url->file ); - } - if( url->username!=NULL ) { - printf("username=%s\n", url->username ); - } - if( url->password!=NULL ) { - printf("password=%s\n", url->password ); - } -} -#endif //__URL_DEBUG
--- a/libmpdemux/url.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * URL Helper - * by Bertrand Baudet <bertrand_baudet@yahoo.com> - * (C) 2001, MPlayer team. - */ - -#ifndef __URL_H -#define __URL_H - -//#define __URL_DEBUG - -typedef struct { - char *url; - char *protocol; - char *hostname; - char *file; - unsigned int port; - char *username; - char *password; -} URL_t; - -URL_t* url_new(const char* url); -void url_free(URL_t* url); - -void url_unescape_string(char *outbuf, const char *inbuf); -void url_escape_string(char *outbuf, const char *inbuf); - -#ifdef __URL_DEBUG -void url_debug(const URL_t* url); -#endif // __URL_DEBUG - -#endif // __URL_H
--- a/libmpdemux/vcd_read.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -//=================== VideoCD ========================== -#if defined(linux) || defined(sun) || defined(__bsdi__) - -typedef struct mp_vcd_priv_st mp_vcd_priv_t; - -#if defined(linux) -#include <linux/cdrom.h> -#elif defined(sun) -#include <sys/cdio.h> -static int sun_vcd_read(mp_vcd_priv_t*, int*); -#elif defined(__bsdi__) -#include <dvd.h> -#endif - -struct mp_vcd_priv_st { - int fd; - struct cdrom_tocentry entry; - char buf[VCD_SECTOR_SIZE]; -}; - -static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect){ - vcd->entry.cdte_addr.msf.frame=sect%75; - sect=sect/75; - vcd->entry.cdte_addr.msf.second=sect%60; - sect=sect/60; - vcd->entry.cdte_addr.msf.minute=sect; -} - -static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd){ - return vcd->entry.cdte_addr.msf.frame + - (vcd->entry.cdte_addr.msf.second+ - vcd->entry.cdte_addr.msf.minute*60)*75; -} - -int vcd_seek_to_track(mp_vcd_priv_t* vcd,int track){ - vcd->entry.cdte_format = CDROM_MSF; - vcd->entry.cdte_track = track; - if (ioctl(vcd->fd, CDROMREADTOCENTRY, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); -} - -int vcd_get_track_end(mp_vcd_priv_t* vcd,int track){ - struct cdrom_tochdr tochdr; - if (ioctl(vcd->fd,CDROMREADTOCHDR,&tochdr)==-1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return -1; - } - vcd->entry.cdte_format = CDROM_MSF; - vcd->entry.cdte_track = track<tochdr.cdth_trk1?(track+1):CDROM_LEADOUT; - if (ioctl(vcd->fd, CDROMREADTOCENTRY, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); -} - -mp_vcd_priv_t* vcd_read_toc(int fd){ - struct cdrom_tochdr tochdr; - mp_vcd_priv_t* vcd; - int i, min = 0, sec = 0, frame = 0; - if (ioctl(fd,CDROMREADTOCHDR,&tochdr)==-1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return NULL; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.cdth_trk0); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.cdth_trk1); - for (i=tochdr.cdth_trk0 ; i<=tochdr.cdth_trk1 + 1; i++){ - struct cdrom_tocentry tocentry; - - tocentry.cdte_track = i<=tochdr.cdth_trk1 ? i : CDROM_LEADOUT; - tocentry.cdte_format = CDROM_MSF; - - if (ioctl(fd,CDROMREADTOCENTRY,&tocentry)==-1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); - return NULL; - } - - if (i<=tochdr.cdth_trk1) - mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d mode: %d\n", - (int)tocentry.cdte_track, - (int)tocentry.cdte_adr, - (int)tocentry.cdte_ctrl, - (int)tocentry.cdte_format, - (int)tocentry.cdte_addr.msf.minute, - (int)tocentry.cdte_addr.msf.second, - (int)tocentry.cdte_addr.msf.frame, - (int)tocentry.cdte_datamode - ); - - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - if (i > tochdr.cdth_trk0) - { - min = tocentry.cdte_addr.msf.minute - min; - sec = tocentry.cdte_addr.msf.second - sec; - frame = tocentry.cdte_addr.msf.frame - frame; - if ( frame < 0 ) - { - frame += 75; - sec --; - } - if ( sec < 0 ) - { - sec += 60; - min --; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); - } - min = tocentry.cdte_addr.msf.minute; - sec = tocentry.cdte_addr.msf.second; - frame = tocentry.cdte_addr.msf.frame; - } - } - vcd = malloc(sizeof(mp_vcd_priv_t)); - vcd->fd = fd; - return vcd; -} - -static int vcd_read(mp_vcd_priv_t* vcd,char *mem){ -#if defined(linux) || defined(__bsdi__) - memcpy(vcd->buf,&vcd->entry.cdte_addr.msf,sizeof(struct cdrom_msf)); - if(ioctl(vcd->fd,CDROMREADRAW,vcd->buf)==-1) return 0; // EOF? - memcpy(mem,&vcd->buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA); -#elif defined(sun) - { - int offset; - if (sun_vcd_read(vcd->fd, &offset) <= 0) return 0; - memcpy(mem,&vcd->buf[offset],VCD_SECTOR_DATA); - } -#endif - - vcd->entry.cdte_addr.msf.frame++; - if (vcd->entry.cdte_addr.msf.frame==75){ - vcd->entry.cdte_addr.msf.frame=0; - vcd->entry.cdte_addr.msf.second++; - if (vcd->entry.cdte_addr.msf.second==60){ - vcd->entry.cdte_addr.msf.second=0; - vcd->entry.cdte_addr.msf.minute++; - } - } - - return VCD_SECTOR_DATA; -} - - -#ifdef sun -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/impl/uscsi.h> - -#define SUN_XAREAD 1 /*fails on atapi drives*/ -#define SUN_MODE2READ 2 /*fails on atapi drives*/ -#define SUN_SCSIREAD 3 -#define SUN_VCDREAD SUN_SCSIREAD - -static int sun_vcd_read(mp_vcd_priv_t* vcd, int *offset) -{ -#if SUN_VCDREAD == SUN_XAREAD - struct cdrom_cdxa cdxa; - cdxa.cdxa_addr = vcd_get_msf(vcd); - cdxa.cdxa_length = 1; - cdxa.cdxa_data = vcd->buf; - cdxa.cdxa_format = CDROM_XA_SECTOR_DATA; - - if(ioctl(vcd->fd,CDROMCDXA,&cdxa)==-1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"CDROMCDXA: %s\n",strerror(errno)); - return 0; - } - *offset = 0; -#elif SUN_VCDREAD == SUN_MODE2READ - struct cdrom_read cdread; - cdread.cdread_lba = 4*vcd_get_msf(vcd); - cdread.cdread_bufaddr = vcd->buf; - cdread.cdread_buflen = 2336; - - if(ioctl(vcd->fd,CDROMREADMODE2,&cdread)==-1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"CDROMREADMODE2: %s\n",strerror(errno)); - return 0; - } - *offset = 8; -#elif SUN_VCDREAD == SUN_SCSIREAD - struct uscsi_cmd sc; - union scsi_cdb cdb; - int lba = vcd_get_msf(vcd); - int blocks = 1; - int sector_type; - int sync, header_code, user_data, edc_ecc, error_field; - int sub_channel; - - /* sector_type = 3; *//* mode2 */ - sector_type = 5; /* mode2/form2 */ - sync = 0; - header_code = 0; - user_data = 1; - edc_ecc = 0; - error_field = 0; - sub_channel = 0; - - memset(&cdb, 0, sizeof(cdb)); - memset(&sc, 0, sizeof(sc)); - cdb.scc_cmd = 0xBE; - cdb.cdb_opaque[1] = (sector_type) << 2; - cdb.cdb_opaque[2] = (lba >> 24) & 0xff; - cdb.cdb_opaque[3] = (lba >> 16) & 0xff; - cdb.cdb_opaque[4] = (lba >> 8) & 0xff; - cdb.cdb_opaque[5] = lba & 0xff; - cdb.cdb_opaque[6] = (blocks >> 16) & 0xff; - cdb.cdb_opaque[7] = (blocks >> 8) & 0xff; - cdb.cdb_opaque[8] = blocks & 0xff; - cdb.cdb_opaque[9] = (sync << 7) | - (header_code << 5) | - (user_data << 4) | - (edc_ecc << 3) | - (error_field << 1); - cdb.cdb_opaque[10] = sub_channel; - - sc.uscsi_cdb = (caddr_t)&cdb; - sc.uscsi_cdblen = 12; - sc.uscsi_bufaddr = vcd->buf; - sc.uscsi_buflen = 2336; - sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ; - sc.uscsi_timeout = 20; - if (ioctl(vcd->fd, USCSICMD, &sc)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"USCSICMD: READ CD: %s\n",strerror(errno)); - return -1; - } - if (sc.uscsi_status) { - mp_msg(MSGT_STREAM,MSGL_ERR,"scsi command failed with status %d\n", sc.uscsi_status); - return -1; - } - *offset = 0; - return 1; -#else -#error SUN_VCDREAD -#endif -} -#endif /*sun*/ - -#else /* linux || sun || __bsdi__ */ - -#error vcd is not yet supported on this arch... - -#endif
--- a/libmpdemux/vcd_read_darwin.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -#include <sys/types.h> -#include <CoreFoundation/CFBase.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/storage/IOCDTypes.h> -#include <IOKit/storage/IOCDMedia.h> -#include <IOKit/storage/IOCDMediaBSDClient.h> - -//=================== VideoCD ========================== -#define CDROM_LEADOUT 0xAA - -typedef struct -{ - uint8_t sync [12]; - uint8_t header [4]; - uint8_t subheader [8]; - uint8_t data [2324]; - uint8_t spare [4]; -} cdsector_t; - -typedef struct mp_vcd_priv_st -{ - int fd; - dk_cd_read_track_info_t entry; - CDMSF msf; - cdsector_t buf; -} mp_vcd_priv_t; - -static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect) -{ - vcd->msf.frame=sect%75; - sect=sect/75; - vcd->msf.second=sect%60; - sect=sect/60; - vcd->msf.minute=sect; -} - -static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd) -{ - return vcd->msf.frame + - (vcd->msf.second+ - vcd->msf.minute*60)*75; - -return 0; -} - -int vcd_seek_to_track(mp_vcd_priv_t* vcd, int track) -{ - dk_cd_read_track_info_t tocentry; - struct CDTrackInfo entry; - - memset( &vcd->entry, 0, sizeof(vcd->entry)); - vcd->entry.addressType = kCDTrackInfoAddressTypeTrackNumber; - vcd->entry.address = track; - vcd->entry.bufferLength = sizeof(entry); - vcd->entry.buffer = &entry; - - if (ioctl(vcd->fd, DKIOCCDREADTRACKINFO, &vcd->entry)) - { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); - -return -1; -} - -int vcd_get_track_end(mp_vcd_priv_t* vcd, int track) -{ - dk_cd_read_disc_info_t tochdr; - struct CDDiscInfo hdr; - - dk_cd_read_track_info_t tocentry; - struct CDTrackInfo entry; - - //read toc header - memset(&tochdr, 0, sizeof(tochdr)); - tochdr.buffer = &hdr; - tochdr.bufferLength = sizeof(hdr); - - if (ioctl(vcd->fd, DKIOCCDREADDISCINFO, &tochdr) < 0) - { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return NULL; - } - - //read track info - memset( &vcd->entry, 0, sizeof(vcd->entry)); - vcd->entry.addressType = kCDTrackInfoAddressTypeTrackNumber; - vcd->entry.address = track<(hdr.lastTrackNumberInLastSessionLSB+1)?(track):CDROM_LEADOUT; - vcd->entry.bufferLength = sizeof(entry); - vcd->entry.buffer = &entry; - - if (ioctl(vcd->fd, DKIOCCDREADTRACKINFO, &vcd->entry)) - { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); - -return -1; -} - -mp_vcd_priv_t* vcd_read_toc(int fd) -{ - dk_cd_read_disc_info_t tochdr; - struct CDDiscInfo hdr; - - dk_cd_read_track_info_t tocentry; - struct CDTrackInfo entry; - CDMSF trackMSF; - - mp_vcd_priv_t* vcd; - int i, min = 0, sec = 0, frame = 0; - - //read toc header - memset(&tochdr, 0, sizeof(tochdr)); - tochdr.buffer = &hdr; - tochdr.bufferLength = sizeof(hdr); - - if (ioctl(fd, DKIOCCDREADDISCINFO, &tochdr) < 0) - { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return NULL; - } - - //print all track info - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", hdr.firstTrackNumberInLastSessionLSB); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", hdr.lastTrackNumberInLastSessionLSB); - for (i=hdr.firstTrackNumberInLastSessionLSB ; i<=hdr.lastTrackNumberInLastSessionLSB + 1; i++) - { - memset( &tocentry, 0, sizeof(tocentry)); - tocentry.addressType = kCDTrackInfoAddressTypeTrackNumber; - tocentry.address = i<=hdr.lastTrackNumberInLastSessionLSB ? i : CDROM_LEADOUT; - tocentry.bufferLength = sizeof(entry); - tocentry.buffer = &entry; - - if (ioctl(fd,DKIOCCDREADTRACKINFO,&tocentry)==-1) - { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); - return NULL; - } - - trackMSF = CDConvertLBAToMSF(entry.trackStartAddress); - - //mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", - if (i<=hdr.lastTrackNumberInLastSessionLSB) - mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: format=%d %02d:%02d:%02d\n", - (int)tocentry.address, - //(int)tocentry.entry.addr_type, - //(int)tocentry.entry.control, - (int)tocentry.addressType, - (int)trackMSF.minute, - (int)trackMSF.second, - (int)trackMSF.frame - ); - - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - if (i > hdr.firstTrackNumberInLastSessionLSB) - { - min = trackMSF.minute - min; - sec = trackMSF.second - sec; - frame = trackMSF.frame - frame; - if ( frame < 0 ) - { - frame += 75; - sec --; - } - if ( sec < 0 ) - { - sec += 60; - min --; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); - } - min = trackMSF.minute; - sec = trackMSF.second; - frame = trackMSF.frame; - } - } - - vcd = malloc(sizeof(mp_vcd_priv_t)); - vcd->fd = fd; - vcd->msf = trackMSF; - return vcd; - - return NULL; -} - -static int vcd_read(mp_vcd_priv_t* vcd,char *mem) -{ - if (pread(vcd->fd,&vcd->buf,VCD_SECTOR_SIZE,vcd_get_msf(vcd)*VCD_SECTOR_SIZE) != VCD_SECTOR_SIZE) - return 0; // EOF? - - vcd->msf.frame++; - if (vcd->msf.frame==75) - { - vcd->msf.frame=0; - vcd->msf.second++; - - if (vcd->msf.second==60) - { - vcd->msf.second=0; - vcd->msf.minute++; - } - } - - memcpy(mem,vcd->buf.data,VCD_SECTOR_DATA); - return VCD_SECTOR_DATA; -return 0; -} -
--- a/libmpdemux/vcd_read_fbsd.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -#include <sys/cdio.h> -#include <sys/cdrio.h> - -//=================== VideoCD ========================== -#define CDROM_LEADOUT 0xAA - -typedef struct { - uint8_t sync [12]; - uint8_t header [4]; - uint8_t subheader [8]; - uint8_t data [2324]; - uint8_t spare [4]; -} cdsector_t; - -typedef struct mp_vcd_priv_st { - int fd; - struct ioc_read_toc_single_entry entry; - cdsector_t buf; -} mp_vcd_priv_t; - -static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect){ - vcd->entry.entry.addr.msf.frame=sect%75; - sect=sect/75; - vcd->entry.entry.addr.msf.second=sect%60; - sect=sect/60; - vcd->entry.entry.addr.msf.minute=sect; -} - -static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd){ - return vcd->entry.entry.addr.msf.frame + - (vcd->entry.entry.addr.msf.second+ - vcd->entry.entry.addr.msf.minute*60)*75; -} - -int vcd_seek_to_track(mp_vcd_priv_t* vcd, int track){ - vcd->entry.address_format = CD_MSF_FORMAT; - vcd->entry.track = track; - if (ioctl(vcd->fd, CDIOREADTOCENTRY, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); -} - -int vcd_get_track_end(mp_vcd_priv_t* vcd, int track){ - struct ioc_toc_header tochdr; - if (ioctl(vcd->fd,CDIOREADTOCHEADER,&tochdr)==-1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return -1; - } - vcd->entry.address_format = CD_MSF_FORMAT; - vcd->entry.track = track<tochdr.ending_track?(track+1):CDROM_LEADOUT; - if (ioctl(vcd->fd, CDIOREADTOCENTRY, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA*vcd_get_msf(vcd); -} - -mp_vcd_priv_t* vcd_read_toc(int fd){ - struct ioc_toc_header tochdr; - mp_vcd_priv_t* vcd; - int i, min = 0, sec = 0, frame = 0; - if (ioctl(fd,CDIOREADTOCHEADER,&tochdr)==-1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return NULL; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.starting_track); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.ending_track); - for (i=tochdr.starting_track ; i<=tochdr.ending_track + 1; i++){ - struct ioc_read_toc_single_entry tocentry; - - tocentry.track = i<=tochdr.ending_track ? i : CDROM_LEADOUT; - tocentry.address_format = CD_MSF_FORMAT; - - if (ioctl(fd,CDIOREADTOCENTRY,&tocentry)==-1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); - return NULL; - } - - if (i<=tochdr.ending_track) - mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", - (int)tocentry.track, - (int)tocentry.entry.addr_type, - (int)tocentry.entry.control, - (int)tocentry.address_format, - (int)tocentry.entry.addr.msf.minute, - (int)tocentry.entry.addr.msf.second, - (int)tocentry.entry.addr.msf.frame - ); - - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - if (i > tochdr.starting_track) - { - min = tocentry.entry.addr.msf.minute - min; - sec = tocentry.entry.addr.msf.second - sec; - frame = tocentry.entry.addr.msf.frame - frame; - if ( frame < 0 ) - { - frame += 75; - sec --; - } - if ( sec < 0 ) - { - sec += 60; - min --; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); - } - min = tocentry.entry.addr.msf.minute; - sec = tocentry.entry.addr.msf.second; - frame = tocentry.entry.addr.msf.frame; - } - } - vcd = malloc(sizeof(mp_vcd_priv_t)); - vcd->fd = fd; - return vcd; -} - -static int vcd_read(mp_vcd_priv_t* vcd,char *mem){ - - if (pread(vcd->fd,&vcd->buf,VCD_SECTOR_SIZE,vcd_get_msf(vcd)*VCD_SECTOR_SIZE) - != VCD_SECTOR_SIZE) return 0; // EOF? - - vcd->entry.entry.addr.msf.frame++; - if (vcd->entry.entry.addr.msf.frame==75){ - vcd->entry.entry.addr.msf.frame=0; - vcd->entry.entry.addr.msf.second++; - if (vcd->entry.entry.addr.msf.second==60){ - vcd->entry.entry.addr.msf.second=0; - vcd->entry.entry.addr.msf.minute++; - } - } - memcpy(mem,vcd->buf.data,VCD_SECTOR_DATA); - return VCD_SECTOR_DATA; -} -
--- a/libmpdemux/vcd_read_nbsd.h Mon Jul 31 12:35:04 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +0,0 @@ - -#include <sys/types.h> -#ifdef __NetBSD__ -#include <sys/inttypes.h> -#endif -#include <sys/cdio.h> -#include <sys/scsiio.h> - -#define CDROM_LEADOUT 0xAA - -typedef struct mp_vcd_priv_st { - int fd; - struct ioc_read_toc_entry entry; - struct cd_toc_entry entry_data; -} mp_vcd_priv_t; - -static inline void -vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect) -{ - vcd->entry_data.addr.msf.frame = sect % 75; - sect = sect / 75; - vcd->entry_data.addr.msf.second = sect % 60; - sect = sect / 60; - vcd->entry_data.addr.msf.minute = sect; -} - -static inline void -vcd_inc_msf(mp_vcd_priv_t* vcd) -{ - vcd->entry_data.addr.msf.frame++; - if (vcd->entry_data.addr.msf.frame==75){ - vcd->entry_data.addr.msf.frame=0; - vcd->entry_data.addr.msf.second++; - if (vcd->entry_data.addr.msf.second==60){ - vcd->entry_data.addr.msf.second=0; - vcd->entry_data.addr.msf.minute++; - } - } -} - -static inline unsigned int -vcd_get_msf(mp_vcd_priv_t* vcd) -{ - return vcd->entry_data.addr.msf.frame + - (vcd->entry_data.addr.msf.second + - vcd->entry_data.addr.msf.minute * 60) * 75; -} - -int -vcd_seek_to_track(mp_vcd_priv_t* vcd, int track) -{ - vcd->entry.address_format = CD_MSF_FORMAT; - vcd->entry.starting_track = track; - vcd->entry.data_len = sizeof(struct cd_toc_entry); - vcd->entry.data = &vcd->entry_data; - if (ioctl(vcd->fd, CDIOREADTOCENTRIES, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA * vcd_get_msf(vcd); -} - -int -vcd_get_track_end(mp_vcd_priv_t* vcd, int track) -{ - struct ioc_toc_header tochdr; - if (ioctl(vcd->fd, CDIOREADTOCHEADER, &tochdr) == -1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return -1; - } - vcd->entry.address_format = CD_MSF_FORMAT; - vcd->entry.starting_track = track < tochdr.ending_track ? (track + 1) : CDROM_LEADOUT; - vcd->entry.data_len = sizeof(struct cd_toc_entry); - vcd->entry.data = &vcd->entry_data; - if (ioctl(vcd->fd, CDIOREADTOCENTRYS, &vcd->entry)) { - mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); - return -1; - } - return VCD_SECTOR_DATA * vcd_get_msf(vcd); -} - -mp_vcd_priv_t* -vcd_read_toc(int fd) -{ - struct ioc_toc_header tochdr; - mp_vcd_priv_t* vcd; - int i, min = 0, sec = 0, frame = 0; - if (ioctl(fd, CDIOREADTOCHEADER, &tochdr) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); - return; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.starting_track); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.ending_track); - for (i = tochdr.starting_track; i <= tochdr.ending_track + 1; i++) { - struct ioc_read_toc_entry tocentry; - struct cd_toc_entry tocentry_data; - - tocentry.starting_track = i<=tochdr.ending_track ? i : CDROM_LEADOUT; - tocentry.address_format = CD_MSF_FORMAT; - tocentry.data_len = sizeof(struct cd_toc_entry); - tocentry.data = &tocentry_data; - - if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); - return NULL; - } - if (i <= tochdr.ending_track) - mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", - (int) tocentry.starting_track, - (int) tocentry.data->addr_type, - (int) tocentry.data->control, - (int) tocentry.address_format, - (int) tocentry.data->addr.msf.minute, - (int) tocentry.data->addr.msf.second, - (int) tocentry.data->addr.msf.frame - ); - - if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - { - if (i > tochdr.starting_track) - { - min = tocentry.data->addr.msf.minute - min; - sec = tocentry.data->addr.msf.second - sec; - frame = tocentry.data->addr.msf.frame - frame; - if ( frame < 0 ) - { - frame += 75; - sec --; - } - if ( sec < 0 ) - { - sec += 60; - min --; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); - } - min = tocentry.data->addr.msf.minute; - sec = tocentry.data->addr.msf.second; - frame = tocentry.data->addr.msf.frame; - } - } - vcd = malloc(sizeof(mp_vcd_priv_t)); - vcd->fd = fd; - return vcd; -} - -static int -vcd_read(mp_vcd_priv_t* vcd, char *mem) -{ - struct scsireq sc; - int lba = vcd_get_msf(vcd); - int blocks; - int sector_type; - int sync, header_code, user_data, edc_ecc, error_field; - int sub_channel; - int rc; - - blocks = 1; - sector_type = 5; /* mode2/form2 */ - sync = 0; - header_code = 0; - user_data = 1; - edc_ecc = 0; - error_field = 0; - sub_channel = 0; - - memset(&sc, 0, sizeof(sc)); - sc.cmd[0] = 0xBE; - sc.cmd[1] = (sector_type) << 2; - sc.cmd[2] = (lba >> 24) & 0xff; - sc.cmd[3] = (lba >> 16) & 0xff; - sc.cmd[4] = (lba >> 8) & 0xff; - sc.cmd[5] = lba & 0xff; - sc.cmd[6] = (blocks >> 16) & 0xff; - sc.cmd[7] = (blocks >> 8) & 0xff; - sc.cmd[8] = blocks & 0xff; - sc.cmd[9] = (sync << 7) | (header_code << 5) | (user_data << 4) | - (edc_ecc << 3) | (error_field << 1); - sc.cmd[10] = sub_channel; - sc.cmdlen = 12; - sc.databuf = (caddr_t) mem; - sc.datalen = 2328; - sc.senselen = sizeof(sc.sense); - sc.flags = SCCMD_READ; - sc.timeout = 10000; - rc = ioctl(vcd->fd, SCIOCCOMMAND, &sc); - if (rc == -1) { - mp_msg(MSGT_STREAM,MSGL_ERR,"SCIOCCOMMAND: %s\n",strerror(errno)); - return -1; - } - if (sc.retsts || sc.error) { - mp_msg(MSGT_STREAM,MSGL_ERR,"scsi command failed: status %d error %d\n", - sc.retsts,sc.error); - return -1; - } - vcd_inc_msf(vcd); - return VCD_SECTOR_DATA; -} -
--- a/m_option.c Mon Jul 31 12:35:04 2006 +0000 +++ b/m_option.c Mon Jul 31 17:39:17 2006 +0000 @@ -15,7 +15,7 @@ #include "m_option.h" //#include "m_config.h" #include "mp_msg.h" -#include "libmpdemux/url.h" +#include "stream/url.h" // Don't free for 'production' atm #ifndef MP_DEBUG
--- a/mencoder.c Mon Jul 31 12:35:04 2006 +0000 +++ b/mencoder.c Mon Jul 31 17:39:17 2006 +0000 @@ -48,7 +48,7 @@ #include "m_config.h" #include "parser-mecmd.h" -#include "libmpdemux/stream.h" +#include "stream/stream.h" #include "libmpdemux/demuxer.h" #include "libmpdemux/stheader.h" #include "libmpdemux/mp3_hdr.h" @@ -76,7 +76,7 @@ #include "get_path.c" #ifdef USE_DVDREAD -#include "libmpdemux/stream_dvd.h" +#include "stream/stream_dvd.h" #endif #ifdef USE_LIBAVCODEC
--- a/mplayer.c Mon Jul 31 12:35:04 2006 +0000 +++ b/mplayer.c Mon Jul 31 17:39:17 2006 +0000 @@ -106,11 +106,11 @@ #endif /* HAVE_RTC */ #ifdef USE_TV -#include "libmpdemux/tv.h" +#include "stream/tv.h" #endif #ifdef HAS_DVBIN_SUPPORT -#include "libmpdemux/dvbin.h" +#include "stream/dvbin.h" static int last_dvb_step = 1; static int dvbin_reopen = 0; extern void cache_uninit(stream_t *s); @@ -175,14 +175,14 @@ static int max_framesize=0; -#include "libmpdemux/stream.h" +#include "stream/stream.h" #include "libmpdemux/demuxer.h" #include "libmpdemux/stheader.h" //#include "parse_es.h" #include "libmpdemux/matroska.h" #ifdef USE_DVDREAD -#include "libmpdemux/stream_dvd.h" +#include "stream/stream_dvd.h" #endif #include "libmpcodecs/dec_audio.h"
--- a/osdep/macosx_finder_args.c Mon Jul 31 12:35:04 2006 +0000 +++ b/osdep/macosx_finder_args.c Mon Jul 31 17:39:17 2006 +0000 @@ -1,6 +1,6 @@ #include <Carbon/Carbon.h> #include <ApplicationServices/ApplicationServices.h> -#include "libmpdemux/url.h" +#include "stream/url.h" #include "mp_msg.h" #include "m_option.h" #include "m_config.h"
--- a/playtreeparser.c Mon Jul 31 12:35:04 2006 +0000 +++ b/playtreeparser.c Mon Jul 31 17:39:17 2006 +0000 @@ -18,7 +18,7 @@ #include "m_config.h" #include "playtree.h" #include "playtreeparser.h" -#include "libmpdemux/stream.h" +#include "stream/stream.h" #include "libmpdemux/demuxer.h" #include "mp_msg.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/Makefile Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,151 @@ + +LIBNAME = stream.a + +include ../config.mak + +# Core +SRCS += mf.c \ + open.c \ + url.c \ + +ifeq ($(STREAM_CACHE),yes) +SRCS += cache2.c +endif + +# Miscellaneous +SRCS += cdinfo.c \ + cue_read.c \ + +ifeq ($(CDDA),yes) +SRCS += cdda.c + ifeq ($(MPLAYER_NETWORK),yes) + SRCS += cddb.c + endif +endif + +# Stream readers/writers +SRCS += stream.c \ + stream_file.c \ + stream_null.c \ + +ifeq ($(HAVE_DVD),yes) +SRCS += stream_dvd.c +endif +ifeq ($(DVDNAV),yes) +SRCS += dvdnav_stream.c +endif +ifeq ($(VCD),yes) +SRCS += stream_vcd.c +endif +ifeq ($(FTP),yes) +SRCS += stream_ftp.c +endif +ifeq ($(LIBSMBCLIENT),yes) +SRCS += stream_smb.c +endif +ifeq ($(MPLAYER_NETWORK),yes) + SRCS += stream_netstream.c + ifeq ($(STREAMING_LIVE555),yes) + SRCS += stream_livedotcom.c + endif +endif +ifeq ($(VSTREAM),yes) +SRCS += stream_vstream.c +endif + +# TV in +ifeq ($(TV),yes) +SRCS += tv.c frequencies.c tvi_dummy.c + ifeq ($(TV_BSDBT848),yes) + SRCS += tvi_bsdbt848.c + endif + ifeq ($(TV_V4L2),yes) + SRCS += tvi_v4l2.c audio_in.c + ifeq ($(PVR),yes) + SRCS += stream_pvr.c + endif + endif + ifeq ($(TV_V4L1),yes) + SRCS += tvi_v4l.c audio_in.c + endif + ifeq ($(TV_V4L),yes) + ifeq ($(ALSA1X),yes) + SRCS += ai_alsa1x.c + endif + ifeq ($(ALSA9),yes) + SRCS += ai_alsa.c + endif + ifeq ($(OSS),yes) + SRCS += ai_oss.c + endif + endif +endif + +ifeq ($(MPLAYER_NETWORK),yes) +SRCS += asf_streaming.c \ + http.c \ + network.c \ + cookies.c \ + asf_mmst_streaming.c \ + pnm.c \ + rtp.c \ + stream_rtsp.c \ + +SRCS += realrtsp/asmrp.c \ + realrtsp/real.c \ + realrtsp/rmff.c \ + realrtsp/sdpplin.c \ + realrtsp/xbuffer.c \ + +SRCS += librtsp/rtsp.c \ + librtsp/rtsp_rtp.c \ + librtsp/rtsp_session.c \ + +SRCS += freesdp/common.c \ + freesdp/errorlist.c \ + freesdp/parser.c \ + +endif + +ifeq ($(DVBIN),yes) +SRCS += dvbin.c +SRCS += dvb_tune.c +endif + +OBJS = $(SRCS:.c=.o) +INCLUDE = -I.. -I../libmpdemux -I../loader $(LIBAV_INC) +CFLAGS = $(OPTFLAGS) $(INCLUDE) $(XMMS_CFLAGS) + +.SUFFIXES: .c .o + +# .PHONY: all clean + +all: $(LIBNAME) + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +$(LIBNAME): $(OBJS) + $(AR) r $(LIBNAME) $(OBJS) + $(RANLIB) $(LIBNAME) + +clean: + rm -f *.o *.a *~ \ + realrtsp/*.o realrtsp/*.a realrtsp/*~ \ + librtsp/*.o librtsp/*.a librtsp/*~ \ + freesdp/*.o freesdp/*.a freesdp/*~ + +distclean: clean + rm -f .depend test + +dep: depend + +depend: + $(CC) -MM $(CFLAGS) test.c $(SRCS) 1>.depend + +# +# include dependency files if they exist +# +ifneq ($(wildcard .depend),) +include .depend +endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/ai_alsa.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,166 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + +#include "config.h" + +#include <alsa/asoundlib.h> +#include "audio_in.h" +#include "mp_msg.h" +#include "help_mp.h" + +int ai_alsa_setup(audio_in_t *ai) +{ + snd_pcm_hw_params_t *params; + snd_pcm_sw_params_t *swparams; + int buffer_size; + int err; + unsigned int rate; + + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_sw_params_alloca(&swparams); + + err = snd_pcm_hw_params_any(ai->alsa.handle, params); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); + return -1; + } + err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); + return -1; + } + err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); + return -1; + } + err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); + if (err < 0) { + ai->channels = snd_pcm_hw_params_get_channels(params); + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, + ai->channels); + } else { + ai->channels = ai->req_channels; + } + + err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0); + assert(err >= 0); + rate = err; + ai->samplerate = rate; + + ai->alsa.buffer_time = 1000000; + ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, + ai->alsa.buffer_time, 0); + assert(ai->alsa.buffer_time >= 0); + ai->alsa.period_time = ai->alsa.buffer_time / 4; + ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, + ai->alsa.period_time, 0); + assert(ai->alsa.period_time >= 0); + err = snd_pcm_hw_params(ai->alsa.handle, params); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams); + snd_pcm_hw_params_dump(params, ai->alsa.log); + return -1; + } + ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0); + buffer_size = snd_pcm_hw_params_get_buffer_size(params); + if (ai->alsa.chunk_size == buffer_size) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); + return -1; + } + snd_pcm_sw_params_current(ai->alsa.handle, swparams); + err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); + assert(err >= 0); + err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); + assert(err >= 0); + + err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); + assert(err >= 0); + err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); + assert(err >= 0); + + assert(err >= 0); + if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); + snd_pcm_sw_params_dump(swparams, ai->alsa.log); + return -1; + } + + if (mp_msg_test(MSGT_TV, MSGL_V)) { + snd_pcm_dump(ai->alsa.handle, ai->alsa.log); + } + + ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); + ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; + ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; + ai->samplesize = ai->alsa.bits_per_sample; + ai->bytes_per_sample = ai->alsa.bits_per_sample/8; + + return 0; +} + +int ai_alsa_init(audio_in_t *ai) +{ + int err; + + err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err)); + return -1; + } + + err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0); + + if (err < 0) { + return -1; + } + + err = ai_alsa_setup(ai); + + return err; +} + +#ifndef timersub +#define timersub(a, b, result) \ +do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ +} while (0) +#endif + +int ai_alsa_xrun(audio_in_t *ai) +{ + snd_pcm_status_t *status; + int res; + + snd_pcm_status_alloca(&status); + if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res)); + return -1; + } + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { + struct timeval now, diff, tstamp; + gettimeofday(&now, 0); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN, + diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + if (mp_msg_test(MSGT_TV, MSGL_V)) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus); + snd_pcm_status_dump(status, ai->alsa.log); + } + if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res)); + return -1; + } + return 0; /* ok, data should be accepted again */ + } + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError); + return -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/ai_alsa1x.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,185 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + +#include "config.h" + +#include <alsa/asoundlib.h> +#include "audio_in.h" +#include "mp_msg.h" +#include "help_mp.h" + +int ai_alsa_setup(audio_in_t *ai) +{ + snd_pcm_hw_params_t *params; + snd_pcm_sw_params_t *swparams; + snd_pcm_uframes_t buffer_size, period_size; + int err; + int dir; + unsigned int rate; + + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_sw_params_alloca(&swparams); + + err = snd_pcm_hw_params_any(ai->alsa.handle, params); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); + return -1; + } + + err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); + return -1; + } + + err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); + return -1; + } + + err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); + if (err < 0) { + snd_pcm_hw_params_get_channels(params, &ai->channels); + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, + ai->channels); + } else { + ai->channels = ai->req_channels; + } + + dir = 0; + rate = ai->req_samplerate; + err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetSamplerate); + } + ai->samplerate = rate; + + dir = 0; + ai->alsa.buffer_time = 1000000; + err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, + &ai->alsa.buffer_time, &dir); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetBufferTime); + } + + dir = 0; + ai->alsa.period_time = ai->alsa.buffer_time / 4; + err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, + &ai->alsa.period_time, &dir); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA1X_CannotSetPeriodTime); + } + + err = snd_pcm_hw_params(ai->alsa.handle, params); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams, snd_strerror(err)); + snd_pcm_hw_params_dump(params, ai->alsa.log); + return -1; + } + + dir = -1; + snd_pcm_hw_params_get_period_size(params, &period_size, &dir); + snd_pcm_hw_params_get_buffer_size(params, &buffer_size); + ai->alsa.chunk_size = period_size; + if (period_size == buffer_size) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); + return -1; + } + + snd_pcm_sw_params_current(ai->alsa.handle, swparams); + err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); + assert(err >= 0); + err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); + assert(err >= 0); + + err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); + assert(err >= 0); + err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); + assert(err >= 0); + + assert(err >= 0); + if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); + snd_pcm_sw_params_dump(swparams, ai->alsa.log); + return -1; + } + + if (mp_msg_test(MSGT_TV, MSGL_V)) { + snd_pcm_dump(ai->alsa.handle, ai->alsa.log); + } + + ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); + ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; + ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; + ai->samplesize = ai->alsa.bits_per_sample; + ai->bytes_per_sample = ai->alsa.bits_per_sample/8; + + return 0; +} + +int ai_alsa_init(audio_in_t *ai) +{ + int err; + + err = snd_pcm_open(&ai->alsa.handle, ai->alsa.device, SND_PCM_STREAM_CAPTURE, 0); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_ErrorOpeningAudio, snd_strerror(err)); + return -1; + } + + err = snd_output_stdio_attach(&ai->alsa.log, stderr, 0); + + if (err < 0) { + return -1; + } + + err = ai_alsa_setup(ai); + + return err; +} + +#ifndef timersub +#define timersub(a, b, result) \ +do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ +} while (0) +#endif + +int ai_alsa_xrun(audio_in_t *ai) +{ + snd_pcm_status_t *status; + int res; + + snd_pcm_status_alloca(&status); + if ((res = snd_pcm_status(ai->alsa.handle, status))<0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatusError, snd_strerror(res)); + return -1; + } + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { + struct timeval now, diff, tstamp; + gettimeofday(&now, 0); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUN, + diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + if (mp_msg_test(MSGT_TV, MSGL_V)) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaStatus); + snd_pcm_status_dump(status, ai->alsa.log); + } + if ((res = snd_pcm_prepare(ai->alsa.handle))<0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaXRUNPrepareError, snd_strerror(res)); + return -1; + } + return 0; /* ok, data should be accepted again */ + } + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_AlsaReadWriteError); + return -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/ai_oss.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,139 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "config.h" + +#include <string.h> /* strerror */ +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> + +#ifdef HAVE_SYS_SOUNDCARD_H +#include <sys/soundcard.h> +#else +#ifdef HAVE_SOUNDCARD_H +#include <soundcard.h> +#else +#include <linux/soundcard.h> +#endif +#endif + +#include "audio_in.h" +#include "mp_msg.h" +#include "help_mp.h" + +int ai_oss_set_samplerate(audio_in_t *ai) +{ + int tmp = ai->req_samplerate; + if (ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &tmp) == -1) return -1; + ai->samplerate = tmp; + return 0; +} + +int ai_oss_set_channels(audio_in_t *ai) +{ + int err; + int ioctl_param; + + if (ai->req_channels > 2) + { + ioctl_param = ai->req_channels; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp channels: %d\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_CHANNELS, &ioctl_param)); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetChanCount, + ai->req_channels); + return -1; + } + ai->channels = ioctl_param; + } + else + { + ioctl_param = (ai->req_channels == 2); + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp stereo: %d (req: %d)\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_STEREO, &ioctl_param), + ioctl_param); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetStereo, + ai->req_channels == 2); + return -1; + } + ai->channels = ioctl_param ? 2 : 1; + } + return 0; +} + +int ai_oss_init(audio_in_t *ai) +{ + int err; + int ioctl_param; + + ai->oss.audio_fd = open(ai->oss.device, O_RDONLY); + if (ai->oss.audio_fd < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2Open, + ai->oss.device, strerror(errno)); + return -1; + } + + ioctl_param = 0 ; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp getfmt: %d\n", + ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETFMTS, &ioctl_param)); + + mp_msg(MSGT_TV, MSGL_V, "Supported formats: %x\n", ioctl_param); + if (!(ioctl_param & AFMT_S16_LE)) + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_UnsupportedFmt); + + ioctl_param = AFMT_S16_LE; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp setfmt: %d\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETFMT, &ioctl_param)); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetAudioFmt); + return -1; + } + + if (ai_oss_set_channels(ai) < 0) return -1; + + ioctl_param = ai->req_samplerate; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp speed: %d\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SPEED, &ioctl_param)); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetSamplerate, + ai->req_samplerate); + return -1; + } + ai->samplerate = ioctl_param; + + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp trigger: %d\n", + ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETTRIGGER, &ioctl_param)); + mp_msg(MSGT_TV, MSGL_V, "trigger: %x\n", ioctl_param); + ioctl_param = PCM_ENABLE_INPUT; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp trigger: %d\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_SETTRIGGER, &ioctl_param)); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2SetTrigger, + PCM_ENABLE_INPUT); + } + + ai->blocksize = 0; + mp_msg(MSGT_TV, MSGL_V, "ioctl dsp getblocksize: %d\n", + err = ioctl(ai->oss.audio_fd, SNDCTL_DSP_GETBLKSIZE, &ai->blocksize)); + if (err < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_Unable2GetBlockSize); + } + mp_msg(MSGT_TV, MSGL_V, "blocksize: %d\n", ai->blocksize); + + // correct the blocksize to a reasonable value + if (ai->blocksize <= 0) { + ai->blocksize = 4096*ai->channels*2; + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_AudioBlockSizeZero, ai->blocksize); + } else if (ai->blocksize < 4096*ai->channels*2) { + ai->blocksize *= 4096*ai->channels*2/ai->blocksize; + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIOSS_AudioBlockSize2Low, ai->blocksize); + } + + ai->samplesize = 16; + ai->bytes_per_sample = 2; + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/asf_mmst_streaming.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,665 @@ +// mmst implementation taken from the xine-mms plugin made by majormms (http://geocities.com/majormms/) +// +// ported to mplayer by Abhijeet Phatak <abhijeetphatak@yahoo.com> +// date : 16 April 2002 +// +// information about the mms protocol can be find at http://get.to/sdp +// + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <inttypes.h> + +#include "config.h" + +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include <winsock2.h> +#endif + +#ifndef USE_SETLOCALE +#undef USE_ICONV +#endif + +#ifdef USE_ICONV +#include <iconv.h> +#ifdef USE_LANGINFO +#include <langinfo.h> +#endif +#endif + +#include "url.h" +#include "asf.h" + +#include "stream.h" + +#include "network.h" + +#define BUF_SIZE 102400 +#define HDR_BUF_SIZE 8192 +#define MAX_STREAMS 20 + +typedef struct +{ + uint8_t buf[BUF_SIZE]; + int num_bytes; + +} command_t; + +static int seq_num; +static int num_stream_ids; +static int stream_ids[MAX_STREAMS]; + +static int get_data (int s, char *buf, size_t count); + +static void put_32 (command_t *cmd, uint32_t value) +{ + cmd->buf[cmd->num_bytes ] = value % 256; + value = value >> 8; + cmd->buf[cmd->num_bytes+1] = value % 256 ; + value = value >> 8; + cmd->buf[cmd->num_bytes+2] = value % 256 ; + value = value >> 8; + cmd->buf[cmd->num_bytes+3] = value % 256 ; + + cmd->num_bytes += 4; +} + +static uint32_t get_32 (unsigned char *cmd, int offset) +{ + uint32_t ret; + + ret = cmd[offset] ; + ret |= cmd[offset+1]<<8 ; + ret |= cmd[offset+2]<<16 ; + ret |= cmd[offset+3]<<24 ; + + return ret; +} + +static void send_command (int s, int command, uint32_t switches, + uint32_t extra, int length, + char *data) +{ + command_t cmd; + int len8; + + len8 = (length + 7) / 8; + + cmd.num_bytes = 0; + + put_32 (&cmd, 0x00000001); /* start sequence */ + put_32 (&cmd, 0xB00BFACE); /* #-)) */ + put_32 (&cmd, len8*8 + 32); + put_32 (&cmd, 0x20534d4d); /* protocol type "MMS " */ + put_32 (&cmd, len8 + 4); + put_32 (&cmd, seq_num); + seq_num++; + put_32 (&cmd, 0x0); /* unknown */ + put_32 (&cmd, 0x0); + put_32 (&cmd, len8+2); + put_32 (&cmd, 0x00030000 | command); /* dir | command */ + put_32 (&cmd, switches); + put_32 (&cmd, extra); + + memcpy (&cmd.buf[48], data, length); + if (length & 7) + memset(&cmd.buf[48 + length], 0, 8 - (length & 7)); + + if (send (s, cmd.buf, len8*8+48, 0) != (len8*8+48)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_WriteError); + } +} + +#ifdef USE_ICONV +static iconv_t url_conv; +#endif + +static void string_utf16(char *dest, char *src, int len) { + int i; +#ifdef USE_ICONV + size_t len1, len2; + char *ip, *op; + + if (url_conv != (iconv_t)(-1)) + { + memset(dest, 0, 1000); + len1 = len; len2 = 1000; + ip = src; op = dest; + + iconv(url_conv, &ip, &len1, &op, &len2); + } + else + { +#endif + if (len > 499) len = 499; + for (i=0; i<len; i++) { + dest[i*2] = src[i]; + dest[i*2+1] = 0; + } + /* trailing zeroes */ + dest[i*2] = 0; + dest[i*2+1] = 0; +#ifdef USE_ICONV + } +#endif +} + +static void get_answer (int s) +{ + char data[BUF_SIZE]; + int command = 0x1b; + + while (command == 0x1b) { + int len; + + len = recv (s, data, BUF_SIZE, 0) ; + if (!len) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_EOFAlert); + return; + } + + command = get_32 (data, 36) & 0xFFFF; + + if (command == 0x1b) + send_command (s, 0x1b, 0, 0, 0, data); + } +} + +static int get_data (int s, char *buf, size_t count) +{ + ssize_t len; + size_t total = 0; + + while (total < count) { + + len = recv (s, &buf[total], count-total, 0); + + if (len<=0) { + perror ("read error:"); + return 0; + } + + total += len; + + if (len != 0) { +// mp_msg(MSGT_NETWORK,MSGL_INFO,"[%d/%d]", total, count); + fflush (stdout); + } + + } + + return 1; + +} + +static int get_header (int s, uint8_t *header, streaming_ctrl_t *streaming_ctrl) +{ + unsigned char pre_header[8]; + int header_len; + + header_len = 0; + + while (1) { + if (!get_data (s, pre_header, 8)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed); + return 0; + } + if (pre_header[4] == 0x02) { + + int packet_len; + + packet_len = (pre_header[7] << 8 | pre_header[6]) - 8; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf header packet detected, len=%d\n", packet_len); + + if (packet_len < 0 || packet_len > HDR_BUF_SIZE - header_len) { + mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidHeaderSize); + return 0; + } + + if (!get_data (s, &header[header_len], packet_len)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_HeaderDataReadFailed); + return 0; + } + + header_len += packet_len; + + if ( (header[header_len-1] == 1) && (header[header_len-2]==1)) { + + + if( streaming_bufferize( streaming_ctrl, header, header_len )<0 ) { + return -1; + } + + // mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet finished\n"); + + return (header_len); + + } + + } else { + + int32_t packet_len; + int command; + char data[BUF_SIZE]; + + if (!get_data (s, (char*)&packet_len, 4)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed); + return 0; + } + + packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"command packet detected, len=%d\n", packet_len); + + if (packet_len < 0 || packet_len > BUF_SIZE) { + mp_msg(MSGT_NETWORK, MSGL_FATAL, + MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); + return 0; + } + + if (!get_data (s, data, packet_len)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed); + return 0; + } + + command = get_32 (data, 24) & 0xFFFF; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"command: %02x\n", command); + + if (command == 0x1b) + send_command (s, 0x1b, 0, 0, 0, data); + + } + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"get header packet succ\n"); + } +} + +static int interp_header (uint8_t *header, int header_len) +{ + int i; + int packet_length=-1; + + /* + * parse header + */ + + i = 30; + while (i<header_len) { + + uint64_t guid_1, guid_2, length; + + guid_2 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) + | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) + | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) + | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); + i += 8; + + guid_1 = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) + | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) + | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) + | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); + i += 8; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"guid found: %016llx%016llx\n", guid_1, guid_2); + + length = (uint64_t)header[i] | ((uint64_t)header[i+1]<<8) + | ((uint64_t)header[i+2]<<16) | ((uint64_t)header[i+3]<<24) + | ((uint64_t)header[i+4]<<32) | ((uint64_t)header[i+5]<<40) + | ((uint64_t)header[i+6]<<48) | ((uint64_t)header[i+7]<<56); + + i += 8; + + if ( (guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22630ULL) ) { + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_HeaderObject); + } else if ((guid_1 == 0x6cce6200aa00d9a6ULL) && (guid_2 == 0x11cf668e75b22636ULL)) { + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_DataObject); + } else if ((guid_1 == 0x6553200cc000e48eULL) && (guid_2 == 0x11cfa9478cabdca1ULL)) { + + packet_length = get_32(header, i+92-24); + + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_FileObjectPacketLen, + packet_length, get_32(header, i+96-24)); + + + } else if ((guid_1 == 0x6553200cc000e68eULL) && (guid_2 == 0x11cfa9b7b7dc0791ULL)) { + + int stream_id = header[i+48] | header[i+49] << 8; + + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_StreamObjectStreamID, stream_id); + + if (num_stream_ids < MAX_STREAMS) { + stream_ids[num_stream_ids] = stream_id; + num_stream_ids++; + } else { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_2ManyStreamID); + } + + } else { +#if 0 + int b = i; + printf ("unknown object (guid: %016llx, %016llx, len: %lld)\n", guid_1, guid_2, length); + for (; b < length; b++) + { + if (isascii(header[b]) || isalpha(header[b])) + printf("%c ", header[b]); + else + printf("%x ", header[b]); + } + printf("\n"); +#else + mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_MMST_UnknownObject); +#endif + } + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"length : %lld\n", length); + + i += length-24; + + } + + return packet_length; + +} + + +static int get_media_packet (int s, int padding, streaming_ctrl_t *stream_ctrl) { + unsigned char pre_header[8]; + char data[BUF_SIZE]; + + if (!get_data (s, pre_header, 8)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_PreHeaderReadFailed); + return 0; + } + +// for (i=0; i<8; i++) +// mp_msg(MSGT_NETWORK,MSGL_INFO,"pre_header[%d] = %02x (%d)\n", +// i, pre_header[i], pre_header[i]); + + if (pre_header[4] == 0x04) { + + int packet_len; + + packet_len = (pre_header[7] << 8 | pre_header[6]) - 8; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"asf media packet detected, len=%d\n", packet_len); + + if (packet_len < 0 || packet_len > BUF_SIZE) { + mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); + return 0; + } + + if (!get_data (s, data, packet_len)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MediaDataReadFailed); + return 0; + } + + streaming_bufferize(stream_ctrl, data, padding); + + } else { + + int32_t packet_len; + int command; + + if (!get_data (s, (char*)&packet_len, 4)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_packet_lenReadFailed); + return 0; + } + + packet_len = get_32 ((unsigned char*)&packet_len, 0) + 4; + + if (packet_len < 0 || packet_len > BUF_SIZE) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_MMST_InvalidRTSPPacketSize); + return 0; + } + + if (!get_data (s, data, packet_len)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_CmdDataReadFailed); + return 0; + } + + if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b) + || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) { + + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_MissingSignature); + return -1; + } + + command = get_32 (data, 24) & 0xFFFF; + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"\ncommand packet detected, len=%d cmd=0x%X\n", packet_len, command); + + if (command == 0x1b) + send_command (s, 0x1b, 0, 0, 0, data); + else if (command == 0x1e) { + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_PatentedTechnologyJoke); + return 0; + } + else if (command == 0x21 ) { + // Looks like it's new in WMS9 + // Unknown command, but ignoring it seems to work. + return 0; + } + else if (command != 0x05) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_UnknownCmd,command); + return -1; + } + } + +// mp_msg(MSGT_NETWORK,MSGL_INFO,"get media packet succ\n"); + + return 1; +} + + +static int packet_length1; + +static int asf_mmst_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) +{ + int len; + + while( stream_ctrl->buffer_size==0 ) { + // buffer is empty - fill it! + int ret = get_media_packet( fd, packet_length1, stream_ctrl); + if( ret<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_MMST_GetMediaPacketErr,strerror(errno)); + return -1; + } else if (ret==0) //EOF? + return ret; + } + + len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos; + if(len>size) len=size; + memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len ); + stream_ctrl->buffer_pos += len; + if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) { + free( stream_ctrl->buffer ); + stream_ctrl->buffer = NULL; + stream_ctrl->buffer_size = 0; + stream_ctrl->buffer_pos = 0; + } + return len; + +} + +static int asf_mmst_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl ) +{ + return -1; + // Shut up gcc warning + fd++; + pos++; + streaming_ctrl=NULL; +} + +int asf_mmst_streaming_start(stream_t *stream) +{ + char str[1024]; + char data[BUF_SIZE]; + uint8_t asf_header[HDR_BUF_SIZE]; + int asf_header_len; + int len, i, packet_length; + char *path, *unescpath; + URL_t *url1 = stream->streaming_ctrl->url; + int s = stream->fd; + + if( s>0 ) { + closesocket( stream->fd ); + stream->fd = -1; + } + + /* parse url */ + path = strchr(url1->file,'/') + 1; + + /* mmst filename are not url_escaped by MS MediaPlayer and are expected as + * "plain text" by the server, so need to decode it here + */ + unescpath=malloc(strlen(path)+1); + if (!unescpath) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return -1; + } + url_unescape_string(unescpath,path); + path=unescpath; + + + if( url1->port==0 ) { + url1->port=1755; + } + s = connect2Server( url1->hostname, url1->port, 1); + if( s<0 ) { + free(path); + return s; + } + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_MMST_Connected); + + seq_num=0; + + /* + * Send the initial connect info including player version no. Client GUID (random) and the host address being connected to. + * This command is sent at the very start of protocol initiation. It sends local information to the serve + * cmd 1 0x01 + * */ + + /* prepare for the url encoding conversion */ +#ifdef USE_ICONV +#ifdef USE_LANGINFO + url_conv = iconv_open("UTF-16LE",nl_langinfo(CODESET)); +#else + url_conv = iconv_open("UTF-16LE", NULL); +#endif +#endif + + snprintf (str, 1023, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", url1->hostname); + string_utf16 (data, str, strlen(str)); +// send_command(s, commandno ....) + send_command (s, 1, 0, 0x0004000b, strlen(str)*2+2, data); + + len = recv (s, data, BUF_SIZE, 0) ; + + /*This sends details of the local machine IP address to a Funnel system at the server. + * Also, the TCP or UDP transport selection is sent. + * + * here 192.168.0.1 is local ip address TCP/UDP states the tronsport we r using + * and 1037 is the local TCP or UDP socket number + * cmd 2 0x02 + * */ + + string_utf16 (&data[8], "\002\000\\\\192.168.0.1\\TCP\\1037", 24); + memset (data, 0, 8); + send_command (s, 2, 0, 0, 24*2+10, data); + + len = recv (s, data, BUF_SIZE, 0) ; + + /* This command sends file path (at server) and file name request to the server. + * 0x5 */ + + string_utf16 (&data[8], path, strlen(path)); + memset (data, 0, 8); + send_command (s, 5, 0, 0, strlen(path)*2+10, data); + free(path); + + get_answer (s); + + /* The ASF header chunk request. Includes ?session' variable for pre header value. + * After this command is sent, + * the server replies with 0x11 command and then the header chunk with header data follows. + * 0x15 */ + + memset (data, 0, 40); + data[32] = 2; + + send_command (s, 0x15, 1, 0, 40, data); + + num_stream_ids = 0; + /* get_headers(s, asf_header); */ + + asf_header_len = get_header (s, asf_header, stream->streaming_ctrl); +// mp_msg(MSGT_NETWORK,MSGL_INFO,"---------------------------------- asf_header %d\n",asf_header); + if (asf_header_len==0) return -1; //error reading header + packet_length = interp_header (asf_header, asf_header_len); + + + /* + * This command is the media stream MBR selector. Switches are always 6 bytes in length. + * After all switch elements, data ends with bytes [00 00] 00 20 ac 40 [02]. + * Where: + * [00 00] shows 0x61 0x00 (on the first 33 sent) or 0xff 0xff for ASF files, and with no ending data for WMV files. + * It is not yet understood what all this means. + * And the last [02] byte is probably the header ?session' value. + * + * 0x33 */ + + memset (data, 0, 40); + + for (i=1; i<num_stream_ids; i++) { + data [ (i-1) * 6 + 2 ] = 0xFF; + data [ (i-1) * 6 + 3 ] = 0xFF; + data [ (i-1) * 6 + 4 ] = stream_ids[i]; + data [ (i-1) * 6 + 5 ] = 0x00; + } + + send_command (s, 0x33, num_stream_ids, 0xFFFF | stream_ids[0] << 16, (num_stream_ids-1)*6+2 , data); + + get_answer (s); + + /* Start sending file from packet xx. + * This command is also used for resume downloads or requesting a lost packet. + * Also used for seeking by sending a play point value which seeks to the media time point. + * Includes ?session' value in pre header and the maximum media stream time. + * 0x07 */ + + memset (data, 0, 40); + + for (i=8; i<16; i++) + data[i] = 0xFF; + + data[20] = 0x04; + + send_command (s, 0x07, 1, 0xFFFF | stream_ids[0] << 16, 24, data); + + stream->fd = s; + stream->streaming_ctrl->streaming_read = asf_mmst_streaming_read; + stream->streaming_ctrl->streaming_seek = asf_mmst_streaming_seek; + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + + packet_length1 = packet_length; + mp_msg(MSGT_NETWORK,MSGL_INFO,"mmst packet_length = %d\n", packet_length); + +#ifdef USE_ICONV + if (url_conv != (iconv_t)(-1)) + iconv_close(url_conv); +#endif + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/asf_streaming.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,882 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <limits.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include <winsock2.h> +#endif + +#include "url.h" +#include "http.h" +#include "asf.h" + +#include "stream.h" +#include "demuxer.h" + +#include "network.h" + +#ifdef ARCH_X86 +#define ASF_LOAD_GUID_PREFIX(guid) (*(uint32_t *)(guid)) +#else +#define ASF_LOAD_GUID_PREFIX(guid) \ + ((guid)[3] << 24 | (guid)[2] << 16 | (guid)[1] << 8 | (guid)[0]) +#endif + +extern int network_bandwidth; + +int asf_mmst_streaming_start( stream_t *stream ); +static int asf_http_streaming_start(stream_t *stream, int *demuxer_type); + +// We can try several protocol for asf streaming +// * first the UDP protcol, if there is a firewall, UDP +// packets will not come back, so the mmsu will fail. +// * Then we can try TCP, but if there is a proxy for +// internet connection, the TCP connection will not get +// through +// * Then we can try HTTP. +// +// Note: Using WMP sequence MMSU then MMST and then HTTP. + +static int asf_streaming_start( stream_t *stream, int *demuxer_type) { + char *proto = stream->streaming_ctrl->url->protocol; + int fd = -1; + int port = stream->streaming_ctrl->url->port; + + // Is protocol mms or mmsu? + if (!strcasecmp(proto, "mmsu") || !strcasecmp(proto, "mms")) + { + mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/UDP...\n"); + //fd = asf_mmsu_streaming_start( stream ); + if( fd>-1 ) return fd; //mmsu support is not implemented yet - using this code + mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/UDP failed\n"); + if( fd==-2 ) return -1; + } + + //Is protocol mms or mmst? + if (!strcasecmp(proto, "mmst") || !strcasecmp(proto, "mms")) + { + mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/TCP...\n"); + fd = asf_mmst_streaming_start( stream ); + stream->streaming_ctrl->url->port = port; + if( fd>-1 ) return fd; + mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/TCP failed\n"); + if( fd==-2 ) return -1; + } + + //Is protocol http, http_proxy, or mms? + if (!strcasecmp(proto, "http_proxy") || !strcasecmp(proto, "http") || + !strcasecmp(proto, "mms") || !strcasecmp(proto, "mmshttp")) + { + mp_msg(MSGT_NETWORK,MSGL_V,"Trying ASF/HTTP...\n"); + fd = asf_http_streaming_start( stream, demuxer_type ); + stream->streaming_ctrl->url->port = port; + if( fd>-1 ) return fd; + mp_msg(MSGT_NETWORK,MSGL_V," ===> ASF/HTTP failed\n"); + if( fd==-2 ) return -1; + } + + //everything failed + return -1; +} + +static int asf_streaming(ASF_stream_chunck_t *stream_chunck, int *drop_packet ) { +/* +printf("ASF stream chunck size=%d\n", stream_chunck->size); +printf("length: %d\n", length ); +printf("0x%02X\n", stream_chunck->type ); +*/ + if( drop_packet!=NULL ) *drop_packet = 0; + + if( stream_chunck->size<8 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_StreamChunkSize2Small, stream_chunck->size); + return -1; + } + if( stream_chunck->size!=stream_chunck->size_confirm ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SizeConfirmMismatch, stream_chunck->size, stream_chunck->size_confirm); + return -1; + } +/* + printf(" type: 0x%02X\n", stream_chunck->type ); + printf(" size: %d (0x%02X)\n", stream_chunck->size, stream_chunck->size ); + printf(" sequence_number: 0x%04X\n", stream_chunck->sequence_number ); + printf(" unknown: 0x%02X\n", stream_chunck->unknown ); + printf(" size_confirm: 0x%02X\n", stream_chunck->size_confirm ); +*/ + switch(stream_chunck->type) { + case ASF_STREAMING_CLEAR: // $C Clear ASF configuration + mp_msg(MSGT_NETWORK,MSGL_V,"=====> Clearing ASF stream configuration!\n"); + if( drop_packet!=NULL ) *drop_packet = 1; + return stream_chunck->size; + break; + case ASF_STREAMING_DATA: // $D Data follows +// printf("=====> Data follows\n"); + break; + case ASF_STREAMING_END_TRANS: // $E Transfer complete + mp_msg(MSGT_NETWORK,MSGL_V,"=====> Transfer complete\n"); + if( drop_packet!=NULL ) *drop_packet = 1; + return stream_chunck->size; + break; + case ASF_STREAMING_HEADER: // $H ASF header chunk follows + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF header chunk follows\n"); + break; + default: + mp_msg(MSGT_NETWORK,MSGL_V,"=====> Unknown stream type 0x%x\n", stream_chunck->type ); + } + return stream_chunck->size+4; +} + +extern int find_asf_guid(char *buf, const char *guid, int cur_pos, int buf_len); +extern const char asf_file_header_guid[]; +extern const char asf_stream_header_guid[]; +extern const char asf_stream_group_guid[]; +extern int audio_id; +extern int video_id; + +static void close_s(stream_t *stream) { + close(stream->fd); + stream->fd=-1; +} + +static int max_idx(int s_count, int *s_rates, int bound) { + int i, best = -1, rate = -1; + for (i = 0; i < s_count; i++) { + if (s_rates[i] > rate && s_rates[i] <= bound) { + rate = s_rates[i]; + best = i; + } + } + return best; +} + +static int asf_streaming_parse_header(int fd, streaming_ctrl_t* streaming_ctrl) { + ASF_header_t asfh; + ASF_stream_chunck_t chunk; + asf_http_streaming_ctrl_t* asf_ctrl = (asf_http_streaming_ctrl_t*) streaming_ctrl->data; + char* buffer=NULL, *chunk_buffer=NULL; + int i,r,size,pos = 0; + int start; + int buffer_size = 0; + int chunk_size2read = 0; + int bw = streaming_ctrl->bandwidth; + int *v_rates = NULL, *a_rates = NULL; + int v_rate = 0, a_rate = 0, a_idx = -1, v_idx = -1; + + if(asf_ctrl == NULL) return -1; + + // The ASF header can be in several network chunks. For example if the content description + // is big, the ASF header will be split in 2 network chunk. + // So we need to retrieve all the chunk before starting to parse the header. + do { + for( r=0; r < (int)sizeof(ASF_stream_chunck_t) ; ) { + i = nop_streaming_read(fd,((char*)&chunk)+r,sizeof(ASF_stream_chunck_t) - r,streaming_ctrl); + if(i <= 0) return -1; + r += i; + } + // Endian handling of the stream chunk + le2me_ASF_stream_chunck_t(&chunk); + size = asf_streaming( &chunk, &r) - sizeof(ASF_stream_chunck_t); + if(r) mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_WarnDropHeader); + if(size < 0){ + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); + return -1; + } + if (chunk.type != ASF_STREAMING_HEADER) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoHeaderAtFirstChunk); + return -1; + } + + // audit: do not overflow buffer_size + if (size > SIZE_MAX - buffer_size) return -1; + buffer = (char*) malloc(size+buffer_size); + if(buffer == NULL) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MPDEMUX_ASF_BufferMallocFailed,size+buffer_size); + return -1; + } + if( chunk_buffer!=NULL ) { + memcpy( buffer, chunk_buffer, buffer_size ); + free( chunk_buffer ); + } + chunk_buffer = buffer; + buffer += buffer_size; + buffer_size += size; + + for(r = 0; r < size;) { + i = nop_streaming_read(fd,buffer+r,size-r,streaming_ctrl); + if(i < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingNetworkStream); + return -1; + } + r += i; + } + + if( chunk_size2read==0 ) { + if(size < (int)sizeof(asfh)) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunk2Small); + return -1; + } else mp_msg(MSGT_NETWORK,MSGL_DBG2,"Got chunk\n"); + memcpy(&asfh,buffer,sizeof(asfh)); + le2me_ASF_header_t(&asfh); + chunk_size2read = asfh.objh.size; + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Size 2 read=%d\n", chunk_size2read); + } + } while( buffer_size<chunk_size2read); + buffer = chunk_buffer; + size = buffer_size; + + if(asfh.cno > 256) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrSubChunkNumberInvalid); + return -1; + } + + start = sizeof(asfh); + + pos = find_asf_guid(buffer, asf_file_header_guid, start, size); + if (pos >= 0) { + ASF_file_header_t *fileh = (ASF_file_header_t *) &buffer[pos]; + pos += sizeof(ASF_file_header_t); + if (pos > size) goto len_err_out; + le2me_ASF_file_header_t(fileh); +/* + if(fileh.packetsize != fileh.packetsize2) { + printf("Error packetsize check don't match\n"); + return -1; + } +*/ + asf_ctrl->packet_size = fileh->max_packet_size; + // before playing. + // preroll: time in ms to bufferize before playing + streaming_ctrl->prebuffer_size = (unsigned int)(((double)fileh->preroll/1000.0)*((double)fileh->max_bitrate/8.0)); + } + + pos = start; + while ((pos = find_asf_guid(buffer, asf_stream_header_guid, pos, size)) >= 0) + { + ASF_stream_header_t *streamh = (ASF_stream_header_t *)&buffer[pos]; + pos += sizeof(ASF_stream_header_t); + if (pos > size) goto len_err_out; + le2me_ASF_stream_header_t(streamh); + switch(ASF_LOAD_GUID_PREFIX(streamh->type)) { + case 0xF8699E40 : // audio stream + if(asf_ctrl->audio_streams == NULL){ + asf_ctrl->audio_streams = malloc(sizeof(int)); + asf_ctrl->n_audio = 1; + } else { + asf_ctrl->n_audio++; + asf_ctrl->audio_streams = (int*)realloc(asf_ctrl->audio_streams, + asf_ctrl->n_audio*sizeof(int)); + } + asf_ctrl->audio_streams[asf_ctrl->n_audio-1] = streamh->stream_no; + break; + case 0xBC19EFC0 : // video stream + if(asf_ctrl->video_streams == NULL){ + asf_ctrl->video_streams = malloc(sizeof(int)); + asf_ctrl->n_video = 1; + } else { + asf_ctrl->n_video++; + asf_ctrl->video_streams = (int*)realloc(asf_ctrl->video_streams, + asf_ctrl->n_video*sizeof(int)); + } + asf_ctrl->video_streams[asf_ctrl->n_video-1] = streamh->stream_no; + break; + } + } + + // always allocate to avoid lots of ifs later + v_rates = calloc(asf_ctrl->n_video, sizeof(int)); + a_rates = calloc(asf_ctrl->n_audio, sizeof(int)); + + pos = find_asf_guid(buffer, asf_stream_group_guid, start, size); + if (pos >= 0) { + // stream bitrate properties object + int stream_count; + char *ptr = &buffer[pos]; + + mp_msg(MSGT_NETWORK, MSGL_V, "Stream bitrate properties object\n"); + stream_count = le2me_16(*(uint16_t*)ptr); + ptr += sizeof(uint16_t); + if (ptr > &buffer[size]) goto len_err_out; + mp_msg(MSGT_NETWORK, MSGL_V, " stream count=[0x%x][%u]\n", + stream_count, stream_count ); + for( i=0 ; i<stream_count ; i++ ) { + uint32_t rate; + int id; + int j; + id = le2me_16(*(uint16_t*)ptr); + ptr += sizeof(uint16_t); + if (ptr > &buffer[size]) goto len_err_out; + memcpy(&rate, ptr, sizeof(uint32_t));// workaround unaligment bug on sparc + ptr += sizeof(uint32_t); + if (ptr > &buffer[size]) goto len_err_out; + rate = le2me_32(rate); + mp_msg(MSGT_NETWORK, MSGL_V, + " stream id=[0x%x][%u]\n", id, id); + mp_msg(MSGT_NETWORK, MSGL_V, + " max bitrate=[0x%x][%u]\n", rate, rate); + for (j = 0; j < asf_ctrl->n_video; j++) { + if (id == asf_ctrl->video_streams[j]) { + mp_msg(MSGT_NETWORK, MSGL_V, " is video stream\n"); + v_rates[j] = rate; + break; + } + } + for (j = 0; j < asf_ctrl->n_audio; j++) { + if (id == asf_ctrl->audio_streams[j]) { + mp_msg(MSGT_NETWORK, MSGL_V, " is audio stream\n"); + a_rates[j] = rate; + break; + } + } + } + } + free(buffer); + + // automatic stream selection based on bandwidth + if (bw == 0) bw = INT_MAX; + mp_msg(MSGT_NETWORK, MSGL_V, "Max bandwidth set to %d\n", bw); + + if (asf_ctrl->n_audio) { + // find lowest-bitrate audio stream + a_rate = a_rates[0]; + a_idx = 0; + for (i = 0; i < asf_ctrl->n_audio; i++) { + if (a_rates[i] < a_rate) { + a_rate = a_rates[i]; + a_idx = i; + } + } + if (max_idx(asf_ctrl->n_video, v_rates, bw - a_rate) < 0) { + // both audio and video are not possible, try video only next + a_idx = -1; + a_rate = 0; + } + } + // find best video stream + v_idx = max_idx(asf_ctrl->n_video, v_rates, bw - a_rate); + if (v_idx >= 0) + v_rate = v_rates[v_idx]; + + // find best audio stream + a_idx = max_idx(asf_ctrl->n_audio, a_rates, bw - v_rate); + + free(v_rates); + free(a_rates); + + if (a_idx < 0 && v_idx < 0) { + mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_Bandwidth2SmallCannotPlay); + return -1; + } + + if (audio_id > 0) + // a audio stream was forced + asf_ctrl->audio_id = audio_id; + else if (a_idx >= 0) + asf_ctrl->audio_id = asf_ctrl->audio_streams[a_idx]; + else if (asf_ctrl->n_audio) { + mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedAudio); + audio_id = -2; + } + + if (video_id > 0) + // a video stream was forced + asf_ctrl->video_id = video_id; + else if (v_idx >= 0) + asf_ctrl->video_id = asf_ctrl->video_streams[v_idx]; + else if (asf_ctrl->n_video) { + mp_msg(MSGT_NETWORK, MSGL_WARN, MSGTR_MPDEMUX_ASF_Bandwidth2SmallDeselectedVideo); + video_id = -2; + } + + return 1; + +len_err_out: + mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MPDEMUX_ASF_InvalidLenInHeader); + if (buffer) free(buffer); + if (v_rates) free(v_rates); + if (a_rates) free(a_rates); + return -1; +} + +static int asf_http_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { + static ASF_stream_chunck_t chunk; + int read,chunk_size = 0; + static int rest = 0, drop_chunk = 0, waiting = 0; + asf_http_streaming_ctrl_t *asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data; + + while(1) { + if (rest == 0 && waiting == 0) { + read = 0; + while(read < (int)sizeof(ASF_stream_chunck_t)){ + int r = nop_streaming_read( fd, ((char*)&chunk) + read, + sizeof(ASF_stream_chunck_t)-read, + streaming_ctrl ); + if(r <= 0){ + if( r < 0) + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingChunkHeader); + return -1; + } + read += r; + } + + // Endian handling of the stream chunk + le2me_ASF_stream_chunck_t(&chunk); + chunk_size = asf_streaming( &chunk, &drop_chunk ); + if(chunk_size < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrorParsingChunkHeader); + return -1; + } + chunk_size -= sizeof(ASF_stream_chunck_t); + + if(chunk.type != ASF_STREAMING_HEADER && (!drop_chunk)) { + if (asf_http_ctrl->packet_size < chunk_size) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrChunkBiggerThanPacket); + return -1; + } + waiting = asf_http_ctrl->packet_size; + } else { + waiting = chunk_size; + } + + } else if (rest){ + chunk_size = rest; + rest = 0; + } + + read = 0; + if ( waiting >= chunk_size) { + if (chunk_size > size){ + rest = chunk_size - size; + chunk_size = size; + } + while(read < chunk_size) { + int got = nop_streaming_read( fd,buffer+read,chunk_size-read,streaming_ctrl ); + if(got <= 0) { + if(got < 0) + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ErrReadingChunk); + return -1; + } + read += got; + } + waiting -= read; + if (drop_chunk) continue; + } + if (rest == 0 && waiting > 0 && size-read > 0) { + int s = MIN(waiting,size-read); + memset(buffer+read,0,s); + waiting -= s; + read += s; + } + break; + } + + return read; +} + +static int asf_http_streaming_seek( int fd, off_t pos, streaming_ctrl_t *streaming_ctrl ) { + return -1; + // to shut up gcc warning + fd++; + pos++; + streaming_ctrl=NULL; +} + +static int asf_header_check( HTTP_header_t *http_hdr ) { + ASF_obj_header_t *objh; + if( http_hdr==NULL ) return -1; + if( http_hdr->body==NULL || http_hdr->body_size<sizeof(ASF_obj_header_t) ) return -1; + + objh = (ASF_obj_header_t*)http_hdr->body; + if( ASF_LOAD_GUID_PREFIX(objh->guid)==0x75B22630 ) return 0; + return -1; +} + +static int asf_http_streaming_type(char *content_type, char *features, HTTP_header_t *http_hdr ) { + if( content_type==NULL ) return ASF_Unknown_e; + if( !strcasecmp(content_type, "application/octet-stream") || + !strcasecmp(content_type, "application/vnd.ms.wms-hdr.asfv1") || // New in Corona, first request + !strcasecmp(content_type, "application/x-mms-framed") || // New in Corana, second request + !strcasecmp(content_type, "video/x-ms-asf")) { + + if( strstr(features, "broadcast") ) { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Live stream\n"); + return ASF_Live_e; + } else { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Prerecorded\n"); + return ASF_Prerecorded_e; + } + } else { + // Ok in a perfect world, web servers should be well configured + // so we could used mime type to know the stream type, + // but guess what? All of them are not well configured. + // So we have to check for an asf header :(, but it works :p + if( http_hdr->body_size>sizeof(ASF_obj_header_t) ) { + if( asf_header_check( http_hdr )==0 ) { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n"); + return ASF_PlainText_e; + } else if( (!strcasecmp(content_type, "text/html")) ) { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> HTML, MPlayer is not a browser...yet!\n"); + return ASF_Unknown_e; + } else { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Redirector\n"); + return ASF_Redirector_e; + } + } else { + if( (!strcasecmp(content_type, "audio/x-ms-wax")) || + (!strcasecmp(content_type, "audio/x-ms-wma")) || + (!strcasecmp(content_type, "video/x-ms-asf")) || + (!strcasecmp(content_type, "video/x-ms-afs")) || + (!strcasecmp(content_type, "video/x-ms-wvx")) || + (!strcasecmp(content_type, "video/x-ms-wmv")) || + (!strcasecmp(content_type, "video/x-ms-wma")) ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ASFRedirector); + return ASF_Redirector_e; + } else if( !strcasecmp(content_type, "text/plain") ) { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF Plain text\n"); + return ASF_PlainText_e; + } else { + mp_msg(MSGT_NETWORK,MSGL_V,"=====> ASF unknown content-type: %s\n", content_type ); + return ASF_Unknown_e; + } + } + } + return ASF_Unknown_e; +} + +static HTTP_header_t *asf_http_request(streaming_ctrl_t *streaming_ctrl) { + HTTP_header_t *http_hdr; + URL_t *url = NULL; + URL_t *server_url = NULL; + asf_http_streaming_ctrl_t *asf_http_ctrl; + char str[250]; + char *ptr; + int i, enable; + + int offset_hi=0, offset_lo=0, length=0; + int asf_nb_stream=0, stream_id; + + // Sanity check + if( streaming_ctrl==NULL ) return NULL; + url = streaming_ctrl->url; + asf_http_ctrl = (asf_http_streaming_ctrl_t*)streaming_ctrl->data; + if( url==NULL || asf_http_ctrl==NULL ) return NULL; + + // Common header for all requests. + http_hdr = http_new_header(); + http_set_field( http_hdr, "Accept: */*" ); + http_set_field( http_hdr, "User-Agent: NSPlayer/4.1.0.3856" ); + http_add_basic_authentication( http_hdr, url->username, url->password ); + + // Check if we are using a proxy + if( !strcasecmp( url->protocol, "http_proxy" ) ) { + server_url = url_new( (url->file)+1 ); + if( server_url==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_InvalidProxyURL); + http_free( http_hdr ); + return NULL; + } + http_set_uri( http_hdr, server_url->url ); + sprintf( str, "Host: %.220s:%d", server_url->hostname, server_url->port ); + url_free( server_url ); + } else { + http_set_uri( http_hdr, url->file ); + sprintf( str, "Host: %.220s:%d", url->hostname, url->port ); + } + + http_set_field( http_hdr, str ); + http_set_field( http_hdr, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}" ); + sprintf(str, + "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=%u", + offset_hi, offset_lo, asf_http_ctrl->request, length ); + http_set_field( http_hdr, str ); + + switch( asf_http_ctrl->streaming_type ) { + case ASF_Live_e: + case ASF_Prerecorded_e: + http_set_field( http_hdr, "Pragma: xPlayStrm=1" ); + ptr = str; + ptr += sprintf( ptr, "Pragma: stream-switch-entry="); + if(asf_http_ctrl->n_audio > 0) { + for( i=0; i<asf_http_ctrl->n_audio ; i++ ) { + stream_id = asf_http_ctrl->audio_streams[i]; + if(stream_id == asf_http_ctrl->audio_id) { + enable = 0; + } else { + enable = 2; + continue; + } + asf_nb_stream++; + ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable); + } + } + if(asf_http_ctrl->n_video > 0) { + for( i=0; i<asf_http_ctrl->n_video ; i++ ) { + stream_id = asf_http_ctrl->video_streams[i]; + if(stream_id == asf_http_ctrl->video_id) { + enable = 0; + } else { + enable = 2; + continue; + } + asf_nb_stream++; + ptr += sprintf(ptr, "ffff:%d:%d ", stream_id, enable); + } + } + http_set_field( http_hdr, str ); + sprintf( str, "Pragma: stream-switch-count=%d", asf_nb_stream ); + http_set_field( http_hdr, str ); + break; + case ASF_Redirector_e: + break; + case ASF_Unknown_e: + // First request goes here. + break; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_UnknownASFStreamType); + } + + http_set_field( http_hdr, "Connection: Close" ); + http_build_request( http_hdr ); + + return http_hdr; +} + +static int asf_http_parse_response(asf_http_streaming_ctrl_t *asf_http_ctrl, HTTP_header_t *http_hdr ) { + char *content_type, *pragma; + char features[64] = "\0"; + size_t len; + if( http_response_parse(http_hdr)<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_Failed2ParseHTTPResponse); + return -1; + } + switch( http_hdr->status_code ) { + case 200: + break; + case 401: // Authentication required + return ASF_Authenticate_e; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_ServerReturn, http_hdr->status_code, http_hdr->reason_phrase); + return -1; + } + + content_type = http_get_field( http_hdr, "Content-Type"); +//printf("Content-Type: [%s]\n", content_type); + + pragma = http_get_field( http_hdr, "Pragma"); + while( pragma!=NULL ) { + char *comma_ptr=NULL; + char *end; +//printf("Pragma: [%s]\n", pragma ); + // The pragma line can get severals attributes + // separeted with a comma ','. + do { + if( !strncasecmp( pragma, "features=", 9) ) { + pragma += 9; + end = strstr( pragma, "," ); + if( end==NULL ) { + len = strlen(pragma); + } else { + len = (unsigned int)(end-pragma); + } + if(len > sizeof(features) - 1) { + mp_msg(MSGT_NETWORK,MSGL_WARN,MSGTR_MPDEMUX_ASF_ASFHTTPParseWarnCuttedPragma,pragma,len,sizeof(features) - 1); + len = sizeof(features) - 1; + } + strncpy( features, pragma, len ); + features[len]='\0'; + break; + } + comma_ptr = strstr( pragma, "," ); + if( comma_ptr!=NULL ) { + pragma = comma_ptr+1; + if( pragma[0]==' ' ) pragma++; + } + } while( comma_ptr!=NULL ); + pragma = http_get_next_field( http_hdr ); + } + asf_http_ctrl->streaming_type = asf_http_streaming_type( content_type, features, http_hdr ); + return 0; +} + +static int asf_http_streaming_start( stream_t *stream, int *demuxer_type ) { + HTTP_header_t *http_hdr=NULL; + URL_t *url = stream->streaming_ctrl->url; + asf_http_streaming_ctrl_t *asf_http_ctrl; + char buffer[BUFFER_SIZE]; + int i, ret; + int fd = stream->fd; + int done; + int auth_retry = 0; + + asf_http_ctrl = malloc(sizeof(asf_http_streaming_ctrl_t)); + if( asf_http_ctrl==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return -1; + } + asf_http_ctrl->streaming_type = ASF_Unknown_e; + asf_http_ctrl->request = 1; + asf_http_ctrl->audio_streams = asf_http_ctrl->video_streams = NULL; + asf_http_ctrl->n_audio = asf_http_ctrl->n_video = 0; + stream->streaming_ctrl->data = (void*)asf_http_ctrl; + + do { + done = 1; + if( fd>0 ) closesocket( fd ); + + if( !strcasecmp( url->protocol, "http_proxy" ) ) { + if( url->port==0 ) url->port = 8080; + } else { + if( url->port==0 ) url->port = 80; + } + fd = connect2Server( url->hostname, url->port, 1); + if( fd<0 ) return fd; + + http_hdr = asf_http_request( stream->streaming_ctrl ); + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request [%s]\n", http_hdr->buffer ); + for(i=0; i < (int)http_hdr->buffer_size ; ) { + int r = send( fd, http_hdr->buffer+i, http_hdr->buffer_size-i, 0 ); + if(r <0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_SocketWriteError,strerror(errno)); + return -1; + } + i += r; + } + http_free( http_hdr ); + http_hdr = http_new_header(); + do { + i = recv( fd, buffer, BUFFER_SIZE, 0 ); +//printf("read: %d\n", i ); + if( i<=0 ) { + perror("read"); + http_free( http_hdr ); + return -1; + } + http_response_append( http_hdr, buffer, i ); + } while( !http_is_header_entire( http_hdr ) ); + if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { + http_hdr->buffer[http_hdr->buffer_size]='\0'; + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Response [%s]\n", http_hdr->buffer ); + } + ret = asf_http_parse_response(asf_http_ctrl, http_hdr); + if( ret<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_HeaderParseFailed); + http_free( http_hdr ); + return -1; + } + switch( asf_http_ctrl->streaming_type ) { + case ASF_Live_e: + case ASF_Prerecorded_e: + case ASF_PlainText_e: + if( http_hdr->body_size>0 ) { + if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { + http_free( http_hdr ); + return -1; + } + } + if( asf_http_ctrl->request==1 ) { + if( asf_http_ctrl->streaming_type!=ASF_PlainText_e ) { + // First request, we only got the ASF header. + ret = asf_streaming_parse_header(fd,stream->streaming_ctrl); + if(ret < 0) return -1; + if(asf_http_ctrl->n_audio == 0 && asf_http_ctrl->n_video == 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_NoStreamFound); + return -1; + } + asf_http_ctrl->request++; + done = 0; + } else { + done = 1; + } + } + break; + case ASF_Redirector_e: + if( http_hdr->body_size>0 ) { + if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { + http_free( http_hdr ); + return -1; + } + } + *demuxer_type = DEMUXER_TYPE_PLAYLIST; + done = 1; + break; + case ASF_Authenticate_e: + if( http_authenticate( http_hdr, url, &auth_retry)<0 ) return -1; + asf_http_ctrl->streaming_type = ASF_Unknown_e; + done = 0; + break; + case ASF_Unknown_e: + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_ASF_UnknownASFStreamingType); + closesocket(fd); + http_free( http_hdr ); + return -1; + } + // Check if we got a redirect. + } while(!done); + + stream->fd = fd; + if( asf_http_ctrl->streaming_type==ASF_PlainText_e || asf_http_ctrl->streaming_type==ASF_Redirector_e ) { + stream->streaming_ctrl->streaming_read = nop_streaming_read; + stream->streaming_ctrl->streaming_seek = nop_streaming_seek; + } else { + stream->streaming_ctrl->streaming_read = asf_http_streaming_read; + stream->streaming_ctrl->streaming_seek = asf_http_streaming_seek; + stream->streaming_ctrl->buffering = 1; + } + stream->streaming_ctrl->status = streaming_playing_e; + stream->close = close_s; + + http_free( http_hdr ); + return 0; +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + URL_t *url; + + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + url_free(url); + + mp_msg(MSGT_OPEN, MSGL_INFO, MSGTR_MPDEMUX_ASF_InfoStreamASFURL, stream->url); + if((!strncmp(stream->url, "http", 4)) && (*file_format!=DEMUXER_TYPE_ASF && *file_format!=DEMUXER_TYPE_UNKNOWN)) { + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + if(asf_streaming_start(stream, file_format) < 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_ASF_StreamingFailed); + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + *file_format = DEMUXER_TYPE_ASF; + stream->type = STREAMTYPE_STREAM; + fixup_network_stream_cache(stream); + return STREAM_OK; +} + +stream_info_t stream_info_asf = { + "mms and mms over http streaming", + "null", + "Bertrand, Reimar Doeffinger, Albeu", + "originally based on work by Majormms (is that code still there?)", + open_s, + {"mms", "mmsu", "mmst", "http", "http_proxy", "mmshttp", NULL}, + NULL, + 0 // Urls are an option string +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/audio_in.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,219 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" + +#include "audio_in.h" +#include "mp_msg.h" +#include "help_mp.h" +#include <string.h> +#include <errno.h> + +// sanitizes ai structure before calling other functions +int audio_in_init(audio_in_t *ai, int type) +{ + ai->type = type; + ai->setup = 0; + + ai->channels = -1; + ai->samplerate = -1; + ai->blocksize = -1; + ai->bytes_per_sample = -1; + ai->samplesize = -1; + + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + ai->alsa.handle = NULL; + ai->alsa.log = NULL; + ai->alsa.device = strdup("default"); + return 0; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + ai->oss.audio_fd = -1; + ai->oss.device = strdup("/dev/dsp"); + return 0; +#endif + default: + return -1; + } +} + +int audio_in_setup(audio_in_t *ai) +{ + + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + if (ai_alsa_init(ai) < 0) return -1; + ai->setup = 1; + return 0; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + if (ai_oss_init(ai) < 0) return -1; + ai->setup = 1; + return 0; +#endif + default: + return -1; + } +} + +int audio_in_set_samplerate(audio_in_t *ai, int rate) +{ + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + ai->req_samplerate = rate; + if (!ai->setup) return 0; + if (ai_alsa_setup(ai) < 0) return -1; + return ai->samplerate; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + ai->req_samplerate = rate; + if (!ai->setup) return 0; + if (ai_oss_set_samplerate(ai) < 0) return -1; + return ai->samplerate; +#endif + default: + return -1; + } +} + +int audio_in_set_channels(audio_in_t *ai, int channels) +{ + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + ai->req_channels = channels; + if (!ai->setup) return 0; + if (ai_alsa_setup(ai) < 0) return -1; + return ai->channels; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + ai->req_channels = channels; + if (!ai->setup) return 0; + if (ai_oss_set_channels(ai) < 0) return -1; + return ai->channels; +#endif + default: + return -1; + } +} + +int audio_in_set_device(audio_in_t *ai, char *device) +{ +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + int i; +#endif + if (ai->setup) return -1; + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + if (ai->alsa.device) free(ai->alsa.device); + ai->alsa.device = strdup(device); + /* mplayer cannot handle colons in arguments */ + for (i = 0; i < (int)strlen(ai->alsa.device); i++) { + if (ai->alsa.device[i] == '.') ai->alsa.device[i] = ':'; + } + return 0; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + if (ai->oss.device) free(ai->oss.device); + ai->oss.device = strdup(device); + return 0; +#endif + default: + return -1; + } +} + +int audio_in_uninit(audio_in_t *ai) +{ + if (ai->setup) { + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + if (ai->alsa.log) + snd_output_close(ai->alsa.log); + if (ai->alsa.handle) { + snd_pcm_close(ai->alsa.handle); + } + ai->setup = 0; + return 0; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + close(ai->oss.audio_fd); + ai->setup = 0; + return 0; +#endif + } + } + return -1; +} + +int audio_in_start_capture(audio_in_t *ai) +{ + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + return snd_pcm_start(ai->alsa.handle); +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + return 0; +#endif + default: + return -1; + } +} + +int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer) +{ + int ret; + + switch (ai->type) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + case AUDIO_IN_ALSA: + ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size); + if (ret != ai->alsa.chunk_size) { + if (ret < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, snd_strerror(ret)); + if (ret == -EPIPE) { + if (ai_alsa_xrun(ai) == 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut); + } else { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover); + } + } + } else { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples); + } + return -1; + } + return ret; +#endif +#ifdef USE_OSS_AUDIO + case AUDIO_IN_OSS: + ret = read(ai->oss.audio_fd, buffer, ai->blocksize); + if (ret != ai->blocksize) { + if (ret < 0) { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, strerror(errno)); + } else { + mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples); + } + return -1; + } + return ret; +#endif + default: + return -1; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/audio_in.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,75 @@ +#ifndef _audio_in_h +#define _audio_in_h + +#define AUDIO_IN_ALSA 1 +#define AUDIO_IN_OSS 2 + +#include "config.h" + +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) +#include <alsa/asoundlib.h> + +typedef struct { + char *device; + + snd_pcm_t *handle; + snd_output_t *log; + int buffer_time, period_time, chunk_size; + size_t bits_per_sample, bits_per_frame; +} ai_alsa_t; +#endif + +#ifdef USE_OSS_AUDIO +typedef struct { + char *device; + + int audio_fd; +} ai_oss_t; +#endif + +typedef struct +{ + int type; + int setup; + + /* requested values */ + int req_channels; + int req_samplerate; + + /* real values read-only */ + int channels; + int samplerate; + int blocksize; + int bytes_per_sample; + int samplesize; + +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + ai_alsa_t alsa; +#endif +#ifdef USE_OSS_AUDIO + ai_oss_t oss; +#endif +} audio_in_t; + +int audio_in_init(audio_in_t *ai, int type); +int audio_in_setup(audio_in_t *ai); +int audio_in_set_device(audio_in_t *ai, char *device); +int audio_in_set_samplerate(audio_in_t *ai, int rate); +int audio_in_set_channels(audio_in_t *ai, int channels); +int audio_in_uninit(audio_in_t *ai); +int audio_in_start_capture(audio_in_t *ai); +int audio_in_read_chunk(audio_in_t *ai, unsigned char *buffer); + +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) +int ai_alsa_setup(audio_in_t *ai); +int ai_alsa_init(audio_in_t *ai); +int ai_alsa_xrun(audio_in_t *ai); +#endif + +#ifdef USE_OSS_AUDIO +int ai_oss_set_samplerate(audio_in_t *ai); +int ai_oss_set_channels(audio_in_t *ai); +int ai_oss_init(audio_in_t *ai); +#endif + +#endif /* _audio_in_h */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cache2.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,367 @@ +#include "config.h" + +// Initial draft of my new cache system... +// Note it runs in 2 processes (using fork()), but doesn't requires locking!! +// TODO: seeking, data consistency checking + +#define READ_USLEEP_TIME 10000 +#define FILL_USLEEP_TIME 50000 +#define PREFILL_SLEEP_TIME 200 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include "osdep/timer.h" +#ifndef WIN32 +#include <sys/wait.h> +#include "osdep/shmem.h" +#else +#include <windows.h> +static DWORD WINAPI ThreadProc(void* s); +#endif + +#include "mp_msg.h" +#include "help_mp.h" + +#include "stream.h" + +int stream_fill_buffer(stream_t *s); +int stream_seek_long(stream_t *s,off_t pos); + +extern int mp_input_check_interrupt(int time); + +typedef struct { + // constats: + unsigned char *buffer; // base pointer of the alllocated buffer memory + int buffer_size; // size of the alllocated buffer memory + int sector_size; // size of a single sector (2048/2324) + int back_size; // we should keep back_size amount of old bytes for backward seek + int fill_limit; // we should fill buffer only if space>=fill_limit + int seek_limit; // keep filling cache if distanse is less that seek limit + // filler's pointers: + int eof; + off_t min_filepos; // buffer contain only a part of the file, from min-max pos + off_t max_filepos; + off_t offset; // filepos <-> bufferpos offset value (filepos of the buffer's first byte) + // reader's pointers: + off_t read_filepos; + // commands/locking: +// int seek_lock; // 1 if we will seek/reset buffer, 2 if we are ready for cmd +// int fifo_flag; // 1 if we should use FIFO to notice cache about buffer reads. + // callback + stream_t* stream; +} cache_vars_t; + +static int min_fill=0; + +int cache_fill_status=0; + +void cache_stats(cache_vars_t* s){ + int newb=s->max_filepos-s->read_filepos; // new bytes in the buffer + mp_msg(MSGT_CACHE,MSGL_INFO,"0x%06X [0x%06X] 0x%06X ",(int)s->min_filepos,(int)s->read_filepos,(int)s->max_filepos); + mp_msg(MSGT_CACHE,MSGL_INFO,"%3d %% (%3d%%)\n",100*newb/s->buffer_size,100*min_fill/s->buffer_size); +} + +int cache_read(cache_vars_t* s,unsigned char* buf,int size){ + int total=0; + while(size>0){ + int pos,newb,len; + + //printf("CACHE2_READ: 0x%X <= 0x%X <= 0x%X \n",s->min_filepos,s->read_filepos,s->max_filepos); + + if(s->read_filepos>=s->max_filepos || s->read_filepos<s->min_filepos){ + // eof? + if(s->eof) break; + // waiting for buffer fill... + usec_sleep(READ_USLEEP_TIME); // 10ms + continue; // try again... + } + + newb=s->max_filepos-s->read_filepos; // new bytes in the buffer + if(newb<min_fill) min_fill=newb; // statistics... + +// printf("*** newb: %d bytes ***\n",newb); + + pos=s->read_filepos - s->offset; + if(pos<0) pos+=s->buffer_size; else + if(pos>=s->buffer_size) pos-=s->buffer_size; + + if(newb>s->buffer_size-pos) newb=s->buffer_size-pos; // handle wrap... + if(newb>size) newb=size; + + // check: + if(s->read_filepos<s->min_filepos) mp_msg(MSGT_CACHE,MSGL_ERR,"Ehh. s->read_filepos<s->min_filepos !!! Report bug...\n"); + + // len=write(mem,newb) + //printf("Buffer read: %d bytes\n",newb); + memcpy(buf,&s->buffer[pos],newb); + buf+=newb; + len=newb; + // ... + + s->read_filepos+=len; + size-=len; + total+=len; + + } + cache_fill_status=(s->max_filepos-s->read_filepos)/(s->buffer_size / 100); + return total; +} + +int cache_fill(cache_vars_t* s){ + int back,back2,newb,space,len,pos; + off_t read=s->read_filepos; + + if(read<s->min_filepos || read>s->max_filepos){ + // seek... + mp_msg(MSGT_CACHE,MSGL_DBG2,"Out of boundaries... seeking to 0x%"PRIX64" \n",(int64_t)read); + // streaming: drop cache contents only if seeking backward or too much fwd: + if(s->stream->type!=STREAMTYPE_STREAM || + read<s->min_filepos || read>=s->max_filepos+s->seek_limit) + { + s->offset= // FIXME!? + s->min_filepos=s->max_filepos=read; // drop cache content :( + if(s->stream->eof) stream_reset(s->stream); + stream_seek(s->stream,read); + mp_msg(MSGT_CACHE,MSGL_DBG2,"Seek done. new pos: 0x%"PRIX64" \n",(int64_t)stream_tell(s->stream)); + } + } + + // calc number of back-bytes: + back=read - s->min_filepos; + if(back<0) back=0; // strange... + if(back>s->back_size) back=s->back_size; + + // calc number of new bytes: + newb=s->max_filepos - read; + if(newb<0) newb=0; // strange... + + // calc free buffer space: + space=s->buffer_size - (newb+back); + + // calc bufferpos: + pos=s->max_filepos - s->offset; + if(pos>=s->buffer_size) pos-=s->buffer_size; // wrap-around + + if(space<s->fill_limit){ +// printf("Buffer is full (%d bytes free, limit: %d)\n",space,s->fill_limit); + return 0; // no fill... + } + +// printf("### read=0x%X back=%d newb=%d space=%d pos=%d\n",read,back,newb,space,pos); + + // reduce space if needed: + if(space>s->buffer_size-pos) space=s->buffer_size-pos; + +// if(space>32768) space=32768; // limit one-time block size + if(space>4*s->sector_size) space=4*s->sector_size; + +// if(s->seek_lock) return 0; // FIXME + +#if 1 + // back+newb+space <= buffer_size + back2=s->buffer_size-(space+newb); // max back size + if(s->min_filepos<(read-back2)) s->min_filepos=read-back2; +#else + s->min_filepos=read-back; // avoid seeking-back to temp area... +#endif + + // .... + //printf("Buffer fill: %d bytes of %d\n",space,s->buffer_size); + //len=stream_fill_buffer(s->stream); + //memcpy(&s->buffer[pos],s->stream->buffer,len); // avoid this extra copy! + // .... + len=stream_read(s->stream,&s->buffer[pos],space); + if(!len) s->eof=1; + + s->max_filepos+=len; + if(pos+len>=s->buffer_size){ + // wrap... + s->offset+=s->buffer_size; + } + + return len; + +} + +cache_vars_t* cache_init(int size,int sector){ + int num; +#ifndef WIN32 + cache_vars_t* s=shmem_alloc(sizeof(cache_vars_t)); +#else + cache_vars_t* s=malloc(sizeof(cache_vars_t)); +#endif + if(s==NULL) return NULL; + + memset(s,0,sizeof(cache_vars_t)); + num=size/sector; + if(num < 16){ + num = 16; + }//32kb min_size + s->buffer_size=num*sector; + s->sector_size=sector; +#ifndef WIN32 + s->buffer=shmem_alloc(s->buffer_size); +#else + s->buffer=malloc(s->buffer_size); +#endif + + if(s->buffer == NULL){ +#ifndef WIN32 + shmem_free(s,sizeof(cache_vars_t)); +#else + free(s); +#endif + return NULL; + } + + s->fill_limit=8*sector; + s->back_size=s->buffer_size/2; + return s; +} + +void cache_uninit(stream_t *s) { + cache_vars_t* c = s->cache_data; + if(!s->cache_pid) return; +#ifndef WIN32 + kill(s->cache_pid,SIGKILL); + waitpid(s->cache_pid,NULL,0); +#else + TerminateThread((HANDLE)s->cache_pid,0); + free(c->stream); +#endif + if(!c) return; +#ifndef WIN32 + shmem_free(c->buffer,c->buffer_size); + shmem_free(s->cache_data,sizeof(cache_vars_t)); +#else + free(c->buffer); + free(s->cache_data); +#endif +} + +static void exit_sighandler(int x){ + // close stream + exit(0); +} + +int stream_enable_cache(stream_t *stream,int size,int min,int seek_limit){ + int ss=(stream->type==STREAMTYPE_VCD)?VCD_SECTOR_DATA:STREAM_BUFFER_SIZE; + cache_vars_t* s; + + if (stream->type==STREAMTYPE_STREAM && stream->fd < 0) { + // The stream has no 'fd' behind it, so is non-cacheable + mp_msg(MSGT_CACHE,MSGL_STATUS,"\rThis stream is non-cacheable\n"); + return 1; + } + + s=cache_init(size,ss); + if(s == NULL) return 0; + stream->cache_data=s; + s->stream=stream; // callback + s->seek_limit=seek_limit; + + + //make sure that we won't wait from cache_fill + //more data than it is alowed to fill + if (s->seek_limit > s->buffer_size - s->fill_limit ){ + s->seek_limit = s->buffer_size - s->fill_limit; + } + if (min > s->buffer_size - s->fill_limit) { + min = s->buffer_size - s->fill_limit; + } + +#ifndef WIN32 + if((stream->cache_pid=fork())){ +#else + { + DWORD threadId; + stream_t* stream2=malloc(sizeof(stream_t)); + memcpy(stream2,s->stream,sizeof(stream_t)); + s->stream=stream2; + stream->cache_pid = CreateThread(NULL,0,ThreadProc,s,0,&threadId); +#endif + // wait until cache is filled at least prefill_init % + mp_msg(MSGT_CACHE,MSGL_V,"CACHE_PRE_INIT: %"PRId64" [%"PRId64"] %"PRId64" pre:%d eof:%d \n", + (int64_t)s->min_filepos,(int64_t)s->read_filepos,(int64_t)s->max_filepos,min,s->eof); + while(s->read_filepos<s->min_filepos || s->max_filepos-s->read_filepos<min){ + mp_msg(MSGT_CACHE,MSGL_STATUS,MSGTR_CacheFill, + 100.0*(float)(s->max_filepos-s->read_filepos)/(float)(s->buffer_size), + (int64_t)s->max_filepos-s->read_filepos + ); + if(s->eof) break; // file is smaller than prefill size + if(mp_input_check_interrupt(PREFILL_SLEEP_TIME)) + return 0; + } + mp_msg(MSGT_CACHE,MSGL_STATUS,"\n"); + return 1; // parent exits + } + +#ifdef WIN32 +} +static DWORD WINAPI ThreadProc(void*s){ +#endif + +// cache thread mainloop: + signal(SIGTERM,exit_sighandler); // kill + while(1){ + if(!cache_fill((cache_vars_t*)s)){ + usec_sleep(FILL_USLEEP_TIME); // idle + } +// cache_stats(s->cache_data); + } +} + +int cache_stream_fill_buffer(stream_t *s){ + int len; + if(s->eof){ s->buf_pos=s->buf_len=0; return 0; } + if(!s->cache_pid) return stream_fill_buffer(s); + +// cache_stats(s->cache_data); + + if(s->pos!=((cache_vars_t*)s->cache_data)->read_filepos) mp_msg(MSGT_CACHE,MSGL_ERR,"!!! read_filepos differs!!! report this bug...\n"); + + len=cache_read(s->cache_data,s->buffer, ((cache_vars_t*)s->cache_data)->sector_size); + //printf("cache_stream_fill_buffer->read -> %d\n",len); + + if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; } + s->buf_pos=0; + s->buf_len=len; + s->pos+=len; +// printf("[%d]",len);fflush(stdout); + return len; + +} + +int cache_stream_seek_long(stream_t *stream,off_t pos){ + cache_vars_t* s; + off_t newpos; + if(!stream->cache_pid) return stream_seek_long(stream,pos); + + s=stream->cache_data; +// s->seek_lock=1; + + mp_msg(MSGT_CACHE,MSGL_DBG2,"CACHE2_SEEK: 0x%"PRIX64" <= 0x%"PRIX64" (0x%"PRIX64") <= 0x%"PRIX64" \n",s->min_filepos,pos,s->read_filepos,s->max_filepos); + + newpos=pos/s->sector_size; newpos*=s->sector_size; // align + stream->pos=s->read_filepos=newpos; + s->eof=0; // !!!!!!! + + cache_stream_fill_buffer(stream); + + pos-=newpos; + if(pos>=0 && pos<=stream->buf_len){ + stream->buf_pos=pos; // byte position in sector + return 1; + } + +// stream->buf_pos=stream->buf_len=0; +// return 1; + + mp_msg(MSGT_CACHE,MSGL_V,"cache_stream_seek: WARNING! Can't seek to 0x%"PRIX64" !\n",(int64_t)(pos+newpos)); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cdd.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,77 @@ +#ifndef __CDD_H__ +#define __CDD_H__ + +#include "config.h" +#ifndef HAVE_LIBCDIO +#include <cdda_interface.h> +#include <cdda_paranoia.h> +#else +#include <cdio/cdda.h> +#include <cdio/paranoia.h> +#endif + +typedef struct { + char cddb_hello[1024]; + unsigned long disc_id; + unsigned int tracks; + char *cache_dir; + char *freedb_server; + int freedb_proto_level; + int anonymous; + char category[100]; + char *xmcd_file; + size_t xmcd_file_size; + void *user_data; +} cddb_data_t; + +typedef struct { + unsigned int min, sec, frame; +} cd_toc_t; + +typedef struct cd_track { + char *name; + unsigned int track_nb; + unsigned int min; + unsigned int sec; + unsigned int msec; + unsigned long frame_begin; + unsigned long frame_length; + struct cd_track *prev; + struct cd_track *next; +} cd_track_t; + +typedef struct { + char *artist; + char *album; + char *genre; + unsigned int nb_tracks; + unsigned int min; + unsigned int sec; + unsigned msec; + cd_track_t *first; + cd_track_t *last; + cd_track_t *current; +} cd_info_t; + +typedef struct { +#ifndef HAVE_LIBCDIO + cdrom_drive* cd; + cdrom_paranoia* cdp; +#else + cdrom_drive_t* cd; + cdrom_paranoia_t* cdp; +#endif + int sector; + int start_sector; + int end_sector; + cd_info_t *cd_info; +} cdda_priv; + +cd_info_t* cd_info_new(); +void cd_info_free(cd_info_t *cd_info); +cd_track_t* cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length); +cd_track_t* cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb); + +void cd_info_debug(cd_info_t *cd_info); + +#endif // __CDD_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cdda.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,391 @@ +#include "config.h" + +#include "stream.h" +#include "m_option.h" +#include "m_struct.h" +#include "bswap.h" + +#include <stdio.h> +#include <stdlib.h> +#include "demuxer.h" + +#include "cdd.h" + +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef CD_FRAMESIZE_RAW +#define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW +#endif + + +extern char *cdrom_device; + +static struct cdda_params { + int speed; + int paranoia_mode; + char* generic_dev; + int sector_size; + int search_overlap; + int toc_bias; + int toc_offset; + int no_skip; + char* device; + m_span_t span; +} cdda_dflts = { + -1, + 0, + NULL, + 0, + -1, + 0, + 0, + 0, + NULL, + { 0, 0 } +}; + +#define ST_OFF(f) M_ST_OFF(struct cdda_params,f) +m_option_t cdda_params_fields[] = { + { "speed", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, + { "paranoia", ST_OFF(paranoia_mode), CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL }, + { "generic-dev", ST_OFF(generic_dev), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "sector-size", ST_OFF(sector_size), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, + { "overlap", ST_OFF(search_overlap), CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL }, + { "toc-bias", ST_OFF(toc_bias), CONF_TYPE_INT, 0, 0, 0, NULL }, + { "toc-offset", ST_OFF(toc_offset), CONF_TYPE_INT, 0, 0, 0, NULL }, + { "noskip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 0, 1, NULL }, + { "skip", ST_OFF(no_skip), CONF_TYPE_FLAG, 0 , 1, 0, NULL }, + { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "span", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, + /// For url parsing + { "hostname", ST_OFF(span), CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, + { "port", ST_OFF(speed), CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, + { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; +static struct m_struct_st stream_opts = { + "cdda", + sizeof(struct cdda_params), + &cdda_dflts, + cdda_params_fields +}; + +/// We keep these options but now they set the defaults +m_option_t cdda_opts[] = { + { "speed", &cdda_dflts.speed, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, + { "paranoia", &cdda_dflts.paranoia_mode, CONF_TYPE_INT,M_OPT_RANGE, 0, 2, NULL }, + { "generic-dev", &cdda_dflts.generic_dev, CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "sector-size", &cdda_dflts.sector_size, CONF_TYPE_INT, M_OPT_RANGE,1,100, NULL }, + { "overlap", &cdda_dflts.search_overlap, CONF_TYPE_INT, M_OPT_RANGE,0,75, NULL }, + { "toc-bias", &cdda_dflts.toc_bias, CONF_TYPE_INT, 0, 0, 0, NULL }, + { "toc-offset", &cdda_dflts.toc_offset, CONF_TYPE_INT, 0, 0, 0, NULL }, + { "noskip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 0, 1, NULL }, + { "skip", &cdda_dflts.no_skip, CONF_TYPE_FLAG, 0 , 1, 0, NULL }, + { "device", &cdda_dflts.device, CONF_TYPE_STRING, 0, 0, 0, NULL }, + { "span", &cdda_dflts.span, CONF_TYPE_OBJ_PARAMS, 0, 0, 0, &m_span_params_def }, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + +extern int cdd_identify(const char *dev); +extern int cddb_resolve(const char *dev, char **xmcd_file); +extern cd_info_t* cddb_parse_xmcd(char *xmcd_file); + +static int seek(stream_t* s,off_t pos); +static int fill_buffer(stream_t* s, char* buffer, int max_len); +static void close_cdda(stream_t* s); + +static int open_cdda(stream_t *st,int m, void* opts, int* file_format) { + struct cdda_params* p = (struct cdda_params*)opts; + int mode = p->paranoia_mode; + int offset = p->toc_offset; +#ifndef HAVE_LIBCDIO + cdrom_drive* cdd = NULL; +#else + cdrom_drive_t* cdd = NULL; +#endif + cdda_priv* priv; + cd_info_t *cd_info,*cddb_info = NULL; + unsigned int audiolen=0; + int last_track; + int i; + char *xmcd_file = NULL; + + if(m != STREAM_READ) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + + if(!p->device) { + if (cdrom_device) + p->device = strdup(cdrom_device); + else + p->device = strdup(DEFAULT_CDROM_DEVICE); + } + +#ifdef MPLAYER_NETWORK + // cdd_identify returns -1 if it cannot read the TOC, + // in which case there is no point in calling cddb_resolve + if(cdd_identify(p->device) >= 0 && strncmp(st->url,"cddb",4) == 0) { + i = cddb_resolve(p->device, &xmcd_file); + if(i == 0) { + cddb_info = cddb_parse_xmcd(xmcd_file); + free(xmcd_file); + } + } +#endif + +#ifndef HAVE_LIBCDIO + if(p->generic_dev) + cdd = cdda_identify_scsi(p->generic_dev,p->device,0,NULL); + else +#endif +#if defined(__NetBSD__) + cdd = cdda_identify_scsi(p->device,p->device,0,NULL); +#else + cdd = cdda_identify(p->device,0,NULL); +#endif + + if(!cdd) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice); + m_struct_free(&stream_opts,opts); + free(cddb_info); + return STREAM_ERROR; + } + + cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); + + if(p->sector_size) { + cdd->nsectors = p->sector_size; +#ifndef HAVE_LIBCDIO + cdd->bigbuff = p->sector_size * CD_FRAMESIZE_RAW; +#endif + } + + if(cdda_open(cdd) != 0) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenDisc); + cdda_close(cdd); + m_struct_free(&stream_opts,opts); + free(cddb_info); + return STREAM_ERROR; + } + + cd_info = cd_info_new(); + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks,cdda_tracks(cdd)); + for(i=0;i<cdd->tracks;i++) { + char track_name[80]; + long sec=cdda_track_firstsector(cdd,i+1); + long off=cdda_track_lastsector(cdd,i+1)-sec+1; + + sprintf(track_name, "Track %d", i+1); + cd_info_add_track(cd_info, track_name, i+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off ); + audiolen += off; + } + cd_info->min = (unsigned int)(audiolen/(60*75)); + cd_info->sec = (unsigned int)((audiolen/75)%60); + cd_info->msec = (unsigned int)(audiolen%75); + + priv = malloc(sizeof(cdda_priv)); + memset(priv, 0, sizeof(cdda_priv)); + priv->cd = cdd; + priv->cd_info = cd_info; + + if(p->toc_bias) + offset -= cdda_track_firstsector(cdd,1); + + if(offset) { + int i; + for(i = 0 ; i < cdd->tracks + 1 ; i++) + cdd->disc_toc[i].dwStartSector += offset; + } + + if(p->speed) + cdda_speed_set(cdd,p->speed); + + last_track = cdda_tracks(cdd); + if (p->span.start > last_track) p->span.start = last_track; + if (p->span.end < p->span.start) p->span.end = p->span.start; + if (p->span.end > last_track) p->span.end = last_track; + if(p->span.start) + priv->start_sector = cdda_track_firstsector(cdd,p->span.start); + else + priv->start_sector = cdda_disc_firstsector(cdd); + + if(p->span.end) { + priv->end_sector = cdda_track_lastsector(cdd,p->span.end); + } else + priv->end_sector = cdda_disc_lastsector(cdd); + + priv->cdp = paranoia_init(cdd); + if(priv->cdp == NULL) { + cdda_close(cdd); + free(priv); + cd_info_free(cd_info); + m_struct_free(&stream_opts,opts); + free(cddb_info); + return STREAM_ERROR; + } + + if(mode == 0) + mode = PARANOIA_MODE_DISABLE; + else if(mode == 1) + mode = PARANOIA_MODE_OVERLAP; + else + mode = PARANOIA_MODE_FULL; + + if(p->no_skip) + mode |= PARANOIA_MODE_NEVERSKIP; +#ifndef HAVE_LIBCDIO + paranoia_modeset(cdd, mode); + + if(p->search_overlap >= 0) + paranoia_overlapset(cdd,p->search_overlap); +#else + paranoia_modeset(priv->cdp, mode); + + if(p->search_overlap >= 0) + paranoia_overlapset(priv->cdp,p->search_overlap); +#endif + + paranoia_seek(priv->cdp,priv->start_sector,SEEK_SET); + priv->sector = priv->start_sector; + +#ifdef MPLAYER_NETWORK + if(cddb_info) { + cd_info_free(cd_info); + priv->cd_info = cddb_info; + cd_info_debug( cddb_info ); + } +#endif + + st->priv = priv; + st->start_pos = priv->start_sector*CD_FRAMESIZE_RAW; + st->end_pos = priv->end_sector*CD_FRAMESIZE_RAW; + st->type = STREAMTYPE_CDDA; + st->sector_size = CD_FRAMESIZE_RAW; + + st->fill_buffer = fill_buffer; + st->seek = seek; + st->close = close_cdda; + + *file_format = DEMUXER_TYPE_RAWAUDIO; + + m_struct_free(&stream_opts,opts); + + return STREAM_OK; +} + +#ifndef HAVE_LIBCDIO +static void cdparanoia_callback(long inpos, int function) { +#else +static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function) { +#endif +} + +static int fill_buffer(stream_t* s, char* buffer, int max_len) { + cdda_priv* p = (cdda_priv*)s->priv; + cd_track_t *cd_track; + int16_t * buf; + int i; + + buf = paranoia_read(p->cdp,cdparanoia_callback); + +#ifdef WORDS_BIGENDIAN + for(i=0;i<CD_FRAMESIZE_RAW/2;i++) + buf[i]=le2me_16(buf[i]); +#endif + + p->sector++; + s->pos = p->sector*CD_FRAMESIZE_RAW; + memcpy(buffer,buf,CD_FRAMESIZE_RAW); + + if((p->sector < p->start_sector) || (p->sector >= p->end_sector)) { + s->eof = 1; + return 0; + } + + for(i=0;i<p->cd->tracks;i++){ + if(p->cd->disc_toc[i].dwStartSector==p->sector-1) { + cd_track = cd_info_get_track(p->cd_info, i+1); +//printf("Track %d, sector=%d\n", i, p->sector-1); + if( cd_track!=NULL ) { + mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb); + } + break; + } + } + + + return CD_FRAMESIZE_RAW; +} + +static int seek(stream_t* s,off_t newpos) { + cdda_priv* p = (cdda_priv*)s->priv; + cd_track_t *cd_track; + int sec; + int current_track=0, seeked_track=0; + int i; + + s->pos = newpos; + if(s->pos < 0) { + s->eof = 1; + return 0; + } + + sec = s->pos/CD_FRAMESIZE_RAW; +//printf("pos: %d, sec: %d ## %d\n", (int)s->pos, (int)sec, CD_FRAMESIZE_RAW); +//printf("sector: %d new: %d\n", p->sector, sec ); + + for(i=0;i<p->cd->tracks;i++){ +// printf("trk #%d: %d .. %d\n",i,p->cd->disc_toc[i].dwStartSector,p->cd->disc_toc[i+1].dwStartSector); + if( p->sector>=p->cd->disc_toc[i].dwStartSector && p->sector<p->cd->disc_toc[i+1].dwStartSector ) { + current_track = i; + } + if( sec>=p->cd->disc_toc[i].dwStartSector && sec<p->cd->disc_toc[i+1].dwStartSector ) { + seeked_track = i; + } + } +//printf("current: %d, seeked: %d\n", current_track, seeked_track); + if( current_track!=seeked_track ) { +//printf("Track %d, sector=%d\n", seeked_track, sec); + cd_track = cd_info_get_track(p->cd_info, seeked_track+1); + if( cd_track!=NULL ) { + mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb); + } + + } +#if 0 + if(sec < p->start_sector) + sec = p->start_sector; + else if(sec > p->end_sector) + sec = p->end_sector; +#endif + + p->sector = sec; +// s->pos = sec*CD_FRAMESIZE_RAW; + +//printf("seek: %d, sec: %d\n", (int)s->pos, sec); + paranoia_seek(p->cdp,sec,SEEK_SET); + return 1; +} + +static void close_cdda(stream_t* s) { + cdda_priv* p = (cdda_priv*)s->priv; + paranoia_free(p->cdp); + cdda_close(p->cd); + cd_info_free(p->cd_info); + free(p); +} + +stream_info_t stream_info_cdda = { + "CDDA", + "cdda", + "Albeu", + "", + open_cdda, + { "cdda", "cddb", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cddb.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,878 @@ +/* + * CDDB HTTP protocol + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2002, MPlayer team. + * + * Implementation follow the freedb.howto1.06.txt specification + * from http://freedb.freedb.org + * + * discid computation by Jeremy D. Zawodny + * Copyright (c) 1998-2000 Jeremy D. Zawodny <Jeremy@Zawodny.com> + * Code release under GPL + * + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <stdarg.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#ifdef WIN32 +#ifdef __MINGW32__ +#define mkdir(a,b) mkdir(a) +#endif +#include <windows.h> +#ifdef HAVE_WINSOCK2 +#include <winsock2.h> +#endif +#else +#include <netdb.h> +#include <sys/ioctl.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> + +#include "mp_msg.h" +#include "help_mp.h" + +#if defined(__linux__) + #include <linux/cdrom.h> +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #include <sys/cdio.h> +#elif defined(WIN32) + #include <ddk/ntddcdrm.h> +#elif (__bsdi__) + #include <dvd.h> +#endif + +#include "cdd.h" +#include "version.h" +#include "stream.h" +#include "network.h" + +#define DEFAULT_FREEDB_SERVER "freedb.freedb.org" +#define DEFAULT_CACHE_DIR "/.cddb/" + +stream_t* open_cdda(char *dev, char *track); + +static cd_toc_t cdtoc[100]; +static int cdtoc_last_track; + +#if defined(__linux__) || defined(__bsdi__) +int +read_toc(const char *dev) { + int drive; + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocentry; + int i; + + drive = open(dev, O_RDONLY | O_NONBLOCK); + if( drive<0 ) { + return drive; + } + + ioctl(drive, CDROMREADTOCHDR, &tochdr); + for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) { + tocentry.cdte_track = i; + tocentry.cdte_format = CDROM_MSF; + ioctl(drive, CDROMREADTOCENTRY, &tocentry); + cdtoc[i-1].min = tocentry.cdte_addr.msf.minute; + cdtoc[i-1].sec = tocentry.cdte_addr.msf.second; + cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame; + cdtoc[i-1].frame += cdtoc[i-1].min*60*75; + cdtoc[i-1].frame += cdtoc[i-1].sec*75; + } + tocentry.cdte_track = 0xAA; + tocentry.cdte_format = CDROM_MSF; + ioctl(drive, CDROMREADTOCENTRY, &tocentry); + cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute; + cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second; + cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame; + cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75; + cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75; + close(drive); + return tochdr.cdth_trk1; +} + +#elif defined(WIN32) +int +read_toc(const char *dev) { + HANDLE drive; + DWORD r; + CDROM_TOC toc; + char device[10]; + int i; + + sprintf(device, "\\\\.\\%s", dev); + drive = CreateFile(device, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + + if(!DeviceIoControl(drive, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(CDROM_TOC), &r, 0)) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadTOC); + return 0; + } + + for (i = toc.FirstTrack; i <= toc.LastTrack; i++) { + toc.FirstTrack = i; + cdtoc[i-1].min = toc.TrackData[i - 1].Address[1]; + cdtoc[i-1].sec = toc.TrackData[i - 1].Address[2]; + cdtoc[i-1].frame = toc.TrackData[i - 1].Address[3]; + cdtoc[i-1].frame += cdtoc[i-1].min*60*75; + cdtoc[i-1].frame += cdtoc[i-1].sec*75; + } + toc.FirstTrack = 0xAA; + cdtoc[toc.LastTrack].min = toc.TrackData[toc.LastTrack].Address[1]; + cdtoc[toc.LastTrack].sec = toc.TrackData[toc.LastTrack].Address[2]; + cdtoc[toc.LastTrack].frame = toc.TrackData[toc.LastTrack].Address[3]; + cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].min*60*75; + cdtoc[toc.LastTrack].frame += cdtoc[toc.LastTrack].sec*75; + CloseHandle(drive); + return toc.LastTrack; +} + +#elif defined(__FreeBSD__) || defined(__DragonFly__) +int +read_toc(const char *dev) { + int drive; + struct ioc_toc_header tochdr; + struct ioc_read_toc_single_entry tocentry; + int i; + + drive = open(dev, O_RDONLY | O_NONBLOCK); + if( drive<0 ) { + return drive; + } + + ioctl(drive, CDIOREADTOCHEADER, &tochdr); + for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { + tocentry.track = i; + tocentry.address_format = CD_MSF_FORMAT; + ioctl(drive, CDIOREADTOCENTRY, &tocentry); + cdtoc[i-1].min = tocentry.entry.addr.msf.minute; + cdtoc[i-1].sec = tocentry.entry.addr.msf.second; + cdtoc[i-1].frame = tocentry.entry.addr.msf.frame; + cdtoc[i-1].frame += cdtoc[i-1].min*60*75; + cdtoc[i-1].frame += cdtoc[i-1].sec*75; + } + tocentry.track = 0xAA; + tocentry.address_format = CD_MSF_FORMAT; + ioctl(drive, CDIOREADTOCENTRY, &tocentry); + cdtoc[tochdr.ending_track].min = tocentry.entry.addr.msf.minute; + cdtoc[tochdr.ending_track].sec = tocentry.entry.addr.msf.second; + cdtoc[tochdr.ending_track].frame = tocentry.entry.addr.msf.frame; + cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75; + cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75; + close(drive); + return tochdr.ending_track; +} + +#elif defined(__NetBSD__) || defined(__OpenBSD__) +int +read_toc(const char *dev) { + int drive; + struct ioc_toc_header tochdr; + struct ioc_read_toc_entry tocentry; + int i; + struct cd_toc_entry toc_buffer; + + drive = open(dev, O_RDONLY | O_NONBLOCK); + if( drive<0 ) { + return drive; + } + + ioctl(drive, CDIOREADTOCHEADER, &tochdr); + for (i = tochdr.starting_track; i <= tochdr.ending_track; i++) { + tocentry.starting_track = i; + tocentry.address_format = CD_MSF_FORMAT; + tocentry.data = &toc_buffer; + tocentry.data_len = sizeof(toc_buffer); + ioctl(drive, CDIOREADTOCENTRYS, &tocentry); + cdtoc[i-1].min = toc_buffer.addr.msf.minute; + cdtoc[i-1].sec = toc_buffer.addr.msf.second; + cdtoc[i-1].frame = toc_buffer.addr.msf.frame; + cdtoc[i-1].frame += cdtoc[i-1].min*60*75; + cdtoc[i-1].frame += cdtoc[i-1].sec*75; + } + tocentry.starting_track = 0xAA; + tocentry.address_format = CD_MSF_FORMAT; + ioctl(drive, CDIOREADTOCENTRYS, &tocentry); + cdtoc[tochdr.ending_track].min = toc_buffer.addr.msf.minute; + cdtoc[tochdr.ending_track].sec = toc_buffer.addr.msf.second; + cdtoc[tochdr.ending_track].frame = toc_buffer.addr.msf.frame; + cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].min*60*75; + cdtoc[tochdr.ending_track].frame += cdtoc[tochdr.ending_track].sec*75; + close(drive); + return tochdr.ending_track; +} +#endif + +/** +\brief Reads TOC from CD in the given device and prints the number of tracks + and the length of each track in minute:second:frame format. +\param *dev the device to analyse +\return if the command line -identify is given, returns the last track of + the TOC or -1 if the TOC can't be read, + otherwise just returns 0 and let cddb_resolve the TOC +*/ +int cdd_identify(const char *dev) +{ + cdtoc_last_track = 0; + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + int i, min, sec, frame; + cdtoc_last_track = read_toc(dev); + if (cdtoc_last_track < 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev); + return -1; + } + mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_CDDA_TRACKS=%d\n", cdtoc_last_track); + for (i = 1; i <= cdtoc_last_track; i++) + { + frame = cdtoc[i].frame - cdtoc[i-1].frame; + sec = frame / 75; + frame -= sec * 75; + min = sec / 60; + sec -= min * 60; + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK_%d_MSF=%02d:%02d:%02d\n", i, min, sec, frame); + } + } + return cdtoc_last_track; +} + +unsigned int +cddb_sum(int n) { + unsigned int ret; + + ret = 0; + while (n > 0) { + ret += (n % 10); + n /= 10; + } + return ret; +} + +unsigned long +cddb_discid(int tot_trks) { + unsigned int i, t = 0, n = 0; + + i = 0; + while (i < (unsigned int)tot_trks) { + n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec); + i++; + } + t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) - + ((cdtoc[0].min * 60) + cdtoc[0].sec); + return ((n % 0xff) << 24 | t << 8 | tot_trks); +} + + + +int +cddb_http_request(char *command, int (*reply_parser)(HTTP_header_t*,cddb_data_t*), cddb_data_t *cddb_data) { + char request[4096]; + int fd, ret = 0; + URL_t *url; + HTTP_header_t *http_hdr; + + if( reply_parser==NULL || command==NULL || cddb_data==NULL ) return -1; + + sprintf( request, "http://%s/~cddb/cddb.cgi?cmd=%s%s&proto=%d", cddb_data->freedb_server, command, cddb_data->cddb_hello, cddb_data->freedb_proto_level ); + mp_msg(MSGT_OPEN, MSGL_INFO,"Request[%s]\n", request ); + + url = url_new(request); + if( url==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NotAValidURL); + return -1; + } + + fd = http_send_request(url,0); + if( fd<0 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest); + return -1; + } + + http_hdr = http_read_response( fd ); + if( http_hdr==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse); + return -1; + } + + http_debug_hdr(http_hdr); + mp_msg(MSGT_OPEN, MSGL_INFO,"body=[%s]\n", http_hdr->body ); + + switch(http_hdr->status_code) { + case 200: + ret = reply_parser(http_hdr, cddb_data); + break; + case 400: + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorNOTFOUND); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_HTTPErrorUnknown); + } + + http_free( http_hdr ); + url_free( url ); + + return ret; +} + +int +cddb_read_cache(cddb_data_t *cddb_data) { + char file_name[100]; + struct stat stats; + int file_fd, ret; + size_t file_size; + + if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1; + + sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id); + + file_fd = open(file_name, O_RDONLY +#ifdef WIN32 + | O_BINARY +#endif + ); + if( file_fd<0 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCacheFound); + return -1; + } + + ret = fstat( file_fd, &stats ); + if( ret<0 ) { + perror("fstat"); + file_size = 4096; + } else { + file_size = stats.st_size; + } + + cddb_data->xmcd_file = malloc(file_size); + if( cddb_data->xmcd_file==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); + close(file_fd); + return -1; + } + cddb_data->xmcd_file_size = read(file_fd, cddb_data->xmcd_file, file_size); + if( cddb_data->xmcd_file_size!=file_size ) { + mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenRead); + close(file_fd); + return -1; + } + + close(file_fd); + + return 0; +} + +int +cddb_write_cache(cddb_data_t *cddb_data) { + // We have the file, save it for cache. + struct stat file_stat; + char file_name[100]; + int file_fd, ret; + int wrote=0; + + if( cddb_data==NULL || cddb_data->cache_dir==NULL ) return -1; + + // Check if the CDDB cache dir exist + ret = stat( cddb_data->cache_dir, &file_stat ); + if( ret<0 ) { + // Directory not present, create it. + ret = mkdir( cddb_data->cache_dir, 0755 ); +#ifdef __MINGW32__ + if( ret<0 && errno != EEXIST ) { +#else + if( ret<0 ) { +#endif + perror("mkdir"); + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToCreateDirectory, cddb_data->cache_dir); + return -1; + } + } + + sprintf( file_name, "%s%08lx", cddb_data->cache_dir, cddb_data->disc_id ); + + file_fd = creat(file_name, S_IREAD|S_IWRITE); + if( file_fd<0 ) { + perror("create"); + return -1; + } + + wrote = write(file_fd, cddb_data->xmcd_file, cddb_data->xmcd_file_size); + if( wrote<0 ) { + perror("write"); + close(file_fd); + return -1; + } + if( (unsigned int)wrote!=cddb_data->xmcd_file_size ) { + mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_NotAllXMCDFileHasBeenWritten); + close(file_fd); + return -1; + } + + close(file_fd); + + return 0; +} + +int +cddb_read_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { + unsigned long disc_id; + char category[100]; + char *ptr=NULL, *ptr2=NULL; + int ret, status; + + if( http_hdr==NULL || cddb_data==NULL ) return -1; + + ret = sscanf( http_hdr->body, "%d ", &status); + if( ret!=1 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + + switch(status) { + case 210: + ret = sscanf( http_hdr->body, "%d %s %08lx", &status, category, &disc_id); + if( ret!=3 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + // Check if it's a xmcd database file + ptr = strstr(http_hdr->body, "# xmcd"); + if( ptr==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_InvalidXMCDDatabaseReturned); + return -1; + } + // Ok found the beginning of the file + // look for the end + ptr2 = strstr(ptr, "\r\n.\r\n"); + if( ptr2==NULL ) { + ptr2 = strstr(ptr, "\n.\n"); + if( ptr2==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_FIXME, "Unable to find '.'\n"); + ptr2=ptr+strlen(ptr); //return -1; + } + } + // Ok found the end + // do a sanity check + if( http_hdr->body_size<(unsigned int)(ptr2-ptr) ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnexpectedFIXME); + return -1; + } + cddb_data->xmcd_file = ptr; + cddb_data->xmcd_file_size = ptr2-ptr+2; + cddb_data->xmcd_file[cddb_data->xmcd_file_size] = '\0'; + // Avoid the http_free function to free the xmcd file...save a mempcy... + http_hdr->body = NULL; + http_hdr->body_size = 0; + return cddb_write_cache(cddb_data); + default: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); + } + return 0; +} + +int +cddb_request_titles(cddb_data_t *cddb_data) { + char command[1024]; + sprintf( command, "cddb+read+%s+%08lx", cddb_data->category, cddb_data->disc_id); + return cddb_http_request(command, cddb_read_parse, cddb_data); +} + +int +cddb_parse_matches_list(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { + char album_title[100]; + char *ptr = NULL; + int ret; + + ptr = strstr(http_hdr->body, "\n"); + if( ptr==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_UnableToFindEOL); + return -1; + } + ptr++; + // We have a list of exact/inexact matches, so which one do we use? + // So let's take the first one. + ret = sscanf(ptr, "%s %08lx %s", cddb_data->category, &(cddb_data->disc_id), album_title); + if( ret!=3 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + ptr = strstr(http_hdr->body, album_title); + if( ptr!=NULL ) { + char *ptr2; + int len; + ptr2 = strstr(ptr, "\n"); + if( ptr2==NULL ) { + len = (http_hdr->body_size)-(ptr-(http_hdr->body)); + } else { + len = ptr2-ptr+1; + } + strncpy(album_title, ptr, len); + album_title[len-2]='\0'; + } + mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title); + return 0; +} + +int +cddb_query_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { + char album_title[100]; + char *ptr = NULL; + int ret, status; + + ret = sscanf( http_hdr->body, "%d ", &status); + if( ret!=1 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + + switch(status) { + case 200: + // Found exact match + ret = sscanf(http_hdr->body, "%d %s %08lx %s", &status, cddb_data->category, &(cddb_data->disc_id), album_title); + if( ret!=4 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + ptr = strstr(http_hdr->body, album_title); + if( ptr!=NULL ) { + char *ptr2; + int len; + ptr2 = strstr(ptr, "\n"); + if( ptr2==NULL ) { + len = (http_hdr->body_size)-(ptr-(http_hdr->body)); + } else { + len = ptr2-ptr+1; + } + strncpy(album_title, ptr, len); + album_title[len-2]='\0'; + } + mp_msg(MSGT_DEMUX, MSGL_STATUS, MSGTR_MPDEMUX_CDDB_ParseOKFoundAlbumTitle, album_title); + return cddb_request_titles(cddb_data); + case 202: + // No match found + mp_msg(MSGT_DEMUX, MSGL_WARN, MSGTR_MPDEMUX_CDDB_AlbumNotFound); + break; + case 210: + // Found exact matches, list follows + cddb_parse_matches_list(http_hdr, cddb_data); + return cddb_request_titles(cddb_data); +/* +body=[210 Found exact matches, list follows (until terminating `.') +misc c711930d Santana / Supernatural +rock c711930d Santana / Supernatural +blues c711930d Santana / Supernatural +.] +*/ + case 211: + // Found inexact matches, list follows + cddb_parse_matches_list(http_hdr, cddb_data); + return cddb_request_titles(cddb_data); + case 500: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_ServerReturnsCommandSyntaxErr); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); + } + return -1; +} + +int +cddb_proto_level_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { + int max; + int ret, status; + char *ptr; + + ret = sscanf( http_hdr->body, "%d ", &status); + if( ret!=1 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + + switch(status) { + case 210: + ptr = strstr(http_hdr->body, "max proto:"); + if( ptr==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + ret = sscanf(ptr, "max proto: %d", &max); + if( ret!=1 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + cddb_data->freedb_proto_level = max; + return 0; + default: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); + } + return -1; +} + +int +cddb_get_proto_level(cddb_data_t *cddb_data) { + return cddb_http_request("stat", cddb_proto_level_parse, cddb_data); +} + +int +cddb_freedb_sites_parse(HTTP_header_t *http_hdr, cddb_data_t *cddb_data) { + int ret, status; + + ret = sscanf( http_hdr->body, "%d ", &status); + if( ret!=1 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_ParseError); + return -1; + } + + switch(status) { + case 210: + // TODO: Parse the sites + ret = cddb_data->anonymous; // For gcc complaining about unused parameter. + return 0; + case 401: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_NoSitesInfoAvailable); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_FIXME, MSGTR_MPDEMUX_CDDB_UnhandledCode); + } + return -1; +} + +int +cddb_get_freedb_sites(cddb_data_t *cddb_data) { + return cddb_http_request("sites", cddb_freedb_sites_parse, cddb_data); +} + +void +cddb_create_hello(cddb_data_t *cddb_data) { + char host_name[51]; + char *user_name; + + if( cddb_data->anonymous ) { // Default is anonymous + /* Note from Eduardo Pérez Ureta <eperez@it.uc3m.es> : + * We don't send current user/host name in hello to prevent spam. + * Software that sends this is considered spyware + * that most people don't like. + */ + user_name = "anonymous"; + strcpy(host_name, "localhost"); + } else { + if( gethostname(host_name, 50)<0 ) { + strcpy(host_name, "localhost"); + } + user_name = getenv("LOGNAME"); + } + sprintf( cddb_data->cddb_hello, "&hello=%s+%s+%s+%s", user_name, host_name, "MPlayer", VERSION ); +} + +int +cddb_retrieve(cddb_data_t *cddb_data) { + char offsets[1024], command[1024]; + char *ptr; + unsigned int i, time_len; + int ret; + + ptr = offsets; + for( i=0; i<cddb_data->tracks ; i++ ) { + ptr += sprintf(ptr, "%d+", cdtoc[i].frame ); + if (ptr-offsets > sizeof offsets - 40) break; + } + ptr[0]=0; + time_len = (cdtoc[cddb_data->tracks].frame)/75; + + cddb_data->freedb_server = DEFAULT_FREEDB_SERVER; + cddb_data->freedb_proto_level = 1; + cddb_data->xmcd_file = NULL; + + cddb_create_hello(cddb_data); + if( cddb_get_proto_level(cddb_data)<0 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToGetProtocolLevel); + return -1; + } + + //cddb_get_freedb_sites(&cddb_data); + + sprintf(command, "cddb+query+%08lx+%d+%s%d", cddb_data->disc_id, cddb_data->tracks, offsets, time_len ); + ret = cddb_http_request(command, cddb_query_parse, cddb_data); + if( ret<0 ) return -1; + + if( cddb_data->cache_dir!=NULL ) { + free(cddb_data->cache_dir); + } + return 0; +} + +int +cddb_resolve(const char *dev, char **xmcd_file) { + char cddb_cache_dir[] = DEFAULT_CACHE_DIR; + char *home_dir = NULL; + cddb_data_t cddb_data; + + if (cdtoc_last_track <= 0) + { + cdtoc_last_track = read_toc(dev); + if (cdtoc_last_track < 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_MPDEMUX_CDDB_FailedToOpenDevice, dev); + return -1; + } + } + cddb_data.tracks = cdtoc_last_track; + cddb_data.disc_id = cddb_discid(cddb_data.tracks); + cddb_data.anonymous = 1; // Don't send user info by default + + // Check if there is a CD in the drive + // FIXME: That's not really a good way to check + if( cddb_data.disc_id==0 ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NoCDInDrive); + return -1; + } + + home_dir = getenv("HOME"); +#ifdef __MINGW32__ + if( home_dir==NULL ) home_dir = getenv("USERPROFILE"); + if( home_dir==NULL ) home_dir = getenv("HOMEPATH"); + // Last resort, store the cddb cache in the mplayer directory + if( home_dir==NULL ) home_dir = (char *)get_path(""); +#endif + if( home_dir==NULL ) { + cddb_data.cache_dir = NULL; + } else { + cddb_data.cache_dir = malloc(strlen(home_dir)+strlen(cddb_cache_dir)+1); + if( cddb_data.cache_dir==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); + return -1; + } + sprintf(cddb_data.cache_dir, "%s%s", home_dir, cddb_cache_dir ); + } + + // Check for a cached file + if( cddb_read_cache(&cddb_data)<0 ) { + // No Cache found + if( cddb_retrieve(&cddb_data)<0 ) { + return -1; + } + } + + if( cddb_data.xmcd_file!=NULL ) { +// printf("%s\n", cddb_data.xmcd_file ); + *xmcd_file = cddb_data.xmcd_file; + return 0; + } + + return -1; +} + +/******************************************************************************************************************* + * + * xmcd parser + * + *******************************************************************************************************************/ +char* +xmcd_parse_dtitle(cd_info_t *cd_info, char *line) { + char *ptr, *album; + ptr = strstr(line, "DTITLE="); + if( ptr!=NULL ) { + ptr += 7; + album = strstr(ptr, "/"); + if( album==NULL ) return NULL; + cd_info->album = malloc(strlen(album+2)+1); + if( cd_info->album==NULL ) { + return NULL; + } + strcpy( cd_info->album, album+2 ); + album--; + album[0] = '\0'; + cd_info->artist = malloc(strlen(ptr)+1); + if( cd_info->artist==NULL ) { + return NULL; + } + strcpy( cd_info->artist, ptr ); + } + return ptr; +} + +char* +xmcd_parse_dgenre(cd_info_t *cd_info, char *line) { + char *ptr; + ptr = strstr(line, "DGENRE="); + if( ptr!=NULL ) { + ptr += 7; + cd_info->genre = malloc(strlen(ptr)+1); + if( cd_info->genre==NULL ) { + return NULL; + } + strcpy( cd_info->genre, ptr ); + } + return ptr; +} + +char* +xmcd_parse_ttitle(cd_info_t *cd_info, char *line) { + unsigned int track_nb; + unsigned long sec, off; + char *ptr; + ptr = strstr(line, "TTITLE"); + if( ptr!=NULL ) { + ptr += 6; + // Here we point to the track number + track_nb = atoi(ptr); + ptr = strstr(ptr, "="); + if( ptr==NULL ) return NULL; + ptr++; + + sec = cdtoc[track_nb].frame; + off = cdtoc[track_nb+1].frame-sec+1; + + cd_info_add_track( cd_info, ptr, track_nb+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off ); + } + return ptr; +} + +cd_info_t* +cddb_parse_xmcd(char *xmcd_file) { + cd_info_t *cd_info = NULL; + int length, pos = 0; + char *ptr, *ptr2; + unsigned int audiolen; + if( xmcd_file==NULL ) return NULL; + + cd_info = cd_info_new(); + if( cd_info==NULL ) { + return NULL; + } + + length = strlen(xmcd_file); + ptr = xmcd_file; + while( ptr!=NULL && pos<length ) { + // Read a line + ptr2 = ptr; + while( ptr2[0]!='\0' && ptr2[0]!='\r' && ptr2[0]!='\n' ) ptr2++; + if( ptr2[0]=='\0' ) { + break; + } + ptr2[0] = '\0'; + // Ignore comments + if( ptr[0]!='#' ) { + // Search for the album title + if( xmcd_parse_dtitle(cd_info, ptr) ); + // Search for the genre + else if( xmcd_parse_dgenre(cd_info, ptr) ); + // Search for a track title + else if( xmcd_parse_ttitle(cd_info, ptr) ) audiolen++; // <-- audiolen++ to shut up gcc warning + } + if( ptr2[1]=='\n' ) ptr2++; + pos = (ptr2+1)-ptr; + ptr = ptr2+1; + } + + audiolen = cdtoc[cd_info->nb_tracks].frame-cdtoc[0].frame; + cd_info->min = (unsigned int)(audiolen/(60*75)); + cd_info->sec = (unsigned int)((audiolen/75)%60); + cd_info->msec = (unsigned int)(audiolen%75); + + return cd_info; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cdinfo.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,137 @@ +/* + * CD Info + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2002, MPlayer team. +*/ + +#include "config.h" + +#if defined(HAVE_CDDA) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "mp_msg.h" +#include "help_mp.h" +#include "cdd.h" + +/******************************************************************************************************************* + * + * xmcd parser, cd info list + * + *******************************************************************************************************************/ + +cd_info_t* +cd_info_new() { + cd_info_t *cd_info = NULL; + + cd_info = malloc(sizeof(cd_info_t)); + if( cd_info==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); + return NULL; + } + + memset(cd_info, 0, sizeof(cd_info_t)); + + return cd_info; +} + +void +cd_info_free(cd_info_t *cd_info) { + cd_track_t *cd_track, *cd_track_next; + if( cd_info==NULL ) return; + if( cd_info->artist!=NULL ) free(cd_info->artist); + if( cd_info->album!=NULL ) free(cd_info->album); + if( cd_info->genre!=NULL ) free(cd_info->genre); + + cd_track_next = cd_info->first; + while( cd_track_next!=NULL ) { + cd_track = cd_track_next; + cd_track_next = cd_track->next; + if( cd_track->name!=NULL ) free(cd_track->name); + free(cd_track); + } +} + +cd_track_t* +cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length) { + cd_track_t *cd_track; + + if( cd_info==NULL || track_name==NULL ) return NULL; + + cd_track = malloc(sizeof(cd_track_t)); + if( cd_track==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); + return NULL; + } + memset(cd_track, 0, sizeof(cd_track_t)); + + cd_track->name = malloc(strlen(track_name)+1); + if( cd_track->name==NULL ) { + mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MemAllocFailed); + free(cd_track); + return NULL; + } + strcpy(cd_track->name, track_name); + cd_track->track_nb = track_nb; + cd_track->min = min; + cd_track->sec = sec; + cd_track->msec = msec; + cd_track->frame_begin = frame_begin; + cd_track->frame_length = frame_length; + + if( cd_info->first==NULL ) { + cd_info->first = cd_track; + } + if( cd_info->last!=NULL ) { + cd_info->last->next = cd_track; + } + + cd_track->prev = cd_info->last; + + cd_info->last = cd_track; + cd_info->current = cd_track; + + cd_info->nb_tracks++; + + return cd_track; +} + +cd_track_t* +cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb) { + cd_track_t *cd_track=NULL; + + if( cd_info==NULL ) return NULL; + + cd_track = cd_info->first; + while( cd_track!=NULL ) { + if( cd_track->track_nb==track_nb ) { + return cd_track; + } + cd_track = cd_track->next; + } + return NULL; +} + +void +cd_info_debug(cd_info_t *cd_info) { + cd_track_t *current_track; + printf("================ CD INFO === start =========\n"); + if( cd_info==NULL ) { + printf("cd_info is NULL\n"); + return; + } + printf(" artist=[%s]\n", cd_info->artist); + printf(" album=[%s]\n", cd_info->album); + printf(" genre=[%s]\n", cd_info->genre); + printf(" nb_tracks=%d\n", cd_info->nb_tracks); + printf(" length= %2d:%02d.%02d\n", cd_info->min, cd_info->sec, cd_info->msec); + current_track = cd_info->first; + while( current_track!=NULL ) { + printf(" #%2d %2d:%02d.%02d @ %7ld\t[%s] \n", current_track->track_nb, current_track->min, current_track->sec, current_track->msec, current_track->frame_begin, current_track->name); + current_track = current_track->next; + } + printf("================ CD INFO === end =========\n"); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cookies.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,278 @@ +/* + * HTTP Cookies + * Reads Netscape and Mozilla cookies.txt files + * + * by Dave Lambley <mplayer@davel.me.uk> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <inttypes.h> + +#include "cookies.h" +#include "http.h" +#include "mp_msg.h" + +#define MAX_COOKIES 20 + +char *cookies_file = NULL; + +typedef struct cookie_list_type { + char *name; + char *value; + char *domain; + char *path; + + int secure; + + struct cookie_list_type *next; +} cookie_list_t; + +/* Pointer to the linked list of cookies */ +static struct cookie_list_type *cookie_list = NULL; + + +/* Like strdup, but stops at anything <31. */ +static char *col_dup(const char *src) +{ + char *dst; + int length = 0; + + while (src[length] > 31) + length++; + + dst = malloc(length + 1); + strncpy(dst, src, length); + dst[length] = 0; + + return dst; +} + +static int right_hand_strcmp(const char *cookie_domain, const char *url_domain) +{ + int c_l; + int u_l; + + c_l = strlen(cookie_domain); + u_l = strlen(url_domain); + + if (c_l > u_l) + return -1; + return strcmp(cookie_domain, url_domain + u_l - c_l); +} + +static int left_hand_strcmp(const char *cookie_path, const char *url_path) +{ + return strncmp(cookie_path, url_path, strlen(cookie_path)); +} + +/* Finds the start of all the columns */ +static int parse_line(char **ptr, char *cols[6]) +{ + int col; + cols[0] = *ptr; + + for (col = 1; col < 7; col++) { + for (; (**ptr) > 31; (*ptr)++); + if (**ptr == 0) + return 0; + (*ptr)++; + if ((*ptr)[-1] != 9) + return 0; + cols[col] = (*ptr); + } + + return 1; +} + +/* Loads a file into RAM */ +static char *load_file(const char *filename, off_t * length) +{ + int fd; + char *buffer; + + mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + mp_msg(MSGT_NETWORK, MSGL_V, "Could not open"); + return NULL; + } + + *length = lseek(fd, 0, SEEK_END); + + if (*length < 0) { + mp_msg(MSGT_NETWORK, MSGL_V, "Could not find EOF"); + return NULL; + } + + if (*length > SIZE_MAX - 1) { + mp_msg(MSGT_NETWORK, MSGL_V, "File too big, could not malloc."); + return NULL; + } + + lseek(fd, SEEK_SET, 0); + + if (!(buffer = malloc(*length + 1))) { + mp_msg(MSGT_NETWORK, MSGL_V, "Could not malloc."); + return NULL; + } + + if (read(fd, buffer, *length) != *length) { + mp_msg(MSGT_NETWORK, MSGL_V, "Read is behaving funny."); + return NULL; + } + close(fd); + buffer[*length] = 0; + + return buffer; +} + +/* Loads a cookies.txt file into a linked list. */ +static struct cookie_list_type *load_cookies_from(const char *filename, + struct cookie_list_type + *list) +{ + char *ptr; + off_t length; + + mp_msg(MSGT_NETWORK, MSGL_V, "Loading cookie file: %s\n", filename); + + ptr = load_file(filename, &length); + if (!ptr) + return list; + + while (*ptr > 0) { + char *cols[7]; + if (parse_line(&ptr, cols)) { + struct cookie_list_type *new; + new = malloc(sizeof(cookie_list_t)); + new->name = col_dup(cols[5]); + new->value = col_dup(cols[6]); + new->path = col_dup(cols[2]); + new->domain = col_dup(cols[0]); + new->secure = (*(cols[3]) == 't') || (*(cols[3]) == 'T'); + new->next = list; + list = new; + } + } + return list; +} + +/* Attempt to load cookies.txt from various locations. Returns a pointer to the linked list contain the cookies. */ +static struct cookie_list_type *load_cookies(void) +{ + DIR *dir; + struct dirent *ent; + struct cookie_list_type *list = NULL; + char *buf; + + char *homedir; + + if (cookies_file) + return load_cookies_from(cookies_file, list); + + homedir = getenv("HOME"); + if (!homedir) + return list; + + + buf = malloc(strlen(homedir) + sizeof("/.mozilla/default") + 1); + sprintf(buf, "%s/.mozilla/default", homedir); + dir = opendir(buf); + free(buf); + + if (dir) { + while ((ent = readdir(dir)) != NULL) { + if ((ent->d_name)[0] != '.') { + buf = malloc(strlen(getenv("HOME")) + + sizeof("/.mozilla/default/") + + strlen(ent->d_name) + sizeof("cookies.txt") + 1); + sprintf(buf, "%s/.mozilla/default/%s/cookies.txt", + getenv("HOME"), ent->d_name); + list = load_cookies_from(buf, list); + free(buf); + } + } + closedir(dir); + } + + buf = malloc(strlen(homedir) + sizeof("/.netscape/cookies.txt") + 1); + sprintf(buf, "%s/.netscape/cookies.txt", homedir); + list = load_cookies_from(buf, list); + free(buf); + + return list; +} + +/* Take an HTTP_header_t, and insert the correct headers. The cookie files are read if necessary. */ +void +cookies_set(HTTP_header_t * http_hdr, const char *domain, const char *url) +{ + int found_cookies = 0; + struct cookie_list_type *cookies[MAX_COOKIES]; + struct cookie_list_type *list, *start; + int i; + char *path; + char *buf; + + path = strchr(url, '/'); + if (!path) + path = ""; + + if (!cookie_list) + cookie_list = load_cookies(); + + + list = start = cookie_list; + + /* Find which cookies we want, removing duplicates. Cookies with the longest domain, then longest path take priority */ + while (list) { + /* Check the cookie domain and path. Also, we never send "secure" cookies. These should only be sent over HTTPS. */ + if ((right_hand_strcmp(list->domain, domain) == 0) + && (left_hand_strcmp(list->path, path) == 0) && !list->secure) { + int replacing = 0; + for (i = 0; i < found_cookies; i++) { + if (strcmp(list->name, cookies[i]->name) == 0) { + replacing = 0; + if (strlen(list->domain) <= strlen(cookies[i]->domain)) { + cookies[i] = list; + } else if (strlen(list->path) <= strlen(cookies[i]->path)) { + cookies[i] = list; + } + } + } + if (found_cookies > MAX_COOKIES) { + /* Cookie jar overflow! */ + break; + } + if (!replacing) + cookies[found_cookies++] = list; + } + list = list->next; + } + + + buf = strdup("Cookie:"); + + for (i = 0; i < found_cookies; i++) { + char *nbuf; + + nbuf = malloc(strlen(buf) + strlen(" ") + strlen(cookies[i]->name) + + strlen("=") + strlen(cookies[i]->value) + strlen(";") + 1); + sprintf(nbuf, "%s %s=%s;", buf, cookies[i]->name, + cookies[i]->value); + free(buf); + buf = nbuf; + } + + if (found_cookies) + http_set_field(http_hdr, buf); + else + free(buf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cookies.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,16 @@ +/* + * HTTP Cookies + * Reads Netscape and Mozilla cookies.txt files + * + * by Dave Lambley <mplayer@davel.me.uk> + */ + +#ifndef __COOKIES_H +#define __COOKIES_H + +#include "http.h" + +extern void cookies_set(HTTP_header_t * http_hdr, const char *hostname, + const char *url); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cue_read.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,604 @@ +//=================== VideoCD BinCue ========================== + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "stream.h" + +#include "cue_read.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +#define byte unsigned char +#define SIZERAW 2352 +#define SIZEISO_MODE1 2048 +#define SIZEISO_MODE2_RAW 2352 +#define SIZEISO_MODE2_FORM1 2048 +#define SIZEISO_MODE2_FORM2 2336 +#define AUDIO 0 +#define MODE1 1 +#define MODE2 2 +#define MODE1_2352 10 +#define MODE2_2352 20 +#define MODE1_2048 30 +#define MODE2_2336 40 +#define UNKNOWN -1 + +static struct stream_priv_s { + char* filename; +} stream_priv_dflts = { + NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + { "string", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "cue", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +static FILE* fd_cue; +static int fd_bin = 0; + +static char bin_filename[256]; + +static char cue_filename[256]; +static char bincue_path[256]; + + +typedef struct track +{ + unsigned short mode; + unsigned short minute; + unsigned short second; + unsigned short frame; + + /* (min*60 + sec) * 75 + fps */ + + unsigned long start_sector; + + /* = the sizes in bytes off all tracks bevor this one */ + /* its needed if there are mode1 tracks befor the mpeg tracks */ + unsigned long start_offset; + + /* unsigned char num[3]; */ +} tTrack; + +/* max 99 tracks on a cd */ +static tTrack tracks[100]; + +static struct cue_track_pos { + int track; + unsigned short mode; + unsigned short minute; + unsigned short second; + unsigned short frame; +} cue_current_pos; + +/* number of tracks on the cd */ +static int nTracks = 0; + +/* presumes Line is preloaded with the "current" line of the file */ +static int cue_getTrackinfo(char *Line, tTrack *track) +{ + char inum[3]; + char min; + char sec; + char fps; + int already_set = 0; + + /* Get the 'mode' */ + if (strncmp(&Line[2], "TRACK ", 6)==0) + { +/* strncpy(track->num, &Line[8], 2); track->num[2] = '\0'; */ + + track->mode = UNKNOWN; + if(strncmp(&Line[11], "AUDIO", 5)==0) track->mode = AUDIO; + if(strncmp(&Line[11], "MODE1/2352", 10)==0) track->mode = MODE1_2352; + if(strncmp(&Line[11], "MODE1/2048", 10)==0) track->mode = MODE1_2048; + if(strncmp(&Line[11], "MODE2/2352", 10)==0) track->mode = MODE2_2352; + if(strncmp(&Line[11], "MODE2/2336", 10)==0) track->mode = MODE2_2336; + } + else return(1); + + /* Get the track indexes */ + while(1) { + if(! fgets( Line, 256, fd_cue ) ) { break;} + + if (strncmp(&Line[2], "TRACK ", 6)==0) + { + /* next track starting */ + break; + } + + /* Track 0 or 1, take the first an get fill the values*/ + if (strncmp(&Line[4], "INDEX ", 6)==0) + { + /* check stuff here so if the answer is false the else stuff below won't be executed */ + strncpy(inum, &Line[10], 2); inum[2] = '\0'; + if ((already_set == 0) && + ((strcmp(inum, "00")==0) || (strcmp(inum, "01")==0))) + { + already_set = 1; + + min = ((Line[13]-'0')<<4) | (Line[14]-'0'); + sec = ((Line[16]-'0')<<4) | (Line[17]-'0'); + fps = ((Line[19]-'0')<<4) | (Line[20]-'0'); + + track->minute = (((min>>4)*10) + (min&0xf)); + track->second = (((sec>>4)*10) + (sec&0xf)); + track->frame = (((fps>>4)*10) + (fps&0xf)); + } + } + else if (strncmp(&Line[4], "PREGAP ", 7)==0) { ; /* ignore */ } + else if (strncmp(&Line[4], "FLAGS ", 6)==0) { ; /* ignore */ } + else mp_msg (MSGT_OPEN,MSGL_INFO, + MSGTR_MPDEMUX_CUEREAD_UnexpectedCuefileLine, Line); + } + return(0); +} + + + +/* FIXME: the string operations ( strcpy,strcat ) below depend + * on the arrays to have the same size, thus we need to make + * sure the sizes are in sync. + */ +static int cue_find_bin (char *firstline) { + int i,j; + char s[256]; + char t[256]; + + /* get the filename out of that */ + /* 12345 6 */ + mp_msg (MSGT_OPEN,MSGL_INFO, "[bincue] cue_find_bin(%s)\n", firstline); + if (strncmp(firstline, "FILE \"",6)==0) + { + i = 0; + j = 0; + while ( firstline[6 + i] != '"') + { + bin_filename[j] = firstline[6 + i]; + + /* if I found a path info, than delete all bevor it */ + switch (bin_filename[j]) + { + case '\\': + j = 0; + break; + + case '/': + j = 0; + break; + + default: + j++; + } + i++; + } + bin_filename[j+1] = '\0'; + + } + + /* now try to open that file, without path */ + fd_bin = open (bin_filename, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, + bin_filename); + + /* now try to find it with the path of the cue file */ + snprintf(s,sizeof( s ),"%s/%s",bincue_path,bin_filename); + fd_bin = open (s, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, + MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); + /* now I would say the whole filename is shit, build our own */ + strncpy(s, cue_filename, strlen(cue_filename) - 3 ); + s[strlen(cue_filename) - 3] = '\0'; + strcat(s, "bin"); + fd_bin = open (s, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, + MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); + + /* ok try it with path */ + snprintf(t, sizeof( t ), "%s/%s", bincue_path, s); + fd_bin = open (t, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, + MSGTR_MPDEMUX_CUEREAD_BinFilenameTested,t); + /* now I would say the whole filename is shit, build our own */ + strncpy(s, cue_filename, strlen(cue_filename) - 3 ); + s[strlen(cue_filename) - 3] = '\0'; + strcat(s, "img"); + fd_bin = open (s, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, + MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); + /* ok try it with path */ + snprintf(t, sizeof( t ), "%s/%s", bincue_path, s); + fd_bin = open (t, O_RDONLY); + if (fd_bin == -1) + { + mp_msg(MSGT_OPEN,MSGL_STATUS, + MSGTR_MPDEMUX_CUEREAD_BinFilenameTested, s); + + /* I'll give up */ + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_CannotFindBinFile); + return -1; + } + } + } else strcpy(bin_filename, t); + + } else strcpy(bin_filename, s); + + } else strcpy(bin_filename, s); + + } + + mp_msg(MSGT_OPEN,MSGL_INFO, + MSGTR_MPDEMUX_CUEREAD_UsingBinFile, bin_filename); + return 0; +} + +static inline int cue_msf_2_sector(int minute, int second, int frame) { + return frame + (second + minute * 60 ) * 75; +} + +static inline int cue_get_msf(void) { + return cue_msf_2_sector (cue_current_pos.minute, + cue_current_pos.second, + cue_current_pos.frame); +} + +static inline void cue_set_msf(unsigned int sect){ + cue_current_pos.frame=sect%75; + sect=sect/75; + cue_current_pos.second=sect%60; + sect=sect/60; + cue_current_pos.minute=sect; +} + +static inline int cue_mode_2_sector_size(int mode) +{ + switch (mode) + { + case AUDIO: return AUDIO; + case MODE1_2352: return SIZERAW; + case MODE1_2048: return SIZEISO_MODE1; + case MODE2_2352: return SIZEISO_MODE2_RAW; + case MODE2_2336: return SIZEISO_MODE2_FORM2; + + default: + mp_msg(MSGT_OPEN,MSGL_FATAL, + MSGTR_MPDEMUX_CUEREAD_UnknownModeForBinfile); + abort(); + } + +} + + +static int cue_read_cue (char *in_cue_filename) +{ + struct stat filestat; + char sLine[256]; + unsigned int sect; + char *s,*t; + int i; + + /* we have no tracks at the beginning */ + nTracks = 0; + + fd_bin = 0; + + /* split the filename into a path and filename part */ + s = strdup(in_cue_filename); + t = strrchr(s, '/'); + if (t == (char *)NULL) + t = "."; + else { + *t = '\0'; + t = s; + if (*t == '\0') + strcpy(t, "/"); + } + + strlcpy(bincue_path,t,sizeof( bincue_path )); + mp_msg(MSGT_OPEN,MSGL_V,"dirname: %s, cuepath: %s\n", t, bincue_path); + + /* no path at all? */ + if (strcmp(bincue_path, ".") == 0) { + mp_msg(MSGT_OPEN,MSGL_V,"bincue_path: %s\n", bincue_path); + strlcpy(cue_filename,in_cue_filename,sizeof( cue_filename )); + } else { + strlcpy(cue_filename,in_cue_filename + strlen(bincue_path) + 1, + sizeof( cue_filename )); + } + + + + /* open the cue file */ + fd_cue = fopen (in_cue_filename, "r"); + if (fd_cue == NULL) + { + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_CannotOpenCueFile, in_cue_filename); + return -1; + } + + /* read the first line and hand it to find_bin, which will + test more than one possible name of the file */ + + if(! fgets( sLine, 256, fd_cue ) ) + { + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); + fclose (fd_cue); + return -1; + } + + if (cue_find_bin(sLine)) { + fclose (fd_cue); + return -1; + } + + + /* now build the track list */ + /* red the next line and call our track finder */ + if(! fgets( sLine, 256, fd_cue ) ) + { + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); + fclose (fd_cue); + return -1; + } + + while(!feof(fd_cue)) + { + if (cue_getTrackinfo(sLine, &tracks[nTracks++]) != 0) + { + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_ErrReadingFromCueFile, in_cue_filename); + fclose (fd_cue); + return -1; + } + } + + /* make a fake track with stands for the Lead out */ + if (fstat (fd_bin, &filestat) == -1) { + mp_msg(MSGT_OPEN,MSGL_ERR, + MSGTR_MPDEMUX_CUEREAD_ErrGettingBinFileSize); + fclose (fd_cue); + return -1; + } + + sect = filestat.st_size / 2352; + + tracks[nTracks].frame = sect%75; + sect=sect/75; + tracks[nTracks].second = sect%60; + sect=sect/60; + tracks[nTracks].minute = sect; + + + /* let's calculate the start sectors and offsets */ + for(i = 0; i <= nTracks; i++) + { + tracks[i].start_sector = cue_msf_2_sector(tracks[i].minute, + tracks[nTracks].second, + tracks[nTracks].frame); + + /* if we're the first track we don't need to offset of the one befor */ + if (i == 0) + { + /* was always 0 on my svcds, but who knows */ + tracks[0].start_offset = tracks[0].start_sector * + cue_mode_2_sector_size(tracks[0].mode); + } else + { + tracks[i].start_offset = tracks[i-1].start_offset + + (tracks[i].start_sector - tracks[i-1].start_sector) * + cue_mode_2_sector_size(tracks[i-1].mode); + } + } + + fclose (fd_cue); + + return fd_bin; +} + + + + +static int cue_read_toc_entry(void) { + + int track = cue_current_pos.track - 1; + + /* check if its a valid track, if not return -1 */ + if (track >= nTracks) + return -1; + + + switch (tracks[track].mode) + { + case AUDIO: + cue_current_pos.mode = AUDIO; + break; + case MODE1_2352: + cue_current_pos.mode = MODE1; + break; + case MODE1_2048: + cue_current_pos.mode = MODE1; + break; + default: /* MODE2_2352 and MODE2_2336 */ + cue_current_pos.mode = MODE2; + } + cue_current_pos.minute = tracks[track].minute; + cue_current_pos.second = tracks[track].second; + cue_current_pos.frame = tracks[track].frame; + + return 0; +} + +static int cue_vcd_seek_to_track (int track){ + cue_current_pos.track = track; + + if (cue_read_toc_entry ()) + return -1; + + return VCD_SECTOR_DATA * cue_get_msf(); +} + +static int cue_vcd_get_track_end (int track){ + cue_current_pos.frame = tracks[track].frame; + cue_current_pos.second = tracks[track].second; + cue_current_pos.minute = tracks[track].minute; + + return VCD_SECTOR_DATA * cue_get_msf(); +} + +static void cue_vcd_read_toc(void){ + int i; + for (i = 0; i < nTracks; ++i) { + + mp_msg(MSGT_OPEN,MSGL_INFO, + MSGTR_MPDEMUX_CUEREAD_InfoTrackFormat, + i+1, + tracks[i].mode, + tracks[i].minute, + tracks[i].second, + tracks[i].frame + ); + } +} + +static int cue_vcd_read(stream_t *stream, char *mem, int size) { + unsigned long position; + int track = cue_current_pos.track - 1; + + position = tracks[track].start_offset + + (cue_msf_2_sector(cue_current_pos.minute, + cue_current_pos.second, + cue_current_pos.frame) - + tracks[track].start_sector) + * cue_mode_2_sector_size(tracks[track].mode); + + + if(position >= tracks[track+1].start_offset) + return 0; + + if(lseek(fd_bin, position+VCD_SECTOR_OFFS, SEEK_SET) == -1) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_MPDEMUX_CUEREAD_UnexpectedBinFileEOF); + return 0; + } + + if(read(fd_bin, mem, VCD_SECTOR_DATA) != VCD_SECTOR_DATA) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_MPDEMUX_CUEREAD_CannotReadNBytesOfPayload, VCD_SECTOR_DATA); + return 0; + } + + cue_current_pos.frame++; + if (cue_current_pos.frame==75){ + cue_current_pos.frame=0; + cue_current_pos.second++; + if (cue_current_pos.second==60){ + cue_current_pos.second=0; + cue_current_pos.minute++; + } + } + + return VCD_SECTOR_DATA; +} + +static int seek(stream_t *s,off_t newpos) { + s->pos=newpos; + cue_set_msf(s->pos/VCD_SECTOR_DATA); + return 1; +} + + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + struct stream_priv_s* p = (struct stream_priv_s*)opts; + int ret,ret2,f,track = 0; + char *filename = NULL, *colon = NULL; + + if(mode != STREAM_READ || !p->filename) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + filename = strdup(p->filename); + if(!filename) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + colon = strstr(filename, ":"); + if(colon) { + if(strlen(colon)>1) + track = atoi(colon+1); + *colon = 0; + } + if(!track) + track = 1; + + f = cue_read_cue(filename); + if(f < 0) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + cue_vcd_read_toc(); + ret2=cue_vcd_get_track_end(track); + ret=cue_vcd_seek_to_track(track); + if(ret<0){ + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n"); + return STREAM_UNSUPORTED; + } + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CUEREAD_CueStreamInfo_FilenameTrackTracksavail, filename, track, ret, ret2); + + stream->fd = f; + stream->type = STREAMTYPE_VCDBINCUE; + stream->sector_size = VCD_SECTOR_DATA; + stream->flags = STREAM_READ | STREAM_SEEK_FW; + stream->start_pos = ret; + stream->end_pos = ret2; + stream->fill_buffer = cue_vcd_read; + stream->seek = seek; + + free(filename); + m_struct_free(&stream_opts,opts); + return STREAM_OK; +} + +stream_info_t stream_info_cue = { + "CUE track", + "cue", + "Albeu", + "based on the code from ???", + open_s, + { "cue", NULL }, + &stream_opts, + 1 // Urls are an option string +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/cue_read.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,7 @@ + +//int cue_read_cue (char *in_cue_filename); +//int cue_vcd_seek_to_track (int track); +//int cue_vcd_get_track_end (int track); +//void cue_vcd_read_toc (); +//int cue_vcd_read(char *mem); +//inline void cue_set_msf(unsigned int sect);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/dvb_tune.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,791 @@ +/* dvbtune - tune.c + + Copyright (C) Dave Chapman 2001,2002 + + Modified for use with MPlayer, for details see the changelog at + http://svn.mplayerhq.hu/mplayer/trunk/ + $Id$ + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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. + Or, point your browser to http://www.gnu.org/copyleft/gpl.html + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include <sys/poll.h> +#include <unistd.h> +#include <fcntl.h> +#include <error.h> +#include <time.h> +#include <errno.h> +#include "config.h" + +#ifdef HAVE_DVB_HEAD + #include <linux/dvb/dmx.h> + #include <linux/dvb/frontend.h> + char* dvb_frontenddev[4]={"/dev/dvb/adapter0/frontend0","/dev/dvb/adapter1/frontend0","/dev/dvb/adapter2/frontend0","/dev/dvb/adapter3/frontend0"}; + char* dvb_dvrdev[4]={"/dev/dvb/adapter0/dvr0","/dev/dvb/adapter1/dvr0","/dev/dvb/adapter2/dvr0","/dev/dvb/adapter3/dvr0"}; + char* dvb_demuxdev[4]={"/dev/dvb/adapter0/demux0","/dev/dvb/adapter1/demux0","/dev/dvb/adapter2/demux0","/dev/dvb/adapter3/demux0"}; + static char* dvb_secdev[4]={"","","",""}; //UNUSED, ONLY FOR UNIFORMITY +#else + #include <ost/dmx.h> + #include <ost/sec.h> + #include <ost/frontend.h> + char* dvb_frontenddev[4]={"/dev/ost/frontend0","/dev/ost/frontend1","/dev/ost/frontend2","/dev/ost/frontend3"}; + char* dvb_dvrdev[4]={"/dev/ost/dvr0","/dev/ost/dvr1","/dev/ost/dvr2","/dev/ost/dvr3"}; + static char* dvb_secdev[4]={"/dev/ost/sec0","/dev/ost/sec1","/dev/ost/sec2","/dev/ost/sec3"}; + char* dvb_demuxdev[4]={"/dev/ost/demux0","/dev/ost/demux1","/dev/ost/demux2","/dev/ost/demux3"}; +#endif + +#include "dvbin.h" +#include "mp_msg.h" + + + +int dvb_get_tuner_type(int fe_fd) +{ +#ifdef HAVE_DVB_HEAD + struct dvb_frontend_info fe_info; +#else + FrontendInfo fe_info; +#endif + + int res; + + res = ioctl(fe_fd, FE_GET_INFO, &fe_info); + if(res < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); + return 0; + } + + switch(fe_info.type) + { + case FE_OFDM: + mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-T\n"); + return TUNER_TER; + + case FE_QPSK: + mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-S\n"); + return TUNER_SAT; + + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-C\n"); + return TUNER_CBL; + +#ifdef DVB_ATSC + case FE_ATSC: + mp_msg(MSGT_DEMUX, MSGL_V, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); + return TUNER_ATSC; +#endif + default: + mp_msg(MSGT_DEMUX, MSGL_ERR, "UNKNOWN TUNER TYPE\n"); + return 0; + } + +} + +int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype); + +int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt, int *pids) +{ + int i; + + priv->fe_fd = open(dvb_frontenddev[n], O_RDWR | O_NONBLOCK); + if(priv->fe_fd < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING FRONTEND DEVICE %s: ERRNO %d\n", dvb_frontenddev[n], errno); + return 0; + } +#ifdef HAVE_DVB_HEAD + priv->sec_fd=0; +#else + priv->sec_fd = open(dvb_secdev[n], O_RDWR); + if(priv->sec_fd < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING SEC DEVICE %s: ERRNO %d\n", dvb_secdev[n], errno); + close(priv->fe_fd); + return 0; + } +#endif + priv->demux_fds_cnt = 0; + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_OPEN_DEVICES(%d)\n", demux_cnt); + for(i = 0; i < demux_cnt; i++) + { + priv->demux_fds[i] = open(dvb_demuxdev[n], O_RDWR | O_NONBLOCK); + if(priv->demux_fds[i] < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DEMUX 0: %d\n", errno); + return 0; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "OPEN(%d), file %s: FD=%d, CNT=%d\n", i, dvb_demuxdev[n], priv->demux_fds[i], priv->demux_fds_cnt); + priv->demux_fds_cnt++; + } + } + + + priv->dvr_fd = open(dvb_dvrdev[n], O_RDONLY| O_NONBLOCK); + if(priv->dvr_fd < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DVR DEVICE %s: %d\n", dvb_dvrdev[n], errno); + return 0; + } + + return 1; +} + + +int dvb_fix_demuxes(dvb_priv_t *priv, int cnt, int *pids) +{ + int i; + + mp_msg(MSGT_DEMUX, MSGL_V, "FIX %d -> %d\n", priv->demux_fds_cnt, cnt); + if(priv->demux_fds_cnt >= cnt) + { + for(i = priv->demux_fds_cnt-1; i >= cnt; i--) + { + mp_msg(MSGT_DEMUX, MSGL_V, "FIX, CLOSE fd(%d): %d\n", i, priv->demux_fds[i]); + close(priv->demux_fds[i]); + } + priv->demux_fds_cnt = cnt; + } + else if(priv->demux_fds_cnt < cnt) + { + for(i = priv->demux_fds_cnt; i < cnt; i++) + { + priv->demux_fds[i] = open(dvb_demuxdev[priv->card], O_RDWR | O_NONBLOCK); + mp_msg(MSGT_DEMUX, MSGL_V, "FIX, OPEN fd(%d): %d\n", i, priv->demux_fds[i]); + if(priv->demux_fds[i] < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DEMUX 0: %d\n", errno); + return 0; + } + else + priv->demux_fds_cnt++; + } + } + + return 1; +} + +int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype) +{ + int i; + struct dmx_pes_filter_params pesFilterParams; + + pesFilterParams.pid = pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; +#ifdef HAVE_DVB_HEAD + pesFilterParams.pes_type = pestype; +#else + pesFilterParams.pesType = pestype; +#endif + + pesFilterParams.flags = DMX_IMMEDIATE_START; + + errno = 0; + if ((i = ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams)) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR IN SETTING DMX_FILTER %i for fd %d: ERRNO: %d", pid, fd, errno); + return 0; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SET PES FILTER ON PID %d to fd %d, RESULT: %d, ERRNO: %d\n", pid, fd, i, errno); + return 1; +} + + +int dvb_demux_stop(int fd) +{ + int i; + i = ioctl(fd, DMX_STOP); + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "STOPPING FD: %d, RESULT: %d\n", fd, i); + + return (i==0); +} + + +int dvb_demux_start(int fd) +{ + int i; + i = ioctl(fd, DMX_START); + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "STARTING FD: %d, RESULT: %d\n", fd, i); + + return (i==0); +} + + +static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, + fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, + fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, + fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int tmout); + + +int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, + fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, + fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate, + fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout) +{ + int ris; + + mp_msg(MSGT_DEMUX, MSGL_INFO, "dvb_tune Freq: %lu\n", (long unsigned int) freq); + + ris = tune_it(priv->fe_fd, priv->sec_fd, freq, srate, pol, tone, specInv, diseqc, modulation, HP_CodeRate, TransmissionMode, guardInterval, bandWidth, LP_CodeRate, hier, timeout); + + if(ris != 0) + mp_msg(MSGT_DEMUX, MSGL_INFO, "dvb_tune, TUNING FAILED\n"); + + return (ris == 0); +} + + +#ifndef HAVE_DVB_HEAD +static int SecGetStatus (int fd, struct secStatus *state) +{ + if(ioctl(fd, SEC_GET_STATUS, state) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, ("SEC GET STATUS: ")); + return -1; + } + + switch (state->busMode) + { + case SEC_BUS_IDLE: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: IDLE (%d)\n",state->busMode); + break; + case SEC_BUS_BUSY: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: BUSY (%d)\n",state->busMode); + break; + case SEC_BUS_OFF: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OFF (%d)\n",state->busMode); + break; + case SEC_BUS_OVERLOAD: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OVERLOAD (%d)\n",state->busMode); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: unknown (%d)\n",state->busMode); + break; + } + + switch (state->selVolt) + { + case SEC_VOLTAGE_OFF: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: OFF (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_LT: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: LT (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_13: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_13_5: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13.5 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_18: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_18_5: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18.5 (%d)\n",state->selVolt); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: unknown (%d)\n",state->selVolt); + break; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SEC CONT TONE: %s\n", (state->contTone == SEC_TONE_ON ? "ON" : "OFF")); + return 0; +} + +#endif + +static void print_status(fe_status_t festatus) +{ + mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); + if (festatus & FE_HAS_SIGNAL) mp_msg(MSGT_DEMUX, MSGL_V," FE_HAS_SIGNAL"); +#ifdef HAVE_DVB_HEAD + if (festatus & FE_TIMEDOUT) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TIMEDOUT"); +#else + if (festatus & FE_HAS_POWER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_POWER"); + if (festatus & FE_SPECTRUM_INV) mp_msg(MSGT_DEMUX, MSGL_V, " FE_SPECTRUM_INV"); + if (festatus & FE_TUNER_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TUNER_HAS_LOCK"); +#endif + if (festatus & FE_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_LOCK"); + if (festatus & FE_HAS_CARRIER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_CARRIER"); + if (festatus & FE_HAS_VITERBI) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_VITERBI"); + if (festatus & FE_HAS_SYNC) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_SYNC"); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); +} + + +#ifdef HAVE_DVB_HEAD +static int check_status(int fd_frontend,struct dvb_frontend_parameters* feparams, int tuner_type, uint32_t base, int tmout) +{ + int32_t strength; + fe_status_t festatus; + struct pollfd pfd[1]; + int ok=0, locks=0; + time_t tm1, tm2; + + if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); + return -1; + } + + pfd[0].fd = fd_frontend; + pfd[0].events = POLLPRI; + + mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend status\n"); + tm1 = tm2 = time((time_t*) NULL); + while(!ok) + { + festatus = 0; + if(poll(pfd,1,tmout*1000) > 0) + { + if (pfd[0].revents & POLLPRI) + { + if(ioctl(fd_frontend, FE_READ_STATUS, &festatus) >= 0) + if(festatus & FE_HAS_LOCK) + locks++; + } + } + usleep(10000); + tm2 = time((time_t*) NULL); + if((festatus & FE_TIMEDOUT) || (locks >= 2) || (tm2 - tm1 >= tmout)) + ok = 1; + } + + if(festatus & FE_HAS_LOCK) + { + if(ioctl(fd_frontend,FE_GET_FRONTEND,feparams) >= 0) + { + switch(tuner_type) + { + case FE_OFDM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); + break; + case FE_QPSK: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((feparams->frequency)+base)); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",feparams->u.qpsk.fec_inner); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + break; + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",feparams->u.qpsk.symbol_rate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",feparams->u.qpsk.fec_inner); + break; +#ifdef DVB_ATSC + case FE_ATSC: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",feparams->frequency); + mp_msg(MSGT_DEMUX, MSGL_V, " Modulation: %d\n",feparams->u.vsb.modulation); + break; +#endif + default: + break; + } + } + + strength=0; + if(ioctl(fd_frontend,FE_READ_BER,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); + + strength=0; + if(ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); + + strength=0; + if(ioctl(fd_frontend,FE_READ_SNR,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); + + strength=0; + if(ioctl(fd_frontend,FE_READ_UNCORRECTED_BLOCKS,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "UNC: %d\n",strength); + + print_status(festatus); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "Not able to lock to the signal on the given frequency, timeout: %d\n", tmout); + return -1; + } + return 0; +} + +#else + +static int check_status(int fd_frontend,FrontendParameters* feparams,int tuner_type,uint32_t base, int tmout) +{ + int i,res; + int32_t strength; + fe_status_t festatus; + FrontendEvent event; + + struct pollfd pfd[1]; + + while(1) + { + if(ioctl(fd_frontend, FE_GET_EVENT, &event) == -1) + break; + } + + i = 0; res = -1; + while ((i < 3) && (res < 0)) + { + if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); + return -1; + } + + pfd[0].fd = fd_frontend; + pfd[0].events = POLLIN | POLLPRI; + + if(poll(pfd,1,tmout*1000) > 0) + { + if (pfd[0].revents & POLLPRI) + { + mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend event\n"); + if ( ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_EVENT"); + return -1; + } + mp_msg(MSGT_DEMUX, MSGL_V, "Received "); + switch(event.type) + { + case FE_UNEXPECTED_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "unexpected event\n"); + res = -1; + break; + + case FE_FAILURE_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "failure event\n"); + res = -1; + break; + + case FE_COMPLETION_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "completion event\n"); + res = 0; + break; + } + } + i++; + } + } + + if (res > 0) + switch (event.type) + { + case FE_UNEXPECTED_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_UNEXPECTED_EV\n"); + break; + case FE_COMPLETION_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_COMPLETION_EV\n"); + break; + case FE_FAILURE_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_FAILURE_EV\n"); + break; + } + + if (event.type == FE_COMPLETION_EV) + { + switch(tuner_type) + { + case FE_OFDM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); + break; + + case FE_QPSK: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((event.u.completionEvent.Frequency)+base)); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + break; + + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); + break; + + default: + break; + } + + strength=0; + if(ioctl(fd_frontend,FE_READ_BER,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); + + strength=0; + if(ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); + + strength=0; + if(ioctl(fd_frontend,FE_READ_SNR,&strength) >= 0) + mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); + + festatus=0; + mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); + + if(ioctl(fd_frontend,FE_READ_STATUS,&festatus) >= 0) + print_status(festatus); + else + mp_msg(MSGT_DEMUX, MSGL_ERR, " ERROR, UNABLE TO READ_STATUS"); + + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "Not able to lock to the signal on the given frequency\n"); + return -1; + } + return 0; +} +#endif + +#ifdef HAVE_DVB_HEAD + +static struct diseqc_cmd { + struct dvb_diseqc_master_cmd cmd; + uint32_t wait; +}; + +static int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, + fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b) +{ + if(ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1) + return -1; + if(ioctl(fd, FE_SET_VOLTAGE, v) == -1) + return -1; + usleep(15 * 1000); + if(ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1) + return -1; + usleep(cmd->wait * 1000); + usleep(15 * 1000); + if(ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1) + return -1; + usleep(15 * 1000); + if(ioctl(fd, FE_SET_TONE, t) == -1) + return -1; + + return 0; +} + +/* digital satellite equipment control, + * specification is available from http://www.eutelsat.com/ + */ +static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) +{ + struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; + + /* param: high nibble: reset bits, low nibble set bits, + * bits are: option, position, polarizaion, band + */ + cmd.cmd.msg[3] = + 0xf0 | (((sat_no * 4) & 0x0f) | (hi_lo ? 1 : 0) | (polv ? 0 : 2)); + + return diseqc_send_msg(secfd, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, + &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, + (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A); +} + +#else + +static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) +{ + struct secCommand scmd; + struct secCmdSequence scmds; + + scmds.continuousTone = (hi_lo ? SEC_TONE_ON : SEC_TONE_OFF); + scmds.voltage = (polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); + scmds.miniCommand = SEC_MINI_NONE; + + scmd.type = SEC_CMDTYPE_DISEQC; + scmds.numCommands = 1; + scmds.commands = &scmd; + + scmd.u.diseqc.addr = 0x10; + scmd.u.diseqc.cmd = 0x38; + scmd.u.diseqc.numParams = 1; + scmd.u.diseqc.params[0] = 0xf0 | + (((sat_no) << 2) & 0x0F) | + (hi_lo ? 1 : 0) | + (polv ? 0 : 2); + + if (ioctl(secfd,SEC_SEND_SEQUENCE,&scmds) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "Error sending DisEqC"); + return -1; + } + + return 0; +} +#endif + +static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, + fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, + fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth, + fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout) +{ + int res, hi_lo, dfd; +#ifdef HAVE_DVB_HEAD + struct dvb_frontend_parameters feparams; + struct dvb_frontend_info fe_info; +#else + FrontendParameters feparams; + FrontendInfo fe_info; + struct secStatus sec_state; +#endif + + + mp_msg(MSGT_DEMUX, MSGL_V, "TUNE_IT, fd_frontend %d, fd_sec %d\nfreq %lu, srate %lu, pol %c, tone %i, specInv, diseqc %u, fe_modulation_t modulation,fe_code_rate_t HP_CodeRate, fe_transmit_mode_t TransmissionMode,fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth\n", + fd_frontend, fd_sec, (long unsigned int)freq, (long unsigned int)srate, pol, tone, diseqc); + + + if ( (res = ioctl(fd_frontend,FE_GET_INFO, &fe_info) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "FE_GET_INFO FAILED\n"); + return -1; + } + + +#ifdef HAVE_DVB_HEAD + mp_msg(MSGT_DEMUX, MSGL_V, "Using DVB card \"%s\"\n", fe_info.name); +#endif + + switch(fe_info.type) + { + case FE_OFDM: +#ifdef HAVE_DVB_HEAD + if (freq < 1000000) freq*=1000UL; + feparams.frequency=freq; + feparams.inversion=specInv; + feparams.u.ofdm.bandwidth=bandwidth; + feparams.u.ofdm.code_rate_HP=HP_CodeRate; + feparams.u.ofdm.code_rate_LP=LP_CodeRate; + feparams.u.ofdm.constellation=modulation; + feparams.u.ofdm.transmission_mode=TransmissionMode; + feparams.u.ofdm.guard_interval=guardInterval; + feparams.u.ofdm.hierarchy_information=hier; +#else + if (freq < 1000000) freq*=1000UL; + feparams.Frequency=freq; + feparams.Inversion=specInv; + feparams.u.ofdm.bandWidth=bandwidth; + feparams.u.ofdm.HP_CodeRate=HP_CodeRate; + feparams.u.ofdm.LP_CodeRate=LP_CodeRate; + feparams.u.ofdm.Constellation=modulation; + feparams.u.ofdm.TransmissionMode=TransmissionMode; + feparams.u.ofdm.guardInterval=guardInterval; + feparams.u.ofdm.HierarchyInformation=hier; +#endif + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-T to %d Hz, bandwidth: %d\n",freq, bandwidth); + break; + case FE_QPSK: + if (freq > 2200000) + { + // this must be an absolute frequency + if (freq < SLOF) + { +#ifdef HAVE_DVB_HEAD + freq = feparams.frequency=(freq-LOF1); +#else + freq = feparams.Frequency=(freq-LOF1); +#endif + hi_lo = 0; + } + else + { +#ifdef HAVE_DVB_HEAD + freq = feparams.frequency=(freq-LOF2); +#else + freq = feparams.Frequency=(freq-LOF2); +#endif + hi_lo = 1; + } + } + else + { + // this is an L-Band frequency +#ifdef HAVE_DVB_HEAD + feparams.frequency=freq; +#else + feparams.Frequency=freq; +#endif + } + +#ifdef HAVE_DVB_HEAD + feparams.inversion=specInv; + feparams.u.qpsk.symbol_rate=srate; + feparams.u.qpsk.fec_inner=HP_CodeRate; + dfd = fd_frontend; +#else + feparams.Inversion=specInv; + feparams.u.qpsk.SymbolRate=srate; + feparams.u.qpsk.FEC_inner=HP_CodeRate; + dfd = fd_sec; +#endif + + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-S to Freq: %u, Pol: %c Srate: %d, 22kHz: %s, LNB: %d\n",freq,pol,srate,hi_lo ? "on" : "off", diseqc); + + if(do_diseqc(dfd, diseqc, (pol == 'V' ? 1 : 0), hi_lo) == 0) + mp_msg(MSGT_DEMUX, MSGL_V, "DISEQC SETTING SUCCEDED\n"); + else + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "DISEQC SETTING FAILED\n"); + return -1; + } + break; + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-C to %d, srate=%d\n",freq,srate); +#ifdef HAVE_DVB_HEAD + feparams.frequency=freq; + feparams.inversion=specInv; + feparams.u.qam.symbol_rate = srate; + feparams.u.qam.fec_inner = HP_CodeRate; + feparams.u.qam.modulation = modulation; +#else + feparams.Frequency=freq; + feparams.Inversion=specInv; + feparams.u.qam.SymbolRate = srate; + feparams.u.qam.FEC_inner = HP_CodeRate; + feparams.u.qam.QAM = modulation; +#endif + break; +#ifdef DVB_ATSC + case FE_ATSC: + mp_msg(MSGT_DEMUX, MSGL_V, "tuning ATSC to %d, modulation=%d\n",freq,modulation); + feparams.frequency=freq; + feparams.u.vsb.modulation = modulation; + break; +#endif + default: + mp_msg(MSGT_DEMUX, MSGL_V, "Unknown FE type. Aborting\n"); + return 0; + } + usleep(100000); + +#ifndef HAVE_DVB_HEAD + if (fd_sec) SecGetStatus(fd_sec, &sec_state); +#endif + + return(check_status(fd_frontend,&feparams,fe_info.type, (hi_lo ? LOF2 : LOF1), timeout)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/dvbin.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,870 @@ +/* + +dvbstream +(C) Dave Chapman <dave@dchapman.com> 2001, 2002. + +The latest version can be found at http://www.linuxstb.org/dvbstream + +Modified for use with MPlayer, for details see the changelog at +http://svn.mplayerhq.hu/mplayer/trunk/ +$Id$ + +Copyright notice: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include "stream.h" +#include "demuxer.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +#include "dvbin.h" + + +#define MAX_CHANNELS 8 +#define CHANNEL_LINE_LEN 256 +#define min(a, b) ((a) <= (b) ? (a) : (b)) + + +//TODO: CAMBIARE list_ptr e da globale a per_priv + + +static struct stream_priv_s +{ + char *prog; + int card; + char *type; + int vid, aid; + int timeout; + char *file; +} +stream_defaults = +{ + "", 1, "", 0, 0, 30, NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s, f) + +/// URL definition +static m_option_t stream_params[] = { + {"prog", ST_OFF(prog), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"card", ST_OFF(card), CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, + {"type", ST_OFF(type), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"vid", ST_OFF(vid), CONF_TYPE_INT, 0, 0 ,0, NULL}, + {"aid", ST_OFF(aid), CONF_TYPE_INT, 0, 0 ,0, NULL}, + {"timeout",ST_OFF(timeout), CONF_TYPE_INT, M_OPT_RANGE, 1, 30, NULL}, + {"file", ST_OFF(file), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + + {"hostname", ST_OFF(prog), CONF_TYPE_STRING, 0, 0, 0, NULL }, + {"username", ST_OFF(card), CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + +static struct m_struct_st stream_opts = { + "dvbin", + sizeof(struct stream_priv_s), + &stream_defaults, + stream_params +}; + + + +m_option_t dvbin_opts_conf[] = { + {"prog", &stream_defaults.prog, CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"card", &stream_defaults.card, CONF_TYPE_INT, M_OPT_RANGE, 1, 4, NULL}, + {"type", "DVB card type is autodetected and can't be overridden\n", CONF_TYPE_PRINT, CONF_NOCFG, 0 ,0, NULL}, + {"vid", &stream_defaults.vid, CONF_TYPE_INT, 0, 0 ,0, NULL}, + {"aid", &stream_defaults.aid, CONF_TYPE_INT, 0, 0 ,0, NULL}, + {"timeout", &stream_defaults.timeout, CONF_TYPE_INT, M_OPT_RANGE, 1, 30, NULL}, + {"file", &stream_defaults.file, CONF_TYPE_STRING, 0, 0 ,0, NULL}, + + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + + + + +extern int dvb_set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype); +extern int dvb_demux_stop(int fd); +extern int dvb_get_tuner_type(int fd); +int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt, int *pids); +int dvb_fix_demuxes(dvb_priv_t *priv, int cnt, int *pids); + +extern int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, + fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, + fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate, + fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout); +extern char *dvb_dvrdev[4], *dvb_demuxdev[4], *dvb_frontenddev[4]; + +static dvb_config_t *dvb_config = NULL; + + +static dvb_channels_list *dvb_get_channels(char *filename, int type) +{ + dvb_channels_list *list; + FILE *f; + char line[CHANNEL_LINE_LEN], *colon; + + int fields, cnt, pcnt, k; + dvb_channel_t *ptr, *tmp, chn; + char tmp_lcr[256], tmp_hier[256], inv[256], bw[256], cr[256], mod[256], transm[256], gi[256], vpid_str[256], apid_str[256]; + const char *cbl_conf = "%d:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; + const char *sat_conf = "%d:%c:%d:%d:%255[^:]:%255[^:]\n"; + const char *ter_conf = "%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; + const char *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]\n"; + + mp_msg(MSGT_DEMUX, MSGL_V, "CONFIG_READ FILE: %s, type: %d\n", filename, type); + if((f=fopen(filename, "r"))==NULL) + { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "CAN'T READ CONFIG FILE %s\n", filename); + return NULL; + } + + list = malloc(sizeof(dvb_channels_list)); + if(list == NULL) + { + fclose(f); + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); + return NULL; + } + + ptr = &chn; + list->NUM_CHANNELS = 0; + list->channels = NULL; + while(! feof(f)) + { + if( fgets(line, CHANNEL_LINE_LEN, f) == NULL ) + continue; + + if((line[0] == '#') || (strlen(line) == 0)) + continue; + + colon = index(line, ':'); + if(colon) + { + k = colon - line; + if(!k) + continue; + ptr->name = (char*) malloc(k+1); + if(! ptr->name) + continue; + strncpy(ptr->name, line, k); + ptr->name[k] = 0; + } + else + continue; + k++; + apid_str[0] = vpid_str[0] = 0; + ptr->pids_cnt = 0; + ptr->freq = 0; + if(type == TUNER_TER) + { + fields = sscanf(&line[k], ter_conf, + &ptr->freq, inv, bw, cr, tmp_lcr, mod, + transm, gi, tmp_hier, vpid_str, apid_str); + mp_msg(MSGT_DEMUX, MSGL_V, + "TER, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq); + } + else if(type == TUNER_CBL) + { + fields = sscanf(&line[k], cbl_conf, + &ptr->freq, inv, &ptr->srate, + cr, mod, vpid_str, apid_str); + mp_msg(MSGT_DEMUX, MSGL_V, + "CBL, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate); + } +#ifdef DVB_ATSC + else if(type == TUNER_ATSC) + { + fields = sscanf(&line[k], atsc_conf, + &ptr->freq, mod, vpid_str, apid_str); + mp_msg(MSGT_DEMUX, MSGL_V, + "ATSC, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq); + } +#endif + else //SATELLITE + { + fields = sscanf(&line[k], sat_conf, + &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, vpid_str, apid_str); + ptr->pol = toupper(ptr->pol); + ptr->freq *= 1000UL; + ptr->srate *= 1000UL; + ptr->tone = -1; + ptr->inv = INVERSION_AUTO; + ptr->cr = FEC_AUTO; + if((ptr->diseqc > 4) || (ptr->diseqc < 0)) + continue; + if(ptr->diseqc > 0) + ptr->diseqc--; + mp_msg(MSGT_DEMUX, MSGL_V, + "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, ptr->diseqc); + } + + if(vpid_str[0]) + { + pcnt = sscanf(vpid_str, "%d+%d+%d+%d+%d+%d+%d", &ptr->pids[0], &ptr->pids[1], &ptr->pids[2], &ptr->pids[3], + &ptr->pids[4], &ptr->pids[5], &ptr->pids[6]); + if(pcnt > 0) + { + ptr->pids_cnt = pcnt; + fields++; + } + } + + if(apid_str[0]) + { + cnt = ptr->pids_cnt; + pcnt = sscanf(apid_str, "%d+%d+%d+%d+%d+%d+%d+%d", &ptr->pids[cnt], &ptr->pids[cnt+1], &ptr->pids[cnt+2], + &ptr->pids[cnt+3], &ptr->pids[cnt+4], &ptr->pids[cnt+5], &ptr->pids[cnt+6], &ptr->pids[cnt+7]); + if(pcnt > 0) + { + ptr->pids_cnt += pcnt; + fields++; + } + } + + if((fields < 2) || (ptr->pids_cnt <= 0) || (ptr->freq == 0) || (strlen(ptr->name) == 0)) + continue; + + + ptr->pids[ptr->pids_cnt] = 0; //PID 0 is the PAT + ptr->pids_cnt++; + mp_msg(MSGT_DEMUX, MSGL_V, " PIDS: "); + for(cnt = 0; cnt < ptr->pids_cnt; cnt++) + mp_msg(MSGT_DEMUX, MSGL_V, " %d ", ptr->pids[cnt]); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + + if((type == TUNER_TER) || (type == TUNER_CBL)) + { + if(! strcmp(inv, "INVERSION_ON")) + ptr->inv = INVERSION_ON; + else if(! strcmp(inv, "INVERSION_OFF")) + ptr->inv = INVERSION_OFF; + else + ptr->inv = INVERSION_AUTO; + + + if(! strcmp(cr, "FEC_1_2")) + ptr->cr =FEC_1_2; + else if(! strcmp(cr, "FEC_2_3")) + ptr->cr =FEC_2_3; + else if(! strcmp(cr, "FEC_3_4")) + ptr->cr =FEC_3_4; +#ifdef HAVE_DVB_HEAD + else if(! strcmp(cr, "FEC_4_5")) + ptr->cr =FEC_4_5; + else if(! strcmp(cr, "FEC_6_7")) + ptr->cr =FEC_6_7; + else if(! strcmp(cr, "FEC_8_9")) + ptr->cr =FEC_8_9; +#endif + else if(! strcmp(cr, "FEC_5_6")) + ptr->cr =FEC_5_6; + else if(! strcmp(cr, "FEC_7_8")) + ptr->cr =FEC_7_8; + else if(! strcmp(cr, "FEC_NONE")) + ptr->cr =FEC_NONE; + else ptr->cr =FEC_AUTO; + } + + + if((type == TUNER_TER) || (type == TUNER_CBL) || (type == TUNER_ATSC)) + { + if(! strcmp(mod, "QAM_128")) + ptr->mod = QAM_128; + else if(! strcmp(mod, "QAM_256")) + ptr->mod = QAM_256; + else if(! strcmp(mod, "QAM_64")) + ptr->mod = QAM_64; + else if(! strcmp(mod, "QAM_32")) + ptr->mod = QAM_32; + else if(! strcmp(mod, "QAM_16")) + ptr->mod = QAM_16; +#ifdef DVB_ATSC + else if(! strcmp(mod, "VSB_8") || ! strcmp(mod, "8VSB")) + ptr->mod = VSB_8; + else if(! strcmp(mod, "VSB_16") || !strcmp(mod, "16VSB")) + ptr->mod = VSB_16; + + ptr->inv = INVERSION_AUTO; +#endif + } + + if(type == TUNER_TER) + { + if(! strcmp(bw, "BANDWIDTH_6_MHZ")) + ptr->bw = BANDWIDTH_6_MHZ; + else if(! strcmp(bw, "BANDWIDTH_7_MHZ")) + ptr->bw = BANDWIDTH_7_MHZ; + else if(! strcmp(bw, "BANDWIDTH_8_MHZ")) + ptr->bw = BANDWIDTH_8_MHZ; + + + if(! strcmp(transm, "TRANSMISSION_MODE_2K")) + ptr->trans = TRANSMISSION_MODE_2K; + else if(! strcmp(transm, "TRANSMISSION_MODE_8K")) + ptr->trans = TRANSMISSION_MODE_8K; + + + if(! strcmp(gi, "GUARD_INTERVAL_1_32")) + ptr->gi = GUARD_INTERVAL_1_32; + else if(! strcmp(gi, "GUARD_INTERVAL_1_16")) + ptr->gi = GUARD_INTERVAL_1_16; + else if(! strcmp(gi, "GUARD_INTERVAL_1_8")) + ptr->gi = GUARD_INTERVAL_1_8; + else ptr->gi = GUARD_INTERVAL_1_4; + + if(! strcmp(tmp_lcr, "FEC_1_2")) + ptr->cr_lp =FEC_1_2; + else if(! strcmp(tmp_lcr, "FEC_2_3")) + ptr->cr_lp =FEC_2_3; + else if(! strcmp(tmp_lcr, "FEC_3_4")) + ptr->cr_lp =FEC_3_4; +#ifdef HAVE_DVB_HEAD + else if(! strcmp(tmp_lcr, "FEC_4_5")) + ptr->cr_lp =FEC_4_5; + else if(! strcmp(tmp_lcr, "FEC_6_7")) + ptr->cr_lp =FEC_6_7; + else if(! strcmp(tmp_lcr, "FEC_8_9")) + ptr->cr_lp =FEC_8_9; +#endif + else if(! strcmp(tmp_lcr, "FEC_5_6")) + ptr->cr_lp =FEC_5_6; + else if(! strcmp(tmp_lcr, "FEC_7_8")) + ptr->cr_lp =FEC_7_8; + else if(! strcmp(tmp_lcr, "FEC_NONE")) + ptr->cr_lp =FEC_NONE; + else ptr->cr_lp =FEC_AUTO; + + + if(! strcmp(tmp_hier, "HIERARCHY_1")) + ptr->hier = HIERARCHY_1; + else if(! strcmp(tmp_hier, "HIERARCHY_2")) + ptr->hier = HIERARCHY_2; + else if(! strcmp(tmp_hier, "HIERARCHY_4")) + ptr->hier = HIERARCHY_4; +#ifdef HAVE_DVB_HEAD + else if(! strcmp(tmp_hier, "HIERARCHY_AUTO")) + ptr->hier = HIERARCHY_AUTO; +#endif + else ptr->hier = HIERARCHY_NONE; + } + + tmp = (dvb_channel_t*)realloc(list->channels, sizeof(dvb_channel_t) * (list->NUM_CHANNELS + 1)); + if(tmp == NULL) + break; + + list->channels = tmp; + memcpy(&(list->channels[list->NUM_CHANNELS]), ptr, sizeof(dvb_channel_t)); + list->NUM_CHANNELS++; + if(sizeof(dvb_channel_t) * list->NUM_CHANNELS >= 1024*1024) + { + mp_msg(MSGT_DEMUX, MSGL_V, "dvbin.c, > 1MB allocated for channels struct, dropping the rest of the file\r\n"); + break; + } + } + + fclose(f); + if(list->NUM_CHANNELS == 0) + { + if(list->channels != NULL) + free(list->channels); + free(list); + return NULL; + } + + list->current = 0; + return list; +} + + + +static int dvb_streaming_read(stream_t *stream, char *buffer, int size) +{ + struct pollfd pfds[1]; + int pos=0, tries, rk, fd; + dvb_priv_t *priv = (dvb_priv_t *) stream->priv; + + mp_msg(MSGT_DEMUX, MSGL_DBG3, "dvb_streaming_read(%d)\n", size); + + tries = priv->retry + 1; + + fd = stream->fd; + while(pos < size) + { + pfds[0].fd = fd; + pfds[0].events = POLLIN | POLLPRI; + + rk = size - pos; + if(poll(pfds, 1, 500) <= 0) + { + errno = 0; + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_streaming_read, attempt N. %d failed with errno %d when reading %d bytes\n", tries, errno, size-pos); + if(--tries > 0) + continue; + else + break; + } + if((rk = read(fd, &buffer[pos], rk)) > 0) + { + pos += rk; + mp_msg(MSGT_DEMUX, MSGL_DBG3, "ret (%d) bytes\n", pos); + } + } + + + if(! pos) + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_streaming_read, return %d bytes\n", pos); + + return pos; +} + +static void dvbin_close(stream_t *stream); + +int dvb_set_channel(dvb_priv_t *priv, int card, int n) +{ + dvb_channels_list *new_list; + dvb_channel_t *channel; + int do_tuning; + stream_t *stream = (stream_t*) priv->stream; + char buf[4096]; + dvb_config_t *conf = (dvb_config_t *) priv->config; + int devno; + int i; + + if((card < 0) || (card > conf->count)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_set_channel: INVALID CARD NUMBER: %d vs %d, abort\n", card, conf->count); + return 0; + } + + devno = conf->cards[card].devno; + new_list = conf->cards[card].list; + if((n > new_list->NUM_CHANNELS) || (n < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_set_channel: INVALID CHANNEL NUMBER: %d, for card %d, abort\n", n, card); + return 0; + } + channel = &(new_list->channels[n]); + + if(priv->is_on) //the fds are already open and we have to stop the demuxers + { + for(i = 0; i < priv->demux_fds_cnt; i++) + dvb_demux_stop(priv->demux_fds[i]); + + priv->retry = 0; + while(dvb_streaming_read(stream, buf, 4096) > 0); //empty both the stream's and driver's buffer + if(priv->card != card) + { + dvbin_close(stream); + if(! dvb_open_devices(priv, devno, channel->pids_cnt, channel->pids)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB_SET_CHANNEL, COULDN'T OPEN DEVICES OF CARD: %d, EXIT\n", card); + return 0; + } + strcpy(priv->prev_tuning, ""); + } + else //close all demux_fds with pos > pids required for the new channel or open other demux_fds if we have too few + { + if(! dvb_fix_demuxes(priv, channel->pids_cnt, channel->pids)) + return 0; + } + } + else + { + if(! dvb_open_devices(priv, devno, channel->pids_cnt, channel->pids)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB_SET_CHANNEL2, COULDN'T OPEN DEVICES OF CARD: %d, EXIT\n", card); + return 0; + } + strcpy(priv->prev_tuning, ""); + } + + dvb_config->priv = priv; + priv->card = card; + priv->list = new_list; + priv->retry = 5; + new_list->current = n; + stream->fd = priv->dvr_fd; + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_SET_CHANNEL: new channel name=%s, card: %d, channel %d\n", channel->name, card, n); + + switch(priv->tuner_type) + { + case TUNER_SAT: + sprintf(priv->new_tuning, "%d|%09d|%09d|%d|%c", priv->card, channel->freq, channel->srate, channel->diseqc, channel->pol); + break; + + case TUNER_TER: + sprintf(priv->new_tuning, "%d|%09d|%d|%d|%d|%d|%d|%d", priv->card, channel->freq, channel->inv, + channel->bw, channel->cr, channel->mod, channel->trans, channel->gi); + break; + + case TUNER_CBL: + sprintf(priv->new_tuning, "%d|%09d|%d|%d|%d|%d", priv->card, channel->freq, channel->inv, channel->srate, + channel->cr, channel->mod); + break; +#ifdef DVB_ATSC + case TUNER_ATSC: + sprintf(priv->new_tuning, "%d|%09d|%d", priv->card, channel->freq, channel->mod); + break; +#endif + } + + + + if(strcmp(priv->prev_tuning, priv->new_tuning)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DIFFERENT TUNING THAN THE PREVIOUS: %s -> %s\n", priv->prev_tuning, priv->new_tuning); + strcpy(priv->prev_tuning, priv->new_tuning); + do_tuning = 1; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "SAME TUNING PARAMETERS, NO TUNING\n"); + do_tuning = 0; + } + + stream->eof=1; + stream_reset(stream); + + + if(do_tuning) + if (! dvb_tune(priv, channel->freq, channel->pol, channel->srate, channel->diseqc, channel->tone, + channel->inv, channel->mod, channel->gi, channel->trans, channel->bw, channel->cr, channel->cr_lp, channel->hier, priv->timeout)) + return 0; + + + priv->is_on = 1; + + //sets demux filters and restart the stream + for(i = 0; i < channel->pids_cnt; i++) + { + if(! dvb_set_ts_filt(priv->demux_fds[i], channel->pids[i], DMX_PES_OTHER)) + return 0; + } + + return 1; +} + + + +int dvb_step_channel(dvb_priv_t *priv, int dir) +{ + int new_current; + dvb_channels_list *list; + + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_STEP_CHANNEL dir %d\n", dir); + + if(priv == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: NULL priv_ptr, quit\n"); + return 0; + } + + list = priv->list; + if(list == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: NULL list_ptr, quit\n"); + return 0; + } + + new_current = (list->NUM_CHANNELS + list->current + (dir == DVB_CHANNEL_HIGHER ? 1 : -1)) % list->NUM_CHANNELS; + + return dvb_set_channel(priv, priv->card, new_current); +} + + + + +extern char *get_path(const char *); + +static void dvbin_close(stream_t *stream) +{ + int i; + dvb_priv_t *priv = (dvb_priv_t *) stream->priv; + + for(i = priv->demux_fds_cnt-1; i >= 0; i--) + { + priv->demux_fds_cnt--; + mp_msg(MSGT_DEMUX, MSGL_V, "DVBIN_CLOSE, close(%d), fd=%d, COUNT=%d\n", i, priv->demux_fds[i], priv->demux_fds_cnt); + close(priv->demux_fds[i]); + } + close(priv->dvr_fd); + + close(priv->fe_fd); +#ifdef HAVE_DVB + close(priv->sec_fd); +#endif + + priv->is_on = 0; + dvb_config->priv = NULL; +} + + +static int dvb_streaming_start(dvb_priv_t *priv, struct stream_priv_s *opts, int tuner_type, char *progname) +{ + int i; + dvb_channel_t *channel = NULL; + stream_t *stream = (stream_t*) priv->stream; + + mp_msg(MSGT_DEMUX, MSGL_V, "\r\ndvb_streaming_start(PROG: %s, CARD: %d, VID: %d, AID: %d, TYPE: %s, FILE: %s)\r\n", + opts->prog, opts->card, opts->vid, opts->aid, opts->type, opts->file); + + priv->is_on = 0; + + i = 0; + while((channel == NULL) && i < priv->list->NUM_CHANNELS) + { + if(! strcmp(priv->list->channels[i].name, progname)) + channel = &(priv->list->channels[i]); + + i++; + } + + if(channel != NULL) + { + priv->list->current = i-1; + mp_msg(MSGT_DEMUX, MSGL_V, "PROGRAM NUMBER %d: name=%s, freq=%u\n", i-1, channel->name, channel->freq); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "\n\nDVBIN: no such channel \"%s\"\n\n", progname); + return 0; + } + + + strcpy(priv->prev_tuning, ""); + if(!dvb_set_channel(priv, priv->card, priv->list->current)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR, COULDN'T SET CHANNEL %i: ", priv->list->current); + dvbin_close(stream); + return 0; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SUCCESSFUL EXIT from dvb_streaming_start\n"); + + return 1; +} + + + + +static int dvb_open(stream_t *stream, int mode, void *opts, int *file_format) +{ + // I don't force the file format bacause, although it's almost always TS, + // there are some providers that stream an IP multicast with M$ Mpeg4 inside + struct stream_priv_s* p = (struct stream_priv_s*)opts; + dvb_priv_t *priv; + char *progname; + int tuner_type = 0; + + + if(mode != STREAM_READ) + return STREAM_UNSUPORTED; + + stream->priv = (dvb_priv_t*) malloc(sizeof(dvb_priv_t)); + if(stream->priv == NULL) + return STREAM_ERROR; + + priv = (dvb_priv_t *)stream->priv; + priv->stream = stream; + dvb_config = dvb_get_config(); + if(dvb_config == NULL) + { + free(priv); + mp_msg(MSGT_DEMUX, MSGL_ERR, "DVB CONFIGURATION IS EMPTY, exit\n"); + return STREAM_ERROR; + } + dvb_config->priv = priv; + priv->config = dvb_config; + + if(p->card < 1 || p->card > priv->config->count) + { + free(priv); + mp_msg(MSGT_DEMUX, MSGL_ERR, "NO CONFIGURATION FOUND FOR CARD N. %d, exit\n", p->card); + return STREAM_ERROR; + } + priv->card = p->card - 1; + priv->timeout = p->timeout; + + tuner_type = priv->config->cards[priv->card].type; + + if(tuner_type == 0) + { + free(priv); + mp_msg(MSGT_DEMUX, MSGL_V, "OPEN_DVB: UNKNOWN OR UNDETECTABLE TUNER TYPE, EXIT\n"); + return STREAM_ERROR; + } + + + priv->tuner_type = tuner_type; + + mp_msg(MSGT_DEMUX, MSGL_V, "OPEN_DVB: prog=%s, card=%d, type=%d, vid=%d, aid=%d\n", + p->prog, priv->card+1, priv->tuner_type, p->vid, p->aid); + + priv->list = priv->config->cards[priv->card].list; + + if((! strcmp(p->prog, "")) && (priv->list != NULL)) + progname = priv->list->channels[0].name; + else + progname = p->prog; + + + if(! dvb_streaming_start(priv, p, tuner_type, progname)) + { + free(stream->priv); + stream->priv = NULL; + return STREAM_ERROR; + } + + stream->type = STREAMTYPE_DVB; + stream->fill_buffer = dvb_streaming_read; + stream->close = dvbin_close; + m_struct_free(&stream_opts, opts); + + *file_format = DEMUXER_TYPE_MPEG_TS; + + return STREAM_OK; +} + +#define MAX_CARDS 4 +dvb_config_t *dvb_get_config(void) +{ + int i, fd, type, size; + char filename[30], *conf_file, *name; + dvb_channels_list *list; + dvb_card_config_t *cards = NULL, *tmp; + dvb_config_t *conf = NULL; + + if(dvb_config != NULL) + return dvb_config; + + conf = (dvb_config_t*) malloc(sizeof(dvb_config_t)); + if(conf == NULL) + return NULL; + + conf->priv = NULL; + conf->count = 0; + conf->cards = NULL; + for(i=0; i<MAX_CARDS; i++) + { + sprintf(filename, "/dev/dvb/adapter%d/frontend0", i); + fd = open(filename, O_RDWR | O_NONBLOCK); + if(fd < 0) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_CONFIG, can't open device %s, skipping\n", filename); + continue; + } + + type = dvb_get_tuner_type(fd); + close(fd); + if(type != TUNER_SAT && type != TUNER_TER && type != TUNER_CBL && type != TUNER_ATSC) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_CONFIG, can't detect tuner type of card %d, skipping\n", i); + continue; + } + + switch(type) + { + case TUNER_TER: + conf_file = get_path("channels.conf.ter"); + break; + case TUNER_CBL: + conf_file = get_path("channels.conf.cbl"); + break; + case TUNER_SAT: + conf_file = get_path("channels.conf.sat"); + break; + case TUNER_ATSC: + conf_file = get_path("channels.conf.atsc"); + break; + } + + if((access(conf_file, F_OK | R_OK) != 0)) + conf_file = get_path("channels.conf"); + + list = dvb_get_channels(conf_file, type); + if(list == NULL) + continue; + + size = sizeof(dvb_card_config_t) * (conf->count + 1); + tmp = realloc(conf->cards, size); + + if(tmp == NULL) + { + fprintf(stderr, "DVB_CONFIG, can't realloc %d bytes, skipping\n", size); + continue; + } + cards = tmp; + + name = (char*) malloc(20); + if(name==NULL) + { + fprintf(stderr, "DVB_CONFIG, can't realloc 20 bytes, skipping\n"); + continue; + } + + conf->cards = cards; + conf->cards[conf->count].devno = i; + conf->cards[conf->count].list = list; + conf->cards[conf->count].type = type; + sprintf(name, "DVB-%c card n. %d", type==TUNER_TER ? 'T' : (type==TUNER_CBL ? 'C' : 'S'), conf->count+1); + conf->cards[conf->count].name = name; + conf->count++; + } + + if(conf->count == 0) + { + free(conf); + conf = NULL; + } + + dvb_config = conf; + return conf; +} + + + +stream_info_t stream_info_dvb = { + "Dvb Input", + "dvbin", + "Nico", + "based on the code from ??? (probably Arpi)", + dvb_open, + { "dvb", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/dvbin.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,118 @@ +/* Imported from the dvbstream project + * + * Modified for use with MPlayer, for details see the changelog at + * http://svn.mplayerhq.hu/mplayer/trunk/ + * $Id$ + */ + +#ifndef DVBIN_H +#define DVBIN_H + +#include "stream.h" + +#define SLOF (11700*1000UL) +#define LOF1 (9750*1000UL) +#define LOF2 (10600*1000UL) + +#ifdef HAVE_DVB_HEAD + #include <linux/dvb/dmx.h> + #include <linux/dvb/frontend.h> + #include <linux/dvb/version.h> +#else + #include <ost/dmx.h> + #include <ost/sec.h> + #include <ost/frontend.h> + #define fe_status_t FrontendStatus + #define fe_spectral_inversion_t SpectralInversion + #define fe_modulation_t Modulation + #define fe_code_rate_t CodeRate + #define fe_transmit_mode_t TransmitMode + #define fe_guard_interval_t GuardInterval + #define fe_bandwidth_t BandWidth + #define fe_hierarchy_t Hierarchy + #define fe_sec_voltage_t SecVoltage + #define dmx_pes_filter_params dmxPesFilterParams + #define dmx_sct_filter_params dmxSctFilterParams + #define dmx_pes_type_t dmxPesType_t +#endif + +#undef DVB_ATSC +#if defined(DVB_API_VERSION_MINOR) +#if DVB_API_VERSION == 3 && DVB_API_VERSION_MINOR >= 1 +#define DVB_ATSC 1 +#endif +#endif + + +#define DVB_CHANNEL_LOWER -1 +#define DVB_CHANNEL_HIGHER 1 + +#include "inttypes.h" + +#ifndef DMX_FILTER_SIZE +#define DMX_FILTER_SIZE 16 +#endif + +typedef struct { + char *name; + int freq, srate, diseqc, tone; + char pol; + int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt; + fe_spectral_inversion_t inv; + fe_modulation_t mod; + fe_transmit_mode_t trans; + fe_bandwidth_t bw; + fe_guard_interval_t gi; + fe_code_rate_t cr, cr_lp; + fe_hierarchy_t hier; +} dvb_channel_t; + + +typedef struct { + uint16_t NUM_CHANNELS; + uint16_t current; + dvb_channel_t *channels; +} dvb_channels_list; + +typedef struct { + int type; + dvb_channels_list *list; + char *name; + int devno; +} dvb_card_config_t; + +typedef struct { + int count; + dvb_card_config_t *cards; + void *priv; +} dvb_config_t; + + +typedef struct { + int card; + int fe_fd; + int sec_fd; + int demux_fd[3], demux_fds[DMX_FILTER_SIZE], demux_fds_cnt; + int dvr_fd; + + dvb_config_t *config; + dvb_channels_list *list; + int tuner_type; + int is_on; + stream_t *stream; + char new_tuning[256], prev_tuning[256]; + int retry; + int timeout; +} dvb_priv_t; + + +#define TUNER_SAT 1 +#define TUNER_TER 2 +#define TUNER_CBL 3 +#define TUNER_ATSC 4 + +extern int dvb_step_channel(dvb_priv_t *, int); +extern int dvb_set_channel(dvb_priv_t *, int, int); +extern dvb_config_t *dvb_get_config(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/dvdnav_stream.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,396 @@ +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "mp_msg.h" +#include "osdep/timer.h" +#include "input/input.h" +#include "stream.h" +#include "demuxer.h" +#include "dvdnav_stream.h" +#include "libvo/video_out.h" +#include "spudec.h" +#include "m_option.h" +#include "m_struct.h" +#include "help_mp.h" + +extern char *dvd_device; +extern char *audio_lang, *dvdsub_lang; + +static struct stream_priv_s { + int track; + char* device; +} stream_priv_dflts = { + 1, + NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + {"filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, + {"hostname", ST_OFF(track), CONF_TYPE_INT, 0, 0, 0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "dvd", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +int dvd_nav_skip_opening=0; /* skip opening stalls? */ +int osd_show_dvd_nav_delay=0; /* count down for dvd nav text on OSD */ +char dvd_nav_text[50]; /* for reporting stuff to OSD */ +int osd_show_dvd_nav_highlight; /* show highlight area */ +int osd_show_dvd_nav_sx; /* start x .... */ +int osd_show_dvd_nav_ex; +int osd_show_dvd_nav_sy; +int osd_show_dvd_nav_ey; +int dvd_nav_still=0; /* are we on a still picture? */ + +dvdnav_priv_t * new_dvdnav_stream(char * filename) { + char * title_str; + dvdnav_priv_t *dvdnav_priv; + + if (!filename) + return NULL; + + if (!(dvdnav_priv=calloc(1,sizeof(*dvdnav_priv)))) + return NULL; + + if (!(dvdnav_priv->filename=strdup(filename))) { + free(dvdnav_priv); + return NULL; + } + + if(dvdnav_open(&(dvdnav_priv->dvdnav),dvdnav_priv->filename)!=DVDNAV_STATUS_OK) + { + free(dvdnav_priv->filename); + free(dvdnav_priv); + return NULL; + } + + if (!dvdnav_priv->dvdnav) { + free(dvdnav_priv); + return NULL; + } + + if(1) //from vlc: if not used dvdnav from cvs will fail + { + int len, event; + char buf[2048]; + + dvdnav_get_next_block(dvdnav_priv->dvdnav,buf,&event,&len); + } + + /* turn on dvdnav caching */ + dvdnav_set_readahead_flag(dvdnav_priv->dvdnav, 0); + if(dvdnav_set_PGC_positioning_flag(dvdnav_priv->dvdnav, 1) != DVDNAV_STATUS_OK) + mp_msg(MSGT_OPEN,MSGL_ERR,"stream_dvdnav, failed to set PGC positioning\n"); +#if 1 + /* report the title?! */ + if (dvdnav_get_title_string(dvdnav_priv->dvdnav,&title_str)==DVDNAV_STATUS_OK) { + mp_msg(MSGT_IDENTIFY, MSGL_INFO,"Title: '%s'\n",title_str); + } +#endif + + //dvdnav_event_clear(dvdnav_priv); + + return dvdnav_priv; +} + +int dvdnav_stream_reset(dvdnav_priv_t * dvdnav_priv) { + if (!dvdnav_priv) return 0; + +// if (dvdnav_reset(dvdnav_priv->dvdnav)!=DVDNAV_STATUS_OK) + return 0; + + dvdnav_priv->started=0; + + return 1; +} + +int dvdnav_stream_sleeping(dvdnav_priv_t * dvdnav_priv) { + unsigned int now; + + if (!dvdnav_priv) return 0; + + if(dvdnav_priv->sleeping) + { + now=GetTimer(); + while(dvdnav_priv->sleeping>1 || now<dvdnav_priv->sleep_until) { +// printf("%s %u<%u\n",__FUNCTION__,now,dvdnav_priv->sleep_until); +// usec_sleep(1000); /* 1ms granularity */ + return 1; + } + dvdnav_still_skip(dvdnav_priv->dvdnav); // continue past... + dvdnav_priv->sleeping=0; + mp_msg(MSGT_OPEN,MSGL_V, "%s: woke up!\n",__FUNCTION__); + } + dvd_nav_still=0; + mp_msg(MSGT_OPEN,MSGL_V, "%s: active\n",__FUNCTION__); + return 0; +} + +void dvdnav_stream_sleep(dvdnav_priv_t * dvdnav_priv, int seconds) { + if (!dvdnav_priv) return; + + if (!dvdnav_priv->started) return; + + dvdnav_priv->sleeping=0; + switch (seconds) { + case 0: + return; + case 0xff: + mp_msg(MSGT_OPEN,MSGL_V, "Sleeping indefinately\n" ); + dvdnav_priv->sleeping=2; + break; + default: + mp_msg(MSGT_OPEN,MSGL_V, "Sleeping %d sec(s)\n", seconds ); + dvdnav_priv->sleep_until = GetTimer();// + seconds*1000000; + dvdnav_priv->sleeping=1; + break; + } + //if (dvdnav_priv->started) dvd_nav_still=1; +} + +void dvdnav_stream_add_event(dvdnav_priv_t* dvdnav_priv, int event, unsigned char *buf, int len) { + //printf("%s: %d\n",__FUNCTION__,event); + + dvdnav_event_t * dvdnav_event; + mp_cmd_t * cmd; + + if (!dvdnav_priv->started) return; + + if (!(dvdnav_event=calloc(1,sizeof(*dvdnav_event)))) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: dvdnav_event: out of memory!\n",__FUNCTION__); + return; + } + dvdnav_event->event=event; + dvdnav_event->details=calloc(1,len); + memcpy(dvdnav_event->details,buf,len); + dvdnav_event->len=len; + + if (!(cmd = calloc(1,sizeof(*cmd)))) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: mp_cmd_t: out of memory!\n",__FUNCTION__); + free(dvdnav_event->details); + free(dvdnav_event); + return; + } + cmd->id=MP_CMD_DVDNAV_EVENT; // S+event; + cmd->name=strdup("dvdnav_event"); // FIXME: do I really need a 'name'? + cmd->nargs=1; + cmd->args[0].v.v=dvdnav_event; +} + +int dvdnav_stream_read(dvdnav_priv_t * dvdnav_priv, unsigned char *buf, int *len) { + int event = DVDNAV_NOP; + + if (!len) return -1; + *len=-1; + if (!dvdnav_priv) return -1; + if (!buf) return -1; + + if (dvd_nav_still) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: got a stream_read while I should be asleep!\n",__FUNCTION__); + *len=0; + return -1; + } + + if (dvdnav_get_next_block(dvdnav_priv->dvdnav,buf,&event,len)!=DVDNAV_STATUS_OK) { + mp_msg(MSGT_OPEN,MSGL_V, "Error getting next block from DVD %d (%s)\n",event, dvdnav_err_to_string(dvdnav_priv->dvdnav) ); + *len=-1; + } + else if (event!=DVDNAV_BLOCK_OK) { + + // need to handle certain events internally (like skipping stills) + switch (event) { + case DVDNAV_STILL_FRAME: { + dvdnav_still_event_t *still_event = (dvdnav_still_event_t*)(buf); + //if (dvdnav_priv->started) dvd_nav_still=1; + //else + dvdnav_still_skip(dvdnav_priv->dvdnav); // don't let dvdnav stall on this image + + break; + case DVDNAV_WAIT: + dvdnav_wait_skip(dvdnav_priv->dvdnav); + break; + } + } + + // got an event, repeat the read + dvdnav_stream_add_event(dvdnav_priv,event,buf,*len); + *len=0; + } +// printf("%s: got %d\n",__FUNCTION__,*len); + return event; +} + +void dvdnav_stream_fullstart(dvdnav_priv_t * dvdnav_priv) { + if (dvdnav_priv && !dvdnav_priv->started) { + dvdnav_stream_reset(dvdnav_priv); + dvdnav_priv->started=1; + } +} + +unsigned int * dvdnav_stream_get_palette(dvdnav_priv_t * dvdnav_priv) { + if (!dvdnav_priv) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv\n",__FUNCTION__); + return NULL; + } + if (!dvdnav_priv->dvdnav) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv->dvdnav\n",__FUNCTION__); + return NULL; + } + #if 0 + if (!dvdnav_priv->dvdnav->vm) { + mp_msg(MSGT_OPEN,MSGL_V, "%s: NULL dvdnav_priv->dvdnav->vm\n",__FUNCTION__); + return NULL; + } + if (!dvdnav_priv->dvdnav->vm->state.pgc) { + printf("%s: NULL dvdnav_priv->dvdnav->vm->state.pgc\n",__FUNCTION__); + return NULL; + } + return dvdnav_priv->dvdnav->vm->state.pgc->palette; + #endif +} + +static void update_title_len(stream_t *stream) { + dvdnav_priv_t *priv = stream->priv; + dvdnav_status_t status; + uint32_t pos = 0, len = 0; + + status = dvdnav_get_position(priv->dvdnav, &pos, &len); + if(status == DVDNAV_STATUS_OK && len) + stream->end_pos = (off_t) len * 2048; +} + + +static int seek(stream_t *s, off_t newpos) { +uint32_t pos = 0, len = 0, sector = 0; +dvdnav_priv_t *priv = s->priv; + + if(newpos==0) { + if(dvdnav_stream_reset(priv->dvdnav)) + s->pos=0; + } + else { + if(s->end_pos && newpos > s->end_pos) + newpos = s->end_pos; + sector = newpos / 2048ULL; + if(dvdnav_sector_search(priv->dvdnav, (uint64_t) sector, SEEK_SET) != DVDNAV_STATUS_OK) + goto fail; + + s->pos = newpos; + } + + return 1; + +fail: + mp_msg(MSGT_STREAM,MSGL_INFO,"dvdnav_stream, seeking to %"PRIu64" failed: %s\n", newpos, dvdnav_err_to_string(priv->dvdnav)); + + return 1; +} + +static void stream_dvdnav_close(stream_t *s) { + dvdnav_priv_t *priv = s->priv; + dvdnav_close(priv->dvdnav); + priv->dvdnav = NULL; + free(priv); +} + + +static int fill_buffer(stream_t *s, char *but, int len) +{ + int event; + dvdnav_priv_t* dvdnav_priv=s->priv; + len=0; + if(!s->end_pos) + update_title_len(s); + while(!len) /* grab all event until DVDNAV_BLOCK_OK (len=2048), DVDNAV_STOP or DVDNAV_STILL_FRAME */ + { + if(-1==(event=dvdnav_stream_read(dvdnav_priv, s->buffer, &len)) || len==-1) + { + mp_msg(MSGT_CPLAYER,MSGL_ERR, "DVDNAV stream read error!\n"); + return 0; + } + switch (event) { + case DVDNAV_STOP: return len; + case DVDNAV_BLOCK_OK: return len; +#if 0 + case DVDNAV_STILL_FRAME: { + if(!dvdnav_priv->stillok) dvdnav_priv->stillcounter++; + dvdnav_priv->lockstillcounter++; + return len; + break; + } + + case DVDNAV_WAIT: { + if(dvdnav_priv->waitcounter>=DVDNAV_MAX_WAIT_FRAME) return len; + break; + } +#endif + } +#if 0 + if(dvdnav_priv->event.cell_really_change && + dvdnav_priv->started && + !dvdnav_priv->vts_domain) + return len; +#endif + } + mp_msg(MSGT_STREAM,MSGL_DBG2,"DVDNAV fill_buffer len: %d\n",len); + return len; +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + struct stream_priv_s* p = (struct stream_priv_s*)opts; + char *filename; + int event,len,tmplen=0; + uint32_t pos, l2; + dvdnav_priv_t *dvdnav_priv; + dvdnav_status_t status; + + //mp_msg(MSGT_OPEN,MSGL_INFO,"URL: %s\n", filename); + + if(p->device) filename = p->device; + else if(dvd_device) filename= dvd_device; + else filename = DEFAULT_DVD_DEVICE; + if(!(dvdnav_priv=new_dvdnav_stream(filename))) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,filename); + return STREAM_UNSUPORTED; + } + + if(dvdnav_title_play(dvdnav_priv->dvdnav, p->track) != DVDNAV_STATUS_OK) { + mp_msg(MSGT_OPEN,MSGL_FATAL,"dvdnav_stream, couldn't select title %d, error '%s'\n", p->track, dvdnav_err_to_string(dvdnav_priv->dvdnav)); + return STREAM_UNSUPORTED; + } + + stream->sector_size = 2048; + stream->flags = STREAM_READ | STREAM_SEEK; + stream->fill_buffer = fill_buffer; + stream->seek = seek; + stream->close = stream_dvdnav_close; + stream->type = STREAMTYPE_DVDNAV; + stream->priv=(void*)dvdnav_priv; + *file_format = DEMUXER_TYPE_MPEG_PS; + + update_title_len(stream); + if(!stream->pos) + mp_msg(MSGT_OPEN,MSGL_ERR, "INIT ERROR: %d, couldn't get init pos %s\r\n", status, dvdnav_err_to_string(dvdnav_priv->dvdnav)); + + return STREAM_OK; +} + +stream_info_t stream_info_dvdnav = { + "DVDNAV stream", + "null", + "", + "", + open_s, + { "dvdnav", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/dvdnav_stream.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,46 @@ +#ifndef _MPLAYER_DVDNAV_STREAM_H +#define _MPLAYER_DVDNAV_STREAM_H + +#include <dvdnav.h> + +typedef struct { + int event; /* event number fromd dvdnav_events.h */ + void * details; /* event details */ + int len; /* bytes in details */ +} dvdnav_event_t; + +typedef struct { + dvdnav_t * dvdnav; /* handle to libdvdnav stuff */ + char * filename; /* path */ + int ignore_timers; /* should timers be skipped? */ + int sleeping; /* are we sleeping? */ + unsigned int sleep_until; /* timer */ + int started; /* Has mplayer initialization finished? */ + unsigned char prebuf[STREAM_BUFFER_SIZE]; /* prefill buffer */ + int prelen; /* length of prefill buffer */ +} dvdnav_priv_t; + +extern int dvd_nav_still; +extern int dvd_nav_skip_opening; +extern char dvd_nav_text[50]; +extern int osd_show_dvd_nav_delay; +extern int osd_show_dvd_nav_highlight; +extern int osd_show_dvd_nav_sx; +extern int osd_show_dvd_nav_ex; +extern int osd_show_dvd_nav_sy; +extern int osd_show_dvd_nav_ey; + +dvdnav_priv_t * new_dvdnav_stream(char * filename); +int dvdnav_stream_reset(dvdnav_priv_t * dvdnav_priv); +void free_dvdnav_stream(dvdnav_priv_t * dvdnav_priv); + +void dvdnav_stream_ignore_timers(dvdnav_priv_t * dvdnav_priv, int ignore); +int dvdnav_stream_read(dvdnav_priv_t * dvdnav_priv, unsigned char *buf, int *len); + +void dvdnav_stream_sleep(dvdnav_priv_t *dvdnav_priv, int seconds); +int dvdnav_stream_sleeping(dvdnav_priv_t * dvdnav_priv); + +void dvdnav_stream_fullstart(dvdnav_priv_t *dvdnav_priv); +unsigned int * dvdnav_stream_get_palette(dvdnav_priv_t * dvdnav_priv); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/common.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,226 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@suidzer0.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 +*/ + +/** + * @file common.c + * + * @short Implementation of routines common to parse and formatting + * modules . + * + * This file implements the routines that operate over data structures + * that are used in both the parse and formatting modules. + **/ + +#include "priv.h" +#include "common.h" + +static void +safe_free (void *ptr) +{ + if (ptr) + free (ptr); +} + +fsdp_description_t * +fsdp_description_new (void) +{ + fsdp_description_t *result = malloc (sizeof (fsdp_description_t)); + + result->version = 0; + result->o_username = result->o_session_id = + result->o_announcement_version = NULL; + result->o_network_type = FSDP_NETWORK_TYPE_UNDEFINED; + result->o_address_type = FSDP_ADDRESS_TYPE_UNDEFINED; + result->o_address = NULL; + result->s_name = NULL; + result->i_information = NULL; + result->u_uri = NULL; + result->emails = NULL; + result->emails_count = 0; + result->phones = NULL; + result->phones_count = 0; + /* At first, there is no session-level definition for these + parameters */ + result->c_network_type = FSDP_NETWORK_TYPE_UNDEFINED; + result->c_address_type = FSDP_ADDRESS_TYPE_UNDEFINED; + result->c_address.address = NULL; + /* there is no session-level definition for these parameters */ + result->bw_modifiers = NULL; + result->bw_modifiers_count = 0; + result->time_periods = NULL; + result->time_periods_count = 0; + result->timezone_adj = NULL; + result->k_encryption_method = FSDP_ENCRYPTION_METHOD_UNDEFINED; + result->k_encryption_content = NULL; + /* Default/undefined values for attributes */ + result->a_category = result->a_keywords = result->a_tool = NULL; + result->a_type = FSDP_SESSION_TYPE_UNDEFINED; + result->a_sendrecv_mode = FSDP_SENDRECV_UNDEFINED; + result->a_charset = NULL; + result->a_sdplangs = result->a_langs = NULL; + result->a_controls = NULL; + result->a_range = NULL; + result->a_rtpmaps = NULL; + result->a_rtpmaps_count = 0; + result->a_sdplangs_count = 0; + result->a_langs_count = 0; + result->a_controls_count = 0; + result->unidentified_attributes = NULL; + result->unidentified_attributes_count = 0; + result->media_announcements = NULL; + result->media_announcements_count = 0; + + return result; +} + +void +fsdp_description_delete (fsdp_description_t * dsc) +{ + fsdp_description_recycle (dsc); + safe_free (dsc); +} + +void +fsdp_description_recycle (fsdp_description_t * dsc) +{ + /* Recursively free all strings and arrays */ + unsigned int i, j; + + if (!dsc) + return; + + safe_free (dsc->o_username); + safe_free (dsc->o_session_id); + safe_free (dsc->o_announcement_version); + safe_free (dsc->o_address); + safe_free (dsc->s_name); + safe_free (dsc->i_information); + safe_free (dsc->u_uri); + + for (i = 0; i < dsc->emails_count; i++) + safe_free ((char *) dsc->emails[i]); + safe_free (dsc->emails); + + for (i = 0; i < dsc->phones_count; i++) + safe_free ((char *) dsc->phones[i]); + safe_free (dsc->phones); + + safe_free (dsc->c_address.address); + + for (i = 0; i < dsc->bw_modifiers_count; i++) + safe_free (dsc->bw_modifiers[i].b_unknown_bw_modt); + safe_free (dsc->bw_modifiers); + + for (i = 0; i < dsc->time_periods_count; i++) + { + for (j = 0; j < dsc->time_periods[i]->repeats_count; j++) + { + safe_free (dsc->time_periods[i]->repeats[j]->offsets); + safe_free (dsc->time_periods[i]->repeats[j]); + } + safe_free (dsc->time_periods[i]->repeats); + safe_free (dsc->time_periods[i]); + } + safe_free (dsc->time_periods); + + safe_free (dsc->timezone_adj); + safe_free (dsc->a_category); + safe_free (dsc->a_keywords); + safe_free (dsc->a_tool); + + for (i = 0; i < dsc->a_rtpmaps_count; i++) + safe_free (dsc->a_rtpmaps[i]); + safe_free (dsc->a_rtpmaps); + + safe_free (dsc->a_charset); + + for (i = 0; i < dsc->a_sdplangs_count; i++) + safe_free (dsc->a_sdplangs[i]); + safe_free (dsc->a_sdplangs); + + for (i = 0; i < dsc->a_langs_count; i++) + safe_free (dsc->a_langs[i]); + safe_free (dsc->a_langs); + + for (i = 0; i < dsc->a_controls_count; i++) + safe_free (dsc->a_controls[i]); + safe_free (dsc->a_controls); + + safe_free (dsc->a_range); + + for (i = 0; i < dsc->media_announcements_count; i++) + { + for (j = 0; j < dsc->media_announcements[i]->formats_count; j++) + safe_free (dsc->media_announcements[i]->formats[j]); + safe_free (dsc->media_announcements[i]->formats); + safe_free (dsc->media_announcements[i]->i_title); + + for (j = 0; j < dsc->media_announcements[i]->bw_modifiers_count; j++) + { + if (FSDP_BW_MOD_TYPE_UNKNOWN == + dsc->media_announcements[i]->bw_modifiers[j].b_mod_type) + safe_free (dsc->media_announcements[i]->bw_modifiers[j]. + b_unknown_bw_modt); + } + safe_free (dsc->media_announcements[i]->bw_modifiers); + + safe_free (dsc->media_announcements[i]->k_encryption_content); + + for (j = 0; j < dsc->media_announcements[i]->a_rtpmaps_count; j++) + { + safe_free (dsc->media_announcements[i]->a_rtpmaps[j]->pt); + safe_free (dsc->media_announcements[i]->a_rtpmaps[j]-> + encoding_name); + safe_free (dsc->media_announcements[i]->a_rtpmaps[j]->parameters); + safe_free (dsc->media_announcements[i]->a_rtpmaps[j]); + } + safe_free (dsc->media_announcements[i]->a_rtpmaps); + + for (j = 0; j < dsc->media_announcements[i]->a_sdplangs_count; j++) + safe_free (dsc->media_announcements[i]->a_sdplangs[j]); + safe_free (dsc->media_announcements[i]->a_sdplangs); + + for (j = 0; j < dsc->media_announcements[i]->a_langs_count; j++) + safe_free (dsc->media_announcements[i]->a_langs[j]); + safe_free (dsc->media_announcements[i]->a_langs); + + for (j = 0; j < dsc->media_announcements[i]->a_controls_count; j++) + safe_free (dsc->media_announcements[i]->a_controls[j]); + safe_free (dsc->media_announcements[i]->a_controls); + + for (j = 0; j < dsc->media_announcements[i]->a_fmtps_count; j++) + safe_free (dsc->media_announcements[i]->a_fmtps[j]); + safe_free (dsc->media_announcements[i]->a_fmtps); + + for (j = 0; + j < dsc->media_announcements[i]->unidentified_attributes_count; j++) + safe_free (dsc->media_announcements[i]->unidentified_attributes[j]); + safe_free (dsc->media_announcements[i]->unidentified_attributes); + safe_free (dsc->media_announcements[i]); + } + safe_free (dsc->media_announcements); + + /* This prevents the user to make the library crash when incorrectly + using recycled but not rebuilt descriptions */ + dsc->emails_count = 0; + dsc->phones_count = 0; + dsc->bw_modifiers_count = 0; + dsc->time_periods_count = 0; + dsc->media_announcements_count = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/common.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,352 @@ +/* + This file is part of FreeSDP. + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 +*/ + +/** + * @file common.h + * @ingroup common + * @short Public header common for both parsing and formatting modules. + **/ + +#ifndef FSDP_COMMON_H +#define FSDP_COMMON_H + +/* Macros to avoid name mangling when compiling with a C++ compiler */ +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +#include <sys/time.h> +#include <time.h> + +BEGIN_C_DECLS +/** + * @defgroup common FreeSDP Common Facilities + * + * Data types and routines common for both parsing and formatting + * modules. + **/ +/** @addtogroup common */ +/*@{*/ +/** + * @enum fsdp_error_t freesdp/common.h + * @short Error codes in the FreeSDP library. + * + * There is a FSDPE_MISSING_XXXX for each mandatory line, as + * FSDPE_MISSING_OWNER. This kind of error is reported when a + * mandatory description line, such as the owner line, is not found + * where it should be in the SDP description. There are also several + * error codes like FSDPE_INVALID_XXXX. These are returned when there + * is a recognized line in the parsed description that violates the + * SDP syntax or gives wrong parameters, for instance "c=foo bar", + * which would cause a FSDPE_INVALID_CONNECTION error code to be + * returned. + **/ +typedef enum +{ + FSDPE_OK = 0, + FSDPE_ILLEGAL_CHARACTER, /**< Misplaced '\r', '\n' or '\0' */ + FSDPE_MISSING_VERSION, /**< The first line is not like + v=... */ + FSDPE_INVALID_VERSION, /**< Parse error in version line, + perhaps, the version specified in + v=... is not valid for FreeSDP */ + FSDPE_MISSING_OWNER, /**< No owner line found in its + place */ + FSDPE_INVALID_OWNER, /**< Parse error in owner line */ + FSDPE_MISSING_NAME, /**< No session name found in its + place */ + FSDPE_EMPTY_NAME, /**< Empty session name line */ + + FSDPE_INVALID_CONNECTION, /**< Syntax error in connection + line */ + + FSDPE_INVALID_CONNECTION_ADDRTYPE, /**< Unrecognized address type in + connection line */ + FSDPE_INVALID_CONNECTION_NETTYPE, /**< Unrecognized network type in + connection line */ + FSDPE_INVALID_BANDWIDTH, /**< Parse error in bandwidth + line */ + FSDPE_MISSING_TIME, /**< No time period has been given + for the session */ + FSDPE_INVALID_TIME, /**< Parse error in time line */ + FSDPE_INVALID_REPEAT, /**< Parse error in repeat time + line */ + FSDPE_INVALID_TIMEZONE, /**< Parse error in timezone line */ + FSDPE_INVALID_ENCRYPTION_METHOD, /**< Unknown encryption method */ + FSDPE_INVALID_ATTRIBUTE, /**< Syntax error in an attribute + line */ + + FSDPE_INVALID_ATTRIBUTE_RTPMAP,/**< Parse error in a=rtpmap:... line */ + FSDPE_INVALID_SESSION_TYPE, /**< An unknown session type has been + specified in a `type:' + session-level attribute */ + + FSDPE_INVALID_MEDIA, /**< Parse error in media line */ + FSDPE_UNKNOWN_MEDIA_TYPE, /**< Unknown media type in media + line */ + + FSDPE_UNKNOWN_MEDIA_TRANSPORT, /**< A media transport has been + specified that is unknown */ + + FSDPE_OVERFILLED, /**< extra unknown lines are at the + end of the description */ + FSDPE_INVALID_LINE, /**< a line unknown to FreeSDP has been + found */ + FSDPE_MISSING_CONNECTION_INFO, /**< No connection information has + been provided for the whole + session nor one or more media */ + FSDPE_INVALID_INDEX, + /* FSDPE_MAXSIZE, description does not fit requested maximun size */ + FSDPE_INTERNAL_ERROR, + + FSDPE_INVALID_PARAMETER, /**< Some parameter of the called + FreeSDP routine has been given an + invalid value. This includes + cases such as NULL pointers. */ + FSDPE_BUFFER_OVERFLOW +} fsdp_error_t; + +/** + * @short Type of network + * + * Initially, SDP defines "Internet". New network types may be + * registered with IANA. However, the number of types is expected to + * be small and rarely extended. In addition, every new network type + * requires at least one new address type. + **/ +typedef enum +{ + FSDP_NETWORK_TYPE_UNDEFINED, /**< Not provided */ + FSDP_NETWORK_TYPE_INET /**< Internet */ +} fsdp_network_type_t; + +/** + * @short Type of address + * + * Initially, IPv4 and IPv6 are defined for the network type + * Internet. New address types may be registered with IANA. + **/ +typedef enum +{ + FSDP_ADDRESS_TYPE_UNDEFINED, /**< Not provided */ + FSDP_ADDRESS_TYPE_IPV4, /**< IP version 4 */ + FSDP_ADDRESS_TYPE_IPV6 /**< IP version 6 */ +} fsdp_address_type_t; + +/** + * @short Type of bandwith modifiers + * + * Bandwidth modifiers specify the meaning of the bandwidth + * value. Initially "Conference Total" and "Application Specific" are + * defined. Both use kilobits as bandwidth unit. "Conference Total" + * specifies that the bandwidth value is a proposed upper limit to the + * session bandwidth. "Application Specific" specifies thath the + * bandwidth value is the application concept of maximum bandwidth. + **/ +typedef enum +{ + FSDP_BW_MOD_TYPE_UNDEFINED, /**< Not provided */ + FSDP_BW_MOD_TYPE_UNKNOWN, /**< Unknown bandwidth + modifier (FreeSDP + ignores it) */ + FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL, /**< "CT - Conference Total" */ + FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC, /**< "AS - Application specific" */ + FSDP_BW_MOD_TYPE_RTCP_SENDERS, /**< "RS - RTCP bandwidth for + senders */ + FSDP_BW_MOD_TYPE_RTCP_RECEIVERS, /**< "RR - RTCP bandwidth for + receivers */ +} fsdp_bw_modifier_type_t; + +/** + * @short encryption method + * + * The encryption method specifies the way to get the encryption key. + **/ +typedef enum +{ + FSDP_ENCRYPTION_METHOD_UNDEFINED, /**< Not provided */ + FSDP_ENCRYPTION_METHOD_CLEAR, /**< The key field is the + untransformed key */ + FSDP_ENCRYPTION_METHOD_BASE64, /**< The key is base64 + encoded */ + FSDP_ENCRYPTION_METHOD_URI, /**< The key value provided is + a URI pointing to the actual + key */ + FSDP_ENCRYPTION_METHOD_PROMPT /**< The key is not provided + but should be got prompting + the user */ +} fsdp_encryption_method_t; + +/** + * @short Advised reception/transmission mode + * + * Depending on wheter sendrecv, recvonly, sendonly or inactive + * attribute is given, the tools used to participate in the session + * should be started in the corresponding transmission + * mode. FSDP_SENDRECV_SENDRECV is the default for sessions which are + * not of the conference type broadcast or H332. + **/ +typedef enum +{ + FSDP_SENDRECV_UNDEFINED, /**< Not specified */ + FSDP_SENDRECV_SENDRECV, /**< Send and receive */ + FSDP_SENDRECV_RECVONLY, /**< Receive only */ + FSDP_SENDRECV_SENDONLY, /**< Send only */ + FSDP_SENDRECV_INACTIVE /**< Do not send nor receive */ +} fsdp_sendrecv_mode_t; + +/** + * @short Values for `orient' media attribute. + * + * Normally used with whiteboard media, this attribute specifies the + * orientation of the whiteboard. + **/ +typedef enum +{ + FSDP_ORIENT_UNDEFINED, /**< Not specified */ + FSDP_ORIENT_PORTRAIT, /**< Portrait */ + FSDP_ORIENT_LANDSCAPE, /**< Landscape */ + FSDP_ORIENT_SEASCAPE /**< Upside down landscape */ +} fsdp_orient_t; + +/** + * @short Type of the conference + * + * The following types are initially defined: broadcast, meeting, + * moderated, test and H332. + **/ +typedef enum +{ + FSDP_SESSION_TYPE_UNDEFINED, /**< Not specified */ + FSDP_SESSION_TYPE_BROADCAST, /**< Broadcast session */ + FSDP_SESSION_TYPE_MEETING, /**< Meeting session */ + FSDP_SESSION_TYPE_MODERATED, /**< Moderated session */ + FSDP_SESSION_TYPE_TEST, /**< Test (do not display) */ + FSDP_SESSION_TYPE_H332 /**< H332 session */ +} fsdp_session_type_t; + +/** + * @short Media type + * + * The following types are defined initially: audio, video, + * application, data and control. + **/ +typedef enum +{ + FSDP_MEDIA_UNDEFINED, /**< Not specified */ + FSDP_MEDIA_VIDEO, /**< Video */ + FSDP_MEDIA_AUDIO, /**< Audio */ + FSDP_MEDIA_APPLICATION, /**< Application, such as whiteboard */ + FSDP_MEDIA_DATA, /**< bulk data */ + FSDP_MEDIA_CONTROL /**< Control channel */ +} fsdp_media_t; + +/** + * @short Transport protocol + * + * The transport protocol used depends on the address type. Initially, + * RTP over UDP Audio/Video Profile, and UDP are defined. + * + **/ +typedef enum +{ + FSDP_TP_UNDEFINED, /**< Not specified */ + FSDP_TP_RTP_AVP, /**< RTP Audio/Video Profile */ + FSDP_TP_UDP, /**< UDP */ + FSDP_TP_TCP, /**< TCP */ + FSDP_TP_UDPTL, /**< ITU-T T.38*/ + FSDP_TP_VAT, /**< old vat protocol (historic)*/ + FSDP_TP_OLD_RTP, /**< old rtp protocols (historic)*/ + FSDP_TP_H320 /**< TODO: add to the parser */ +} fsdp_transport_protocol_t; + +/** + * Session-level attributes whose value is specified as a character + * string in FreeSDP. These values are usually given to + * fsdp_get_strn_att() in order to get the corresponding value. + * + **/ +typedef enum +{ + FSDP_SESSION_STR_ATT_CATEGORY, + FSDP_SESSION_STR_ATT_KEYWORDS, + FSDP_SESSION_STR_ATT_TOOL, + FSDP_SESSION_STR_ATT_CHARSET, +} fsdp_session_str_att_t; + +/** + * @short FreeSDP SDP description media object. + * + * Object for media specific information in SDP descriptions. Each SDP + * description may include any number of media section. A + * fsdp_media_description_t object encapsulates the information in a + * media section, such as video, audio or whiteboard. + **/ +typedef struct fsdp_media_description_t_s fsdp_media_description_t; + +/** + * @short FreeSDP SDP session description object. + * + * Contains all the information extracted from a textual SDP + * description, including all the media announcements. + **/ +typedef struct fsdp_description_t_s fsdp_description_t; + +/** + * Allocates memory and initializes values for a new + * fsdp_description_t object. If you call this routine, do not forget + * about <code>fsdp_description_delete()</code> + * + * @return new fsdp_description_t object + **/ +fsdp_description_t *fsdp_description_new (void); + +/** + * Destroys a fsdp_description_t object. + * + * @param dsc pointer to the fsdp_description_t object to delete. + **/ +void fsdp_description_delete (fsdp_description_t * dsc); + +/** + * Calling this function over a description is equivalent to calling + * fsdp_description_delete and then fsdp_description_delete. This + * function is however more suitable and efficient for description + * processing loops. + * + * @param dsc pointer to the fsdp_description_t object to + * renew/recycle. + **/ +void fsdp_description_recycle (fsdp_description_t * dsc); + +/** + * * Returns a string correspondent to the error number. + * * + * * @param err_no error number. + * **/ +const char *fsdp_strerror (fsdp_error_t err_no); + + /*@}*//* closes addtogroup common */ + +END_C_DECLS +#endif /* FSDP_COMMON_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/errorlist.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,72 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001, 2002 Federico Montesino Pouzols <fedemp@suidzer0.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 +*/ + +/** + * @file errorlist.c + * + * @short Translation table for error numbers + * + */ + +#ifndef FSDP_ERRORLIST_C +#define FSDP_ERRORLIST_C + +#include "common.h" + +const char *fsdp_error_t_s[] = { + "No error",/** FSDPE_OK **/ + "Illegal character detected",/** FSDPE_ILLEGAL_CHARACTER **/ + "Missing version item", /** FSDPE_MISSING_VERSION **/ + "Invalid version item", /** FSDPE_INVALID_VERSION **/ + "Owner item not present", /** FSDPE_MISSING_OWNER **/ + "Parse error in owner item", /** FSDPE_INVALID_OWNER **/ + "Session name not present", /** FSDPE_MISSING_NAME **/ + "Empty session name item", /** FSDPE_EMPTY_NAME **/ + "Syntax error in connection item", /** FSDPE_INVALID_CONNECTION **/ + "Unrecognized address type in connection item", /** FSDPE_INVALID_CONNECTION_ADDRTYPE **/ + "Unrecognized network type in connection item", /** FSDPE_INVALID_CONNECTION_NETTYPE **/ + "Parse error in bandwith item", /** FSDPE_INVALID_BANDWIDTH **/ + "No time period for the session", /** FSDPE_MISSING_TIME **/ + "Parse error in time item", /** FSDPE_INVALID_TIME **/ + "Parse error in repeat time item", /** FSDPE_INVALID_REPEAT **/ + "Parse error in timezone item", /** FSDPE_INVALID_TIMEZONE **/ + "Unknown encryption method", /** FSDPE_INVALID_ENCRYPTION_METHOD **/ + "Syntax error in an attribute item", /** FSDPE_INVALID_ATTRIBUTE **/ + "Syntax error in an rtpmap attribute item", /** FSDPE_INVALID_ATTRIBUTE_RTPMAP **/ + "Unknown session type in a session-level attribute", /** FSDPE_INVALID_SESSION_TYPE **/ + "Parse error in media item", /** FSDPE_INVALID_MEDIA **/ + "Unknown media type in media item", /** FSDPE_UNKNOWN_MEDIA_TYPE **/ + "Unknown media transport", /** FSDPE_UNKNOWN_MEDIA_TRANSPORT **/ + "Unknown extra lines in description item", /** FSDPE_OVERFILLED **/ + "Unknown line found", /** FSDPE_INVALID_LINE **/ + "No connection information provided", /** FSDPE_MISSING_CONNECTION_INFO **/ + "Description item does not fit in MAXSIZE", /** FSDPE_INVALID_INDEX **/ + "Internal error", /** FSDPE_INTERNAL_ERROR **/ + "Invalid function parameters", /** FSDPE_INVALID_PARAMETER **/ + "Buffer overflow" /** FSDPE_BUFFER_OVERFLOW **/ +}; + + +const char * +fsdp_strerror (fsdp_error_t err_no) +{ + return (fsdp_error_t_s[err_no]); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/parser.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,1958 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + Benjamin Zores, (C) 2006 + added support in parser for the a=control: lines. + added support in parser for the a=range: lines. +*/ + +/** + * @file parser.c + * + * @short Parsing module implementation. + * + * This file implements the parsing routine <code>fsdp_parse</code> + * and the <code>fsdp_get_xxxx</code> routines that allow to get the + * session properties from a session description object build through + * the application of <code>fsdp_parse</code> to a textual SDP session + * description. + **/ + +#include "parserpriv.h" + +/** + * Moves the <code>c<code> pointer up to the beginning of the next + * line. + * + * @param c char pointer to pointer + * @retval FSDPE_ILLEGAL_CHARACTER, when an illegal '\r' character + * (not followed by a '\n') is found, returns + */ +#define NEXT_LINE(c) \ +({ \ + while ((*(c) != '\0') && (*(c) != '\r') && (*(c) != '\n')) { \ + (c)++; \ + } \ + if (*(c) == '\n') { \ + (c)++; \ + } else if (*(c) == '\r') { \ + (c)++; \ + if (*(c) == '\n') { \ + (c)++; \ + } else { \ + return FSDPE_ILLEGAL_CHARACTER; \ + } \ + } \ +}) + +fsdp_error_t +fsdp_parse (const char *text_description, fsdp_description_t * dsc) +{ + fsdp_error_t result; + const char *p = text_description, *p2; + unsigned int index, j; + /* temps for sscanf */ + const unsigned int TEMPCHARS = 6; + char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN]; + char longfsdp_buf[MAXLONGFIELDLEN]; + const unsigned int TEMPINTS = 2; + unsigned long int wuint[TEMPINTS]; + + if ((NULL == text_description) || (NULL == dsc)) + return FSDPE_INVALID_PARAMETER; + + /***************************************************************************/ + /* A) parse session-level description */ + /***************************************************************************/ + + /* `v=' line (protocol version) */ + /* according to the RFC, only `v=0' is valid */ + if (sscanf (p, "v=%1lu", &wuint[0])) + { + if (wuint[0] != 0) + return FSDPE_INVALID_VERSION; + } + else + { + return FSDPE_MISSING_VERSION; + } + NEXT_LINE (p); + + /* `o=' line (owner/creator and session identifier) */ + /* o=<username> <session id> <version> <network type> <address type> + <address> */ + if (!strncmp (p, "o=", 2)) + { + p += 2; + /* note that the following max lengths may vary in the future and + are quite arbitary */ + if (sscanf + (p, + "%" MSFLENS "[\x21-\xFF] %" MSFLENS "[0-9] %" MSFLENS + "[0-9] %2s %3s %" MSFLENS "s", fsdp_buf[0], fsdp_buf[1], + fsdp_buf[2], fsdp_buf[3], fsdp_buf[4], fsdp_buf[5]) != 6) + return FSDPE_INVALID_OWNER; + dsc->o_username = strdup (fsdp_buf[0]); + dsc->o_session_id = strdup (fsdp_buf[1]); + dsc->o_announcement_version = strdup (fsdp_buf[2]); + if (!strncmp (fsdp_buf[3], "IN", 2)) + { + dsc->o_network_type = FSDP_NETWORK_TYPE_INET; + if (!strncmp (fsdp_buf[4], "IP4", 3)) + dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV4; + else if (!strncmp (fsdp_buf[4], "IP6", 3)) + dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV6; + else + return FSDPE_INVALID_OWNER; + } + else + { + return FSDPE_INVALID_OWNER; + } + /* TODO? check valid unicast address/FQDN */ + dsc->o_address = strdup (fsdp_buf[5]); + } + else + { + return FSDPE_MISSING_OWNER; + } + NEXT_LINE (p); + + /* `s=' line (session name) -note that the name string cannot be empty */ + /* s=<session name> */ + if (!strncmp (p, "s=", 2)) + { + if (sscanf (p, "s=%" MLFLENS "[^\r\n]", longfsdp_buf) < 1) + return FSDPE_EMPTY_NAME; + dsc->s_name = strdup (longfsdp_buf); + } + else + { + return FSDPE_MISSING_NAME; + } + NEXT_LINE (p); + + /* `i=' line (session information) [optional] */ + /* i=<session description> */ + if (!strncmp (p, "i=", 2) + && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf)) + { + dsc->i_information = strdup (longfsdp_buf); + NEXT_LINE (p); + } + else + { + /* (optional) information absent */ + } + + /* `u=' line (URI of description) [optional] */ + /* u=<URI> */ + if (!strncmp (p, "u=", 2) + && sscanf (p, "u=%" MLFLENS "[^\r\n]", longfsdp_buf)) + { + /* TODO? check valid uri */ + dsc->u_uri = strdup (longfsdp_buf); + NEXT_LINE (p); + } + else + { + /* (optional) uri absent */ + } + + /* `e=' lines (email address) [zero or more] */ + /* e=<email address> */ + p2 = p; + j = 0; + while (!strncmp (p2, "e=", 2)) + { + /* First, count how many emails are there */ + j++; + NEXT_LINE (p2); + } + dsc->emails_count = j; + if (dsc->emails_count > 0) + { + /* Then, build the array of emails */ + dsc->emails = calloc (j, sizeof (const char *)); + for (j = 0; j < dsc->emails_count; j++) + { + sscanf (p, "e=%" MLFLENS "[^\r\n]", longfsdp_buf); + /* TODO? check valid email-address. */ + dsc->emails[j] = strdup (longfsdp_buf); + NEXT_LINE (p); + } + } + + /* `p=' lines (phone number) [zero or more] */ + /* p=<phone number> */ + j = 0; + /* assert ( p2 == p ); */ + while (!strncmp (p2, "p=", 2)) + { + j++; + NEXT_LINE (p2); + } + dsc->phones_count = j; + if (dsc->phones_count > 0) + { + dsc->phones = calloc (j, sizeof (const char *)); + for (j = 0; j < dsc->phones_count; j++) + { + sscanf (p, "p=%" MLFLENS "[^\r\n]", longfsdp_buf); + /* TODO? check valid phone-number. */ + dsc->phones[j] = strdup (longfsdp_buf); + NEXT_LINE (p); + } + } + + /* `c=' line (connection information - not required if included in all media) [optional] */ + /* c=<network type> <address type> <connection address> */ + result = fsdp_parse_c (&p, &(dsc->c_network_type), &(dsc->c_address_type), + &(dsc->c_address)); + if (FSDPE_OK != result) + return result; + + /* `b=' lines (bandwidth information) [optional] */ + /* b=<modifier>:<bandwidth-value> */ + result = + fsdp_parse_b (&p, &(dsc->bw_modifiers), &(dsc->bw_modifiers_count)); + if (FSDPE_OK != result) + return result; + + /* A.1) Time descriptions: */ + + /* `t=' lines (time the session is active) [1 or more] */ + /* t=<start time> <stop time> */ + j = 0; + p2 = p; + while (!strncmp (p2, "t=", 2)) + { + j++; + NEXT_LINE (p2); + while (!strncmp (p2, "r=", 2)) + NEXT_LINE (p2); + } + dsc->time_periods_count = j; + if (dsc->time_periods_count == 0) + return FSDPE_MISSING_TIME; + dsc->time_periods = calloc (dsc->time_periods_count, + sizeof (fsdp_time_period_t *)); + index = 0; + for (j = 0; j < dsc->time_periods_count; j++) + { + unsigned int h = 0; + if (sscanf (p, "t=%10lu %10lu", &wuint[0], &wuint[1]) != 2) + { + /* not all periods have been successfully parsed */ + dsc->time_periods_count = j; + return FSDPE_INVALID_TIME; + } + dsc->time_periods[j] = calloc (1, sizeof (fsdp_time_period_t)); + + /* convert from NTP to time_t time */ + if (wuint[0] != 0) + wuint[0] -= NTP_EPOCH_OFFSET; + if (wuint[1] != 0) + wuint[1] -= NTP_EPOCH_OFFSET; + dsc->time_periods[j]->start = wuint[0]; + dsc->time_periods[j]->stop = wuint[1]; + NEXT_LINE (p); + + /* `r' lines [zero or more repeat times for each t=] */ + /*r=<repeat interval> <active duration> <list of offsets from + start-time> */ + p2 = p; + while (!strncmp (p2, "r=", 2)) + { + h++; + NEXT_LINE (p2); + } + dsc->time_periods[j]->repeats_count = h; + if (h > 0) + { + unsigned int index2 = 0; + dsc->time_periods[j]->repeats = + calloc (h, sizeof (fsdp_repeat_t *)); + for (h = 0; h < dsc->time_periods[j]->repeats_count; h++) + { + /* + get_repeat_values(p,&(dsc->time_periods[index].repeats[index2])); + fsdp_error_t get_repeat_values (const char *r, fsdp_repeat_t + *repeat); + */ + if (sscanf (p, "r=%10s %10s %" MLFLENS "[^\r\n]", + fsdp_buf[0], fsdp_buf[1], longfsdp_buf) == 3) + { + fsdp_repeat_t *repeat; + dsc->time_periods[j]->repeats[h] = + calloc (1, sizeof (fsdp_repeat_t)); + repeat = dsc->time_periods[j]->repeats[h]; + /* get interval, duration and list of offsets */ + result = + fsdp_repeat_time_to_uint (fsdp_buf[0], + &(repeat->interval)); + if (result == FSDPE_OK) + { + result = + fsdp_repeat_time_to_uint (fsdp_buf[1], + &(repeat->duration)); + if (result == FSDPE_OK) + { + unsigned int k = 1; + const char *i = longfsdp_buf; + while (NULL != (i = strchr (i, ' '))) + { + k++; + if (NULL != i) + i++; + } + repeat->offsets_count = k; + repeat->offsets = calloc (k, sizeof (time_t)); + i = longfsdp_buf; + for (k = 0; + (k < repeat->offsets_count) + && (result == FSDPE_OK); k++) + { + result = + fsdp_repeat_time_to_uint (i, + &(repeat-> + offsets[k])); + i = strchr (i, ' '); + if (NULL != i) + i++; + } + if (k < repeat->offsets_count) + { + /* there where invalid repeat offsets */ + dsc->time_periods[j]->repeats_count = k; + return FSDPE_INVALID_REPEAT; + } + } + } + if (result != FSDPE_OK) + { + /* not all repeats have been succesfully parsed */ + dsc->time_periods[j]->repeats_count = h; + return FSDPE_INVALID_REPEAT; + } + NEXT_LINE (p); + } + else + { + /* not all repeats have been succesfully parsed */ + dsc->time_periods[j]->repeats_count = h; + return FSDPE_INVALID_REPEAT; + } + index2++; + } + } + } + + /* `z=' line (time zone adjustments) [zero or more] */ + /* z=<adjustment time> <offset> <adjustment time> <offset> .... */ + if (!strncmp (p, "z=", 2)) + { + if (sscanf (p, "z=%" MLFLENS "[^\r\n]", longfsdp_buf)) + { + /* TODO: guess how many pairs are there and process them */ + dsc->timezone_adj = strdup (longfsdp_buf); + NEXT_LINE (p); + } + else + { + return FSDPE_INVALID_TIMEZONE; + } + } + + /* `k=' line (encryption key) [optional] */ + /* k=<method> + k=<method>:<encryption key> */ + result = fsdp_parse_k (&p, &(dsc->k_encryption_method), + &(dsc->k_encryption_content)); + if (result != FSDPE_OK) + return result; + + /* A.2) Attributes */ + /* `a=' lines (session attribute) [0 or more] */ + /* a=<attribute> + a=<attribute>:<value> */ + while (!strncmp (p, "a=", 2)) + { + /* The "9" lenght specifier of the first string is subject to + changes */ + if (sscanf + (p, "a=%9[^:\r\n]:%" MSFLENS "[^\r\n]", fsdp_buf[0], + fsdp_buf[1]) == 2) + { + /* session-level value attributes */ + if (!strncmp (fsdp_buf[0], "cat", 3)) + dsc->a_category = strdup (fsdp_buf[1]); + else if (!strncmp (fsdp_buf[0], "keywds", 6)) + dsc->a_keywords = strdup (fsdp_buf[1]); + else if (!strncmp (fsdp_buf[0], "tool", 4)) + dsc->a_keywords = strdup (fsdp_buf[1]); + else if (!strncmp (fsdp_buf[0], "rtpmap", 6)) + fsdp_parse_rtpmap (&(dsc->a_rtpmaps), + &(dsc->a_rtpmaps_count), fsdp_buf[1]); + else if (!strncmp (fsdp_buf[0], "type", 4)) + { + if (!strncmp (fsdp_buf[1], "broadcast", 9)) + dsc->a_type = FSDP_SESSION_TYPE_BROADCAST; + else if (!strncmp (fsdp_buf[1], "meeting", 7)) + dsc->a_type = FSDP_SESSION_TYPE_MEETING; + else if (!strncmp (fsdp_buf[1], "moderated", 9)) + dsc->a_type = FSDP_SESSION_TYPE_MODERATED; + else if (!strncmp (fsdp_buf[1], "test", 4)) + dsc->a_type = FSDP_SESSION_TYPE_TEST; + else if (!strncmp (fsdp_buf[1], "H332", 4)) + dsc->a_type = FSDP_SESSION_TYPE_H332; + else + return FSDPE_INVALID_SESSION_TYPE; + } + else if (!strncmp (fsdp_buf[0], "charset", 7)) + dsc->a_charset = strdup (fsdp_buf[1]); + else if (!strncmp (fsdp_buf[0], "sdplang", 7)) + { + if (NULL == dsc->a_sdplangs) + { + dsc->a_sdplangs_count = 0; + dsc->a_sdplangs = + calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); + } + if (dsc->a_sdplangs_count < SDPLANGS_MAX_COUNT) + { + dsc->a_sdplangs[dsc->a_sdplangs_count] = + strdup (fsdp_buf[1]); + dsc->a_sdplangs_count++; + } + } + else if (!strncmp (fsdp_buf[0], "lang", 4)) + { + if (NULL == dsc->a_langs) + { + dsc->a_langs_count = 0; + dsc->a_langs = calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); + } + if (dsc->a_langs_count < SDPLANGS_MAX_COUNT) + { + dsc->a_langs[dsc->a_langs_count] = strdup (fsdp_buf[1]); + dsc->a_langs_count++; + } + } + else if (!strncmp (fsdp_buf[0], "control", 7)) + { + if (NULL == dsc->a_controls) + { + dsc->a_controls_count = 0; + dsc->a_controls = + calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *)); + } + if (dsc->a_controls_count < SDPCONTROLS_MAX_COUNT) + { + dsc->a_controls[dsc->a_controls_count] = + strdup (fsdp_buf[1]); + dsc->a_controls_count++; + } + } + else if (!strncmp (fsdp_buf[0], "range", 5)) + { + if (dsc->a_range) + free (dsc->a_range); + dsc->a_range = strdup (fsdp_buf[1]); + } + else + { + /* ignore unknown attributes, but provide access to them */ + *longfsdp_buf = '\0'; + strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); + strncat (longfsdp_buf, ":", MAXLONGFIELDLEN); + strncat (longfsdp_buf, fsdp_buf[1], MAXLONGFIELDLEN); + if (NULL == dsc->unidentified_attributes) + { + dsc->unidentified_attributes_count = 0; + dsc->unidentified_attributes = + calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, + sizeof (char *)); + } + if (dsc->unidentified_attributes_count < + UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) + { + dsc->unidentified_attributes + [dsc->unidentified_attributes_count] = + strdup (longfsdp_buf); + dsc->unidentified_attributes_count++; + } + } + NEXT_LINE (p); + } + else if (sscanf (p, "a=%20s", fsdp_buf[0]) == 1) + { + /* session-level property attributes */ + if (!strncmp (fsdp_buf[0], "recvonly", 8)) + dsc->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY; + else if (!strncmp (fsdp_buf[0], "sendonly", 8)) + dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY; + else if (!strncmp (fsdp_buf[0], "inactive", 8)) + dsc->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE; + else if (!strncmp (fsdp_buf[0], "sendrecv", 8)) + dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV; + else + { + /* ignore unknown attributes, but provide access to them */ + *longfsdp_buf = '\0'; + strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); + if (NULL == dsc->unidentified_attributes) + { + dsc->unidentified_attributes_count = 0; + dsc->unidentified_attributes = + calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, + sizeof (char *)); + } + if (dsc->unidentified_attributes_count < + UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) + { + dsc->unidentified_attributes + [dsc->unidentified_attributes_count] = + strdup (longfsdp_buf); + dsc->unidentified_attributes_count++; + } + } + NEXT_LINE (p); + } + else + return FSDPE_INVALID_ATTRIBUTE; + } + + /***************************************************************************/ + /* B) parse media-level descriptions */ + /***************************************************************************/ + p2 = p; + j = 0; + while ((*p2 != '\0') && !strncmp (p2, "m=", 2)) + { + char c; + j++; + NEXT_LINE (p2); + while (sscanf (p2, "%c=", &c) == 1) + { + if (c == 'i' || c == 'c' || c == 'b' || c == 'k' || c == 'a') + { + NEXT_LINE (p2); + } + else if (c == 'm') + { + break; + } + else + { + return FSDPE_INVALID_LINE; + } + } + } + dsc->media_announcements_count = j; + if (dsc->media_announcements_count == 0) + { + ; + /*return FSDPE_MISSING_MEDIA; */ + } + else + { /* dsc->media_announcements_count > 0 */ + dsc->media_announcements = + calloc (j, sizeof (fsdp_media_announcement_t *)); + for (j = 0; j < dsc->media_announcements_count; j++) + { + fsdp_media_announcement_t *media = NULL; + /* `m=' line (media name, transport address and format list) */ + /* m=<media> <port> <transport> <fmt list> */ + /* The max. string lengths are subject to change */ + if (sscanf (p, "m=%11s %8s %7s %" MLFLENS "[^\r\n]", + fsdp_buf[0], fsdp_buf[1], fsdp_buf[2], + longfsdp_buf) != 4) + { + return FSDPE_INVALID_MEDIA; + } + else + { + dsc->media_announcements[j] = + calloc (1, sizeof (fsdp_media_announcement_t)); + media = dsc->media_announcements[j]; + if (!strncmp (fsdp_buf[0], "audio", 5)) + media->media_type = FSDP_MEDIA_AUDIO; + else if (!strncmp (fsdp_buf[0], "video", 5)) + media->media_type = FSDP_MEDIA_VIDEO; + else if (!strncmp (fsdp_buf[0], "application", 11)) + media->media_type = FSDP_MEDIA_APPLICATION; + else if (!strncmp (fsdp_buf[0], "data", 4)) + media->media_type = FSDP_MEDIA_DATA; + else if (!strncmp (fsdp_buf[0], "control", 7)) + media->media_type = FSDP_MEDIA_CONTROL; + else + return FSDPE_UNKNOWN_MEDIA_TYPE; + { /* try to get port specification as port/number */ + char *slash; + if ((slash = strchr (fsdp_buf[1], '/'))) + { + *slash = '\0'; + slash++; + media->port = strtol (fsdp_buf[1], NULL, 10); + media->port_count = strtol (slash, NULL, 10); + } + else + { + media->port = strtol (fsdp_buf[1], NULL, 10); + media->port_count = 0; + } + } + if (!strncmp (fsdp_buf[2], "RTP/AVP", 7)) + media->transport = FSDP_TP_RTP_AVP; + else if (!strncmp (fsdp_buf[2], "udp", 3)) + media->transport = FSDP_TP_UDP; + else if (!strncmp (fsdp_buf[2], "TCP", 3)) + media->transport = FSDP_TP_TCP; + else if (!strncmp (fsdp_buf[2], "UDPTL", 5)) + media->transport = FSDP_TP_UDPTL; + else if (!strncmp (fsdp_buf[2], "vat", 3)) + media->transport = FSDP_TP_VAT; + else if (!strncmp (fsdp_buf[2], "rtp", 3)) + media->transport = FSDP_TP_OLD_RTP; + else + return FSDPE_UNKNOWN_MEDIA_TRANSPORT; + { + unsigned int k = 0; + char *s = longfsdp_buf; + while (NULL != (s = strchr (s, ' '))) + { + k++; + if (NULL != s) + s++; + } + k++; /* when there is no space left, count the last format */ + media->formats_count = k; + media->formats = calloc (k, sizeof (char *)); + s = longfsdp_buf; + for (k = 0; k < media->formats_count; k++) + { + char *space = strchr (s, ' '); + if (NULL != space) + *space = '\0'; + media->formats[k] = strdup (s); + s = space + 1; + } + } + NEXT_LINE (p); + } + + /* `i=' line (media title) [optional] */ + /* i=<media title> */ + if (!strncmp (p, "i=", 2) + && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf)) + { + media->i_title = strdup (longfsdp_buf); + NEXT_LINE (p); + } + else + { + /* (optional) information absent */ + } + + /* `c=' line (connection information - overrides session-level + line) [optional if provided at session-level] */ + /* c=<network type> <address type> <connection address> */ + result = fsdp_parse_c (&p, &(media->c_network_type), + &(media->c_address_type), + &(media->c_address)); + if (result != FSDPE_OK) + return result; + + /* `b=' lines (bandwidth information) [optional] */ + /* b=<modifier>:<bandwidth-value> */ + result = fsdp_parse_b (&p, &(media->bw_modifiers), + &(media->bw_modifiers_count)); + if (FSDPE_OK != result) + return result; + + /* `k=' line (encryption key) [optional] */ + /* k=<method> + k=<method>:<encryption key> */ + result = fsdp_parse_k (&p, &(media->k_encryption_method), + &(media->k_encryption_content)); + if (result != FSDPE_OK) + return result; + + /* B.1) Attributes */ + + /* `a=' lines (zero or more media attribute lines) [optional] */ + /* a=<attribute> + a=<attribute>:<value> */ + while (!strncmp (p, "a=", 2)) + { + if (sscanf + (p, "a=%9[^:\r\n]:%" MLFLENS "[^\r\n]", fsdp_buf[0], + longfsdp_buf) == 2) + { + /* media-level value attributes */ + if (!strncmp (fsdp_buf[0], "ptime", 5)) + media->a_ptime = strtoul (longfsdp_buf, NULL, 10); + else if (!strncmp (fsdp_buf[0], "maxptime", 8)) + media->a_maxptime = strtoul (longfsdp_buf, NULL, 10); + else if (!strncmp (fsdp_buf[0], "rtpmap", 6)) + fsdp_parse_rtpmap (&(media->a_rtpmaps), + &(media->a_rtpmaps_count), + longfsdp_buf); + else if (!strncmp (fsdp_buf[0], "orient", 6)) + { + if (!strncmp (longfsdp_buf, "portrait", 8)) + media->a_orient = FSDP_ORIENT_PORTRAIT; + else if (!strncmp (longfsdp_buf, "landscape", 9)) + media->a_orient = FSDP_ORIENT_LANDSCAPE; + else if (!strncmp (longfsdp_buf, "seascape", 9)) + media->a_orient = FSDP_ORIENT_SEASCAPE; + } + else if (!strncmp (fsdp_buf[0], "sdplang", 7)) + { + if (NULL == dsc->a_sdplangs) + { + media->a_sdplangs_count = 0; + media->a_sdplangs = + calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); + } + if (media->a_sdplangs_count < SDPLANGS_MAX_COUNT) + { + media->a_sdplangs[dsc->a_sdplangs_count] = + strdup (longfsdp_buf); + media->a_sdplangs_count++; + } + } + else if (!strncmp (fsdp_buf[0], "lang", 4)) + { + if (NULL == dsc->a_langs) + { + media->a_langs_count = 0; + media->a_langs = + calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); + } + if (media->a_langs_count < SDPLANGS_MAX_COUNT) + { + media->a_langs[dsc->a_langs_count] = + strdup (longfsdp_buf); + media->a_langs_count++; + } + } + else if (!strncmp (fsdp_buf[0], "control", 7)) + { + if (NULL == media->a_controls) + { + media->a_controls_count = 0; + media->a_controls = + calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *)); + } + if (media->a_controls_count < SDPCONTROLS_MAX_COUNT) + { + media->a_controls[media->a_controls_count] = + strdup (longfsdp_buf); + media->a_controls_count++; + } + } + else if (!strncmp (fsdp_buf[0], "range", 5)) + { + if (media->a_range) + free (media->a_range); + media->a_range = strdup (fsdp_buf[1]); + } + else if (!strncmp (fsdp_buf[0], "framerate", 9)) + media->a_framerate = strtod (longfsdp_buf, NULL); + else if (!strncmp (fsdp_buf[0], "fmtp", 4)) + { + if (NULL == media->a_fmtps) + { + media->a_fmtps_count = 0; + media->a_fmtps = + calloc (SDPLANGS_MAX_COUNT, sizeof (char *)); + } + if (media->a_fmtps_count < SDPLANGS_MAX_COUNT) + { + media->a_fmtps[media->a_fmtps_count] = + strdup (longfsdp_buf); + media->a_fmtps_count++; + } + } + else if (!strncmp (fsdp_buf[0], "rtcp", 4)) + { + int opts = 0; + /* rtcp attribute: a=rtcp:<port> <nettype> <addrtype> <address> */ + opts = + sscanf (longfsdp_buf, "%lu %2s %3s %" MSFLENS "s", + &wuint[0], fsdp_buf[0], fsdp_buf[1], + fsdp_buf[2]); + if (opts >= 1) + { + media->a_rtcp_port = wuint[0]; + if (opts >= 2) + { + if (!strncmp (fsdp_buf[0], "IN", 2)) + { + media->a_rtcp_network_type = + FSDP_NETWORK_TYPE_INET; + } /* else + ; TODO: define error code? */ + if (opts >= 3) + { + if (!strncmp (fsdp_buf[1], "IP4", 3)) + media->a_rtcp_address_type = + FSDP_ADDRESS_TYPE_IPV4; + else if (!strncmp (fsdp_buf[1], "IP6", 3)) + media->a_rtcp_address_type = + FSDP_ADDRESS_TYPE_IPV6; + else + return FSDPE_INVALID_CONNECTION_NETTYPE; + /*add specific code? */ + if (opts >= 4) + media->a_rtcp_address = + strdup (fsdp_buf[2]); + } + } + } + } + else + { + /* ignore unknown attributes, but provide access to them */ + *fsdp_buf[1] = '\0'; + strncat (fsdp_buf[1], fsdp_buf[0], MAXLONGFIELDLEN); + strncat (fsdp_buf[1], ":", MAXLONGFIELDLEN); + strncat (fsdp_buf[1], longfsdp_buf, MAXLONGFIELDLEN); + if (NULL == media->unidentified_attributes) + { + media->unidentified_attributes_count = 0; + media->unidentified_attributes = + calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, + sizeof (char *)); + } + if (media->unidentified_attributes_count < + UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) + { + media->unidentified_attributes + [media->unidentified_attributes_count] = + strdup (fsdp_buf[1]); + media->unidentified_attributes_count++; + } + } + NEXT_LINE (p); + } + else if (sscanf (p, "a=%8s", fsdp_buf[0]) == 1) + { + /* media-level property attributes */ + if (!strncmp (fsdp_buf[0], "recvonly", 8)) + media->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY; + else if (!strncmp (fsdp_buf[0], "sendonly", 8)) + media->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY; + else if (!strncmp (fsdp_buf[0], "inactive", 8)) + media->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE; + else if (!strncmp (fsdp_buf[0], "sendrecv", 8)) + media->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV; + else + { + /* ignore unknown attributes, but provide access to them */ + *longfsdp_buf = '\0'; + strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN); + if (NULL == media->unidentified_attributes) + { + media->unidentified_attributes_count = 0; + media->unidentified_attributes = + calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT, + sizeof (char *)); + } + if (media->unidentified_attributes_count < + UNIDENTIFIED_ATTRIBUTES_MAX_COUNT) + { + media->unidentified_attributes + [media->unidentified_attributes_count] = + strdup (longfsdp_buf); + media->unidentified_attributes_count++; + } + } + NEXT_LINE (p); + } + else + return FSDPE_INVALID_ATTRIBUTE; + } + } /* end of for */ + } + + /* Check c= has been given at session level or at media level for + all media */ + if (NULL == dsc->c_address.address) + { + unsigned int c; + for (c = 0; c < dsc->media_announcements_count; c++) + if (NULL == dsc->media_announcements[c]->c_address.address) + return FSDPE_MISSING_CONNECTION_INFO; + } + + /* finish */ + if (*p == '\0') + return FSDPE_OK; + else + return FSDPE_OVERFILLED; +} + +static fsdp_error_t +fsdp_parse_c (const char **p, fsdp_network_type_t * ntype, + fsdp_address_type_t * atype, + fsdp_connection_address_t * address) +{ + const unsigned int TEMPCHARS = 3; + char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN]; + + if (!strncmp (*p, "c=", 2)) + { + if (sscanf (*p, "c=%2s %3s %" MSFLENS "s", + fsdp_buf[0], fsdp_buf[1], fsdp_buf[2])) + { + if (!strncmp (fsdp_buf[0], "IN", 2)) + { + *ntype = FSDP_NETWORK_TYPE_INET; + if (!strncmp (fsdp_buf[1], "IP4", 3)) + *atype = FSDP_ADDRESS_TYPE_IPV4; + else if (!strncmp (fsdp_buf[1], "IP6", 3)) + *atype = FSDP_ADDRESS_TYPE_IPV6; + else + return FSDPE_INVALID_CONNECTION_NETTYPE; + } + else + { + return FSDPE_INVALID_CONNECTION_ADDRTYPE; + } + { + char *slash = strchr (fsdp_buf[2], '/'); + if (NULL == slash) + { + address->address = strdup (fsdp_buf[2]); + address->address_ttl = 0; + address->address_count = 0; + } + else + { + /* address is IP4 multicast */ + char *slash2; + *slash = '\0'; + slash++; + address->address = strdup (fsdp_buf[2]); + slash2 = strchr (slash + 1, '/'); + if (NULL == slash2) + { + address->address_ttl = strtol (slash, NULL, 10); + address->address_count = 0; + } + else + { + *slash2 = '\0'; + slash2++; + address->address_ttl = strtol (slash, NULL, 10); + address->address_count = strtol (slash2, NULL, 10); + } + } + } + NEXT_LINE (*p); + } + else + { + return FSDPE_INVALID_CONNECTION; + } + } + return FSDPE_OK; +} + +static fsdp_error_t +fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers, + unsigned int *bw_modifiers_count) +{ + char fsdp_buf[MAXSHORTFIELDLEN]; + unsigned long int wuint; + unsigned int i = 0; + char *lp = (char *) *p; + + /* count b= lines */ + while (!strncmp (lp, "b=", 2)) + { + NEXT_LINE (lp); + i++; + } + *bw_modifiers = calloc (i, sizeof (fsdp_bw_modifier_t)); + *bw_modifiers_count = i; + + while (i > 0) + { + unsigned int index = *bw_modifiers_count - i; + if (2 == sscanf (*p, "b=%20[^:\r\n]:%lu", fsdp_buf, &wuint)) + { + if (!strncmp (fsdp_buf, "CT", 2)) + (*bw_modifiers)[index].b_mod_type = + FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL; + else if (!strncmp (fsdp_buf, "AS", 2)) + (*bw_modifiers)[index].b_mod_type = + FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC; + else if (!strncmp (fsdp_buf, "RS", 2)) + (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_RTCP_SENDERS; + else if (!strncmp (fsdp_buf, "RR", 2)) + (*bw_modifiers)[index].b_mod_type = + FSDP_BW_MOD_TYPE_RTCP_RECEIVERS; + else + { + (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_UNKNOWN; + (*bw_modifiers)[index].b_unknown_bw_modt = + (char *) strdup (fsdp_buf); + } + (*bw_modifiers)[index].b_value = wuint; + NEXT_LINE (*p); + } + else + { + *bw_modifiers_count -= i; + return FSDPE_INVALID_BANDWIDTH; + } + i--; + } + return FSDPE_OK; +} + +static fsdp_error_t +fsdp_parse_k (const char **p, fsdp_encryption_method_t * method, + char **content) +{ + char fsdp_buf[MAXSHORTFIELDLEN]; + char longfsdp_buf[MAXLONGFIELDLEN]; + + if (!strncmp (*p, "k=", 2)) + { + if (sscanf (*p, "k=prompt")) + { + *method = FSDP_ENCRYPTION_METHOD_PROMPT; + *content = NULL; + NEXT_LINE (*p); + } + else + { + if (sscanf + (*p, "k=%6[^:\r\n]:%" MLFLENS "s", fsdp_buf, longfsdp_buf)) + { + if (!strncmp (fsdp_buf, "clear", 5)) + *method = FSDP_ENCRYPTION_METHOD_CLEAR; + else if (!strncmp (fsdp_buf, "base64", 6)) + *method = FSDP_ENCRYPTION_METHOD_BASE64; + else if (!strncmp (fsdp_buf, "uri", 3)) + *method = FSDP_ENCRYPTION_METHOD_URI; + else + return FSDPE_INVALID_ENCRYPTION_METHOD; + *content = strdup (longfsdp_buf); + NEXT_LINE (*p); + } + } + } + return FSDPE_OK; +} + +static fsdp_error_t +fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter, + const char *value) +{ + fsdp_error_t result = FSDPE_OK; + + if (0 == *counter) + { + *counter = 0; + *rtpmap = calloc (MEDIA_RTPMAPS_MAX_COUNT, sizeof (fsdp_rtpmap_t *)); + } + if (*counter < MEDIA_RTPMAPS_MAX_COUNT) + { + unsigned int c = *counter; + fsdp_rtpmap_t **map = *rtpmap; + char fsdp_buf[MAXSHORTFIELDLEN]; + char longfsdp_buf[MAXLONGFIELDLEN]; + map[c] = calloc (1, sizeof (fsdp_rtpmap_t)); + + /* a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding + parameters]> */ + if (2 == sscanf (value, "%s %s", fsdp_buf, longfsdp_buf)) + { + char *slash1; + map[c]->pt = strdup (fsdp_buf); + /* parse <encoding name>/<clock rate>[/<encoding parameters>] */ + slash1 = strchr (longfsdp_buf, '/'); + if (NULL == slash1) + { + result = FSDPE_INVALID_ATTRIBUTE_RTPMAP; + } + else + { + char *slash2; + *slash1 = '\0'; + slash1++; + map[c]->encoding_name = strdup (longfsdp_buf); + slash2 = strchr (slash1, '/'); + if (NULL != slash2) + { + *slash2 = '\0'; + slash2++; + map[c]->parameters = strdup (slash2); + } + map[c]->clock_rate = strtol (slash1, NULL, 10); + } + (*counter)++; + } + } + return result; +} + +static fsdp_error_t +fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds) +{ + const unsigned long SECONDS_PER_DAY = 86400; + const unsigned long SECONDS_PER_HOUR = 3600; + const unsigned long SECONDS_PER_MINUTE = 60; + char c; + unsigned long int wuint; + + if (sscanf (time, "%lu%c", &wuint, &c) == 2) + { + /* time with unit specification character */ + switch (c) + { + case 'd': + *seconds = wuint * SECONDS_PER_DAY; + break; + case 'h': + *seconds = wuint * SECONDS_PER_HOUR; + break; + case 'm': + *seconds = wuint * SECONDS_PER_MINUTE; + break; + case 's': + *seconds = wuint; + break; + default: + return FSDPE_INVALID_REPEAT; + break; + } + } + else if (sscanf (time, "%lu", &wuint) == 1) + { + /* time without unit specification character */ + *seconds = wuint; + } + else + { + return FSDPE_INVALID_REPEAT; + } + return FSDPE_OK; +} + +unsigned int +fsdp_get_version (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->version; +} + +const char * +fsdp_get_owner_username (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->o_username; +} + +const char * +fsdp_get_session_id (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->o_session_id; +} + +const char * +fsdp_get_announcement_version (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->o_announcement_version; +} + +fsdp_network_type_t +fsdp_get_owner_network_type (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_NETWORK_TYPE_UNDEFINED; + return dsc->o_network_type; +} + +fsdp_address_type_t +fsdp_get_owner_address_type (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_ADDRESS_TYPE_UNDEFINED; + return dsc->o_address_type; +} + +const char * +fsdp_get_owner_address (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->o_address; +} + +const char * +fsdp_get_name (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->s_name; +} + +const char * +fsdp_get_information (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->i_information; +} + +const char * +fsdp_get_uri (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->u_uri; +} + +unsigned int +fsdp_get_emails_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->emails_count; +} + +const char * +fsdp_get_email (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->emails_count)) + return NULL; + return dsc->emails[index]; +} + +unsigned int +fsdp_get_phones_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->phones_count; +} + +const char * +fsdp_get_phone (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->phones_count)) + return NULL; + return dsc->phones[index]; +} + +fsdp_network_type_t +fsdp_get_global_conn_network_type (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_NETWORK_TYPE_UNDEFINED; + return dsc->c_network_type; +} + +fsdp_address_type_t +fsdp_get_global_conn_address_type (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_ADDRESS_TYPE_UNDEFINED; + return dsc->c_address_type; +} + +const char * +fsdp_get_global_conn_address (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->c_address.address; +} + +unsigned int +fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->c_address.address_ttl; +} + +unsigned int +fsdp_get_global_conn_address_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->c_address.address_count; +} + +unsigned int +fsdp_get_bw_modifier_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->bw_modifiers_count; +} + +fsdp_bw_modifier_type_t +fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->bw_modifiers_count)) + return FSDP_BW_MOD_TYPE_UNDEFINED; + return dsc->bw_modifiers[index].b_mod_type; +} + +const char * +fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->bw_modifiers_count) || + (dsc->bw_modifiers[index].b_mod_type != FSDP_BW_MOD_TYPE_UNKNOWN)) + return NULL; + return dsc->bw_modifiers[index].b_unknown_bw_modt; +} + +unsigned long int +fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->bw_modifiers_count)) + return 0; + return dsc->bw_modifiers[index].b_value; +} + +time_t +fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return 0; + return dsc->time_periods[index]->start; +} + +time_t +fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return 0; + return dsc->time_periods[index]->stop; +} + +unsigned int +fsdp_get_period_repeats_count (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return 0; + return dsc->time_periods[index]->repeats_count; +} + +unsigned long int +fsdp_get_period_repeat_interval (const fsdp_description_t * dsc, + unsigned int index, unsigned int rindex) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return 0; + return dsc->time_periods[index]->repeats[rindex]->interval; +} + +unsigned long int +fsdp_get_period_repeat_duration (const fsdp_description_t * dsc, + unsigned int index, unsigned int rindex) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return 0; + return dsc->time_periods[index]->repeats[rindex]->duration; +} + +const unsigned long int * +fsdp_get_period_repeat_offsets (const fsdp_description_t * dsc, + unsigned int index, unsigned int rindex) +{ + if ((!dsc) || (index >= dsc->time_periods_count)) + return NULL; + return dsc->time_periods[index]->repeats[rindex]->offsets; +} + +const char * +fsdp_get_timezone_adj (const fsdp_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->timezone_adj; +} + +unsigned int +fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->unidentified_attributes_count; +} + +const char * +fsdp_get_unidentified_attribute (const fsdp_description_t * dsc, + unsigned int index) +{ + if (!dsc || (index < dsc->unidentified_attributes_count)) + return NULL; + return dsc->unidentified_attributes[index]; +} + +fsdp_encryption_method_t +fsdp_get_encryption_method (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_ENCRYPTION_METHOD_UNDEFINED; + return dsc->k_encryption_method; +} + +const char * +fsdp_get_encryption_content (const fsdp_description_t * dsc) +{ + if (!dsc || (dsc->k_encryption_method == FSDP_ENCRYPTION_METHOD_UNDEFINED)) + return NULL; + return dsc->k_encryption_content; +} + +unsigned int +fsdp_get_rtpmap_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_rtpmaps_count; +} + +const char * +fsdp_get_rtpmap_payload_type (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_rtpmaps_count)) + return NULL; + return dsc->a_rtpmaps[index]->pt; +} + +const char * +fsdp_get_rtpmap_encoding_name (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_rtpmaps_count)) + return NULL; + return dsc->a_rtpmaps[index]->encoding_name; +} + +unsigned int +fsdp_get_rtpmap_clock_rate (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_rtpmaps_count)) + return 0; + return dsc->a_rtpmaps[index]->clock_rate; +} + +const char * +fsdp_get_rtpmap_encoding_parameters (const fsdp_description_t * dsc, + unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_rtpmaps_count)) + return NULL; + return dsc->a_rtpmaps[index]->parameters; +} + +const char * +fsdp_get_str_att (const fsdp_description_t * dsc, fsdp_session_str_att_t att) +{ + /*TODO: change these individual attributes with a table, thus + avoiding this slow switch */ + char *result; + + if (!dsc) + return NULL; + + switch (att) + { + case FSDP_SESSION_STR_ATT_CATEGORY: + result = dsc->a_category; + break; + case FSDP_SESSION_STR_ATT_KEYWORDS: + result = dsc->a_keywords; + break; + case FSDP_SESSION_STR_ATT_TOOL: + result = dsc->a_tool; + break; + case FSDP_SESSION_STR_ATT_CHARSET: + result = dsc->a_charset; + break; + default: + result = NULL; + } + return result; +} + +unsigned int +fsdp_get_sdplang_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_sdplangs_count; +} + +const char * +fsdp_get_sdplang (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_sdplangs_count)) + return NULL; + return dsc->a_sdplangs[index]; +} + +unsigned int +fsdp_get_lang_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_langs_count; +} + +const char * +fsdp_get_lang (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_langs_count)) + return NULL; + return dsc->a_langs[index]; +} + +unsigned int +fsdp_get_control_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_controls_count; +} + +const char * +fsdp_get_control (const fsdp_description_t * dsc, unsigned int index) +{ + if ((!dsc) || (index >= dsc->a_controls_count)) + return NULL; + return dsc->a_controls[index]; +} + +const char * +fsdp_get_range (const fsdp_description_t * dsc) +{ + return dsc->a_range; +} + +fsdp_sendrecv_mode_t +fsdp_get_sendrecv_mode (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_SENDRECV_UNDEFINED; + return dsc->a_sendrecv_mode; +} + +fsdp_session_type_t +fsdp_get_session_type (const fsdp_description_t * dsc) +{ + if (!dsc) + return FSDP_SESSION_TYPE_UNDEFINED; + return dsc->a_type; +} + +unsigned int +fsdp_get_media_count (const fsdp_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->media_announcements_count; +} + +const fsdp_media_description_t * +fsdp_get_media (const fsdp_description_t * dsc, unsigned int index) +{ + if ((index >= dsc->media_announcements_count)) + return NULL; + return dsc->media_announcements[index]; +} + +fsdp_media_t +fsdp_get_media_type (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_MEDIA_UNDEFINED; + return dsc->media_type; +} + +unsigned int +fsdp_get_media_port (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->port; +} + +unsigned int +fsdp_get_media_port_count (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->port_count; +} + +fsdp_transport_protocol_t +fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_TP_UNDEFINED; + return dsc->transport; +} + +unsigned int +fsdp_get_media_formats_count (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->formats_count; +} + +const char * +fsdp_get_media_format (const fsdp_media_description_t * dsc, + unsigned int index) +{ + if (!dsc && (index < dsc->formats_count)) + return NULL; + return dsc->formats[index]; +} + +const char * +fsdp_get_media_title (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->i_title; +} + +fsdp_network_type_t +fsdp_get_media_network_type (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_NETWORK_TYPE_UNDEFINED; + return dsc->c_network_type; +} + +fsdp_address_type_t +fsdp_get_media_address_type (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_ADDRESS_TYPE_UNDEFINED; + return dsc->c_address_type; +} + +const char * +fsdp_get_media_address (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->c_address.address; +} + +unsigned int +fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->c_address.address_ttl; +} + +unsigned int +fsdp_get_media_address_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->c_address.address_count; +} + +fsdp_bw_modifier_type_t +fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc, + unsigned int index) +{ + if (!dsc || (index >= dsc->bw_modifiers_count)) + return FSDP_BW_MOD_TYPE_UNDEFINED; + return dsc->bw_modifiers[index].b_mod_type; +} + +const char * +fsdp_get_media_bw_modifier_type_unknown (const fsdp_media_description_t * dsc, + unsigned int index) +{ + if (!dsc || (index >= dsc->bw_modifiers_count) || + (FSDP_BW_MOD_TYPE_UNKNOWN != dsc->bw_modifiers[index].b_mod_type)) + return NULL; + return dsc->bw_modifiers[index].b_unknown_bw_modt; +} + +unsigned long int +fsdp_get_media_bw_value (const fsdp_media_description_t * dsc, + unsigned int index) +{ + if (!dsc || (index >= dsc->bw_modifiers_count)) + return 0; + return dsc->bw_modifiers[index].b_value; +} + +fsdp_encryption_method_t +fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_ENCRYPTION_METHOD_UNDEFINED; + return dsc->k_encryption_method; +} + +const char * +fsdp_get_media_encryption_content (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->k_encryption_content; +} + +unsigned int +fsdp_get_media_ptime (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_ptime; +} + +unsigned int +fsdp_get_media_maxptime (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_maxptime; +} + +unsigned int +fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->a_rtpmaps_count; +} + +const char * +fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_rtpmaps_count)) + return NULL; + return mdsc->a_rtpmaps[index]->pt; +} + +const char * +fsdp_get_media_rtpmap_encoding_name (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_rtpmaps_count)) + return NULL; + return mdsc->a_rtpmaps[index]->encoding_name; +} + +unsigned int +fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_rtpmaps_count)) + return 0; + return mdsc->a_rtpmaps[index]->clock_rate; +} + +const char * +fsdp_get_media_rtpmap_encoding_parameters (const fsdp_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_rtpmaps_count)) + return NULL; + return mdsc->a_rtpmaps[index]->parameters; +} + +unsigned int +fsdp_get_media_sdplang_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->a_sdplangs_count; +} + +const char * +fsdp_get_media_sdplang (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_sdplangs_count)) + return NULL; + return mdsc->a_sdplangs[index]; +} + +unsigned int +fsdp_get_media_lang_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->a_langs_count; +} + +const char * +fsdp_get_media_lang (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_langs_count)) + return NULL; + return mdsc->a_langs[index]; +} + +unsigned int +fsdp_get_media_control_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->a_controls_count; +} + +char * +fsdp_get_media_control (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_controls_count)) + return NULL; + return mdsc->a_controls[index]; +} + +char * +fsdp_get_media_range (const fsdp_media_description_t * mdsc) +{ + return mdsc->a_range; +} + +unsigned int +fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->a_fmtps_count; +} + +const char * +fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index >= mdsc->a_fmtps_count)) + return NULL; + return mdsc->a_fmtps[index]; +} + +fsdp_orient_t +fsdp_get_media_orient (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_ORIENT_UNDEFINED; + return dsc->a_orient; +} + +fsdp_sendrecv_mode_t +fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_SENDRECV_UNDEFINED; + return dsc->a_sendrecv_mode; +} + +float +fsdp_get_media_framerate (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_framerate; +} + +unsigned int +fsdp_get_media_quality (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_quality; +} + +unsigned int +fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return 0; + return dsc->a_rtcp_port; +} + +fsdp_network_type_t +fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_NETWORK_TYPE_UNDEFINED; + return dsc->a_rtcp_network_type; +} + +fsdp_address_type_t +fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return FSDP_ADDRESS_TYPE_UNDEFINED; + return dsc->a_rtcp_address_type; +} + +const char * +fsdp_get_media_rtcp_address (const fsdp_media_description_t * dsc) +{ + if (!dsc) + return NULL; + return dsc->a_rtcp_address; +} + +unsigned int +fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t + * mdsc) +{ + if (!mdsc) + return 0; + return mdsc->unidentified_attributes_count; +} + +const char * +fsdp_get_media_unidentified_attribute (const fsdp_media_description_t * mdsc, + unsigned int index) +{ + if (!mdsc || (index < mdsc->unidentified_attributes_count)) + return NULL; + return mdsc->unidentified_attributes[index]; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/parser.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,728 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + Benjamin Zores, (C) 2006 + added support in parser for the a=control: lines. + added support in parser for the a=range: lines. +*/ + +/** + * @file parser.h + * @ingroup parser + * @short Specific public header for parsing module. + **/ + +#ifndef FSDP_PARSER_H +#define FSDP_PARSER_H + +#include "common.h" + +BEGIN_C_DECLS +/** + * @defgroup parser FreeSDP Parsing Module + * + * SDP descriptions parsing routines. + * @{ + **/ +/** + * Parse a SDP description in <code>description</code>, extracting the + * session properties into <code>dsc</code>. These properties can be + * obtained individually later using the <code>fsdp_get_xxxx<code> + * functions. + * + * @param description a multimedia session description formatted in + * SDP. + * @param dsc pointer that is updated to point to a fsdp_description_t + * object. This fsdp_description_t object should have been previously + * allocated using <code>fsdp_description_new()</code>; to free it, + * <code>fsdp_description_delete()</code> should be used. + * + * @return FSDPE_OK when parsing completes successfully. Otherwise, + * another error code is returned. + **/ +fsdp_error_t fsdp_parse (const char *description, fsdp_description_t * dsc); + +/** + * Get the SDP protocol version of the description. + * + * @return SDP protocol version number. + **/ +unsigned int fsdp_get_version (const fsdp_description_t * dsc); + +/** + * Get the username provided by the originator of the session. + * + * @param dsc SDP description object. + * @return username of the session owner + **/ +const char *fsdp_get_owner_username (const fsdp_description_t * dsc); + +/** + * Get the id for the session described in <code>dsc</code>. + * + * @param dsc SDP description object. + * @return id string for this session. + **/ +const char *fsdp_get_session_id (const fsdp_description_t * dsc); + +/** + * Get the announcement version for the session description in + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return announcement version string for this description. + **/ +const char *fsdp_get_announcement_version (const fsdp_description_t * dsc); + +/** + * Get the the type of network the owner of the session described in + * <code>dsc</code> is based on. + * + * @param dsc SDP description object. + * @return network type for the owner of this session. + **/ +fsdp_network_type_t +fsdp_get_owner_network_type (const fsdp_description_t * dsc); + +/** + * Get the the type of address the owner of the session described in + * <code>dsc</code> is based on. + * + * @param dsc SDP description object. + * @return network address type for the owner of this session. + **/ +fsdp_address_type_t +fsdp_get_owner_address_type (const fsdp_description_t * dsc); + +/** + * Get the network address of the owner of the session described in + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return network address for the owner this session. + **/ +const char *fsdp_get_owner_address (const fsdp_description_t * dsc); + +/** + * Get the name of the session described in <code>dsc</code>. + * + * @param dsc SDP description object. + * @return name of this session. + **/ +const char *fsdp_get_name (const fsdp_description_t * dsc); + +/** + * Get the information about the session provided in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return information of this session. + **/ +const char *fsdp_get_information (const fsdp_description_t * dsc); + +/** + * Get an URI about the session provided in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return string containing an URI about the session. NULL if the + * session uri is missing. + **/ +const char *fsdp_get_uri (const fsdp_description_t * dsc); + +/** + * Get the number of emails specified for the session in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return number of emails. + **/ +unsigned int fsdp_get_emails_count (const fsdp_description_t * dsc); + +/** + * Get the n-th email specified for the session in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @param index number of URI. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_emails_count() - 1. + * @return string containing an email about the session. NULL if there + * is no such index. + **/ +const char *fsdp_get_email (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the number of phones specified for the session in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @return number of emails. + **/ +unsigned int fsdp_get_phones_count (const fsdp_description_t * dsc); + +/** + * Get the n-th phone specified for the session in the description + * <code>dsc</code>. + * + * @param dsc SDP description object. + * @param index number of URI. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_phones_count() - 1. + * @return string containing a phone about the session. NULL if there + * is no such index. + **/ +const char *fsdp_get_phone (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the the global type of network of the multimedia session + * connection. + * + * @param dsc SDP description object. + * @return global network type for this + * connection. FSDP_NETWORK_TYPE_UNDEFINED if no global network + * address type is included in the description. + **/ +fsdp_network_type_t +fsdp_get_global_conn_network_type (const fsdp_description_t * dsc); + +/** + * Get the the global type of network address of the multimedia + * session connection. + * + * @param dsc SDP description object. + * @return global network address type for this connection. + * FSDP_ADDRESS_TYPE_UNDEFINED if no global network address type is + * included in the description. + **/ +fsdp_address_type_t +fsdp_get_global_conn_address_type (const fsdp_description_t * dsc); + +/** + * Get the the global address of the multimedia session connection. + * + * @param dsc SDP description object. + * @return global address for this connection. + **/ +const char *fsdp_get_global_conn_address (const fsdp_description_t * dsc); + +unsigned int +fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc); + +unsigned int +fsdp_get_global_conn_address_count (const fsdp_description_t * dsc); + +/** + * Get the number of bandwidth modifiers specified for this session. + * + * @param dsc SDP description object. + * @return number of bandwidth modifiers. + **/ +unsigned int fsdp_get_bw_modifier_count (const fsdp_description_t * dsc); + +/** + * Get the bandwidth modifier type for the session. + * + * @param dsc SDP description object. + * @param index number of bandwidth modifier. + * + * @return global bandwidth modifier type. + * @retval FSDP_BW_MOD_TYPE_UNDEFINED if no global bandwith modifier + * type is defined or invalid index. + * @retval FSDP_BW_MOD_TYPE_UNKNOWN if an unknown bandwith modifier is + * specified or an invalid index is provided. In this case + * fsdp_get_bw_modifer_type_unknown() can be called to get the + * modifier as a character string. + **/ +fsdp_bw_modifier_type_t +fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the textual bandwidth modifier type when it is unknown. + * + * @param dsc SDP description object. + * @param index number of bandwidth modifier. + * + * @return global bandwidth modifier type. + * @retval empty string if the provided bandwidth type is not unknown, + * the provided index is invalid or or there was a parse error. + **/ +const char *fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the value for the bandwidth modifier. + * + * @param dsc SDP description object. + * @param index number of bandwidth modifier. + * @return global bandwidth value. + * @retval 0 if no bandwidth is specified for this session or an + * invalid index has been provided. + **/ +unsigned long int +fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index); + +/** + * Get the number of time periods specified for this session + * + * @param dsc SDP description object. + * @return number of time periods + **/ +unsigned long int fsdp_get_period_count (const fsdp_description_t * dsc); + +/** + * Get the start time for the period selected by index. + * + * @param dsc SDP description object. + * @param index number of time period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @return start time + * @retval 0 if an invalid index is provided. + **/ +time_t +fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index); + +/** + * Get the stop time for the period selected by index. + * + * @param dsc SDP description object. + * @param index number of time period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @return stop time + * @retval 0 if an invalid index is provided. + **/ +time_t +fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index); + +/** + * Get the number of repeats for the period selected by index. + * + * @param dsc SDP description object. + * @param index number of the period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @return number of repeats + * @retval 0 if an invalid index is provided. + **/ +unsigned int +fsdp_get_period_repeats_count (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the interval time of the repeat selected by rindex for the + * period selected by index. + * + * @param dsc SDP description object. + * @param index number of time period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @param rindex number of repeat + * @return interval time + * @retval 0 if an invalid index is provided. + **/ +unsigned long int +fsdp_get_period_repeat_interval (const fsdp_description_t * dsc, + unsigned int index, unsigned int rindex); + +/** + * Get the duration of the repeat selected by rindex for the period + * selected by index. + * + * @param dsc SDP description object. + * @param index number of time period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @param rindex number of repeat + * @return duration + * @retval 0 if an invalid index is provided. + **/ +unsigned long int +fsdp_get_period_repeat_duration (const fsdp_description_t * dsc, + unsigned int index, unsigned int rindex); + +/** + * Get the offsets of the repeat selected by rindex for the period + * selected by index. + * + * @param dsc SDP description object. + * @param index number of time period. Note that this index follows the + * traditional C convention: from 0 to fsdp_get_period_count() - 1. + * @param rindex number of repeat + * @return array of offsets + * @retval NULL if an invalid index is provided. + **/ +const unsigned long int *fsdp_get_period_repeat_offsets (const + fsdp_description_t * + dsc, + unsigned int index, + unsigned int rindex); + +/** + * Get the encryption method defined for this session. + * + * @param dsc SDP description object. + * @return encryption method. FSDP_ENCRYPTION_METHOD_UNDEFINED if no + * encryption method is specified. + **/ +fsdp_encryption_method_t +fsdp_get_encryption_method (const fsdp_description_t * dsc); + +/** + * Get the encryption key or a URI pointing to the encryption key for + * this session. + * + * @param dsc SDP description object. + * @return encryption key unless FSDP_ENCRYPTION_METHOD_URI is + * specified, in which case a URI pointing to the key is returned. If + * the global encryption method is undefined, NULL is returned. + **/ +const char *fsdp_get_encryption_content (const fsdp_description_t * dsc); + +/** + * Get timezone adjustments. + * + * @param dsc SDP description object. + * @return string with list of timezone adjustments + * @retval NULL if no timezone adjustment list was specified or there + * was a parse error. + **/ +const char *fsdp_get_timezone_adj (const fsdp_description_t * dsc); + +/** + * + **/ +unsigned int +fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_unidentified_attribute (const fsdp_description_t * dsc, + unsigned int index); + +/** + * + **/ +unsigned int +fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc); + +/** + * + **/ +const char *fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t + * mdsc, unsigned int index); + +/** + * + **/ +const char *fsdp_get_media_rtpmap_encoding_name (const + fsdp_media_description_t * + mdsc, unsigned int index); + +/** + * + **/ +unsigned int +fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc, + unsigned int index); + +/** + * + **/ +const char *fsdp_get_media_rtpmap_encoding_parameters (const + fsdp_description_t * + mdsc, + unsigned int index); + +/** + * Get the value of the session attribute specified in + * <code>att</code>. This function works for all the session + * attributes whose value is a character string. These attributes are + * defined in the session_string_attribute_t enumerated type. + * + * @param dsc SDP description object. + * @param att attribute to get. + * + * @return value of the attribute <code>att</code>. + * @retval NULL if the attribute was not specified or there was a + * parse error or an invalid att is given. + **/ +const char *fsdp_get_str_att (const fsdp_description_t * dsc, + fsdp_session_str_att_t att); + +/** + * + **/ +unsigned int fsdp_get_sdplang_count (const fsdp_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_sdplang (const fsdp_description_t * dsc, + unsigned int index); + +/** + * Get the mode of the conference, specified with attributes sendrecv, + * sendonly, recvonly and inactive. + * + * @param dsc SDP description object. + * @return send/rec conference mode. + * @retval FSDP_SENDRECV_UNDEFINED if conference mode not provided. + **/ +fsdp_sendrecv_mode_t fsdp_get_sendrecv_mode (const fsdp_description_t * dsc); + +/** + * Get the type of conference, such as broadcast, meeting, moderated, + * test or H332. + * + * @param dsc SDP description object. + * @return conference type. + * @retval FSDP_SESSION_TYPE_UNDEFINED if conference type not provided. + **/ +fsdp_session_type_t fsdp_get_session_type (const fsdp_description_t * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_count (const fsdp_description_t * dsc); + +/** + * + **/ +const fsdp_media_description_t *fsdp_get_media (const fsdp_description_t * + dsc, unsigned int index); + +/** + * + **/ +fsdp_media_t fsdp_get_media_type (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_port (const fsdp_media_description_t * dsc); + +unsigned int fsdp_get_media_port_count (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_transport_protocol_t +fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_formats (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int +fsdp_get_media_formats_count (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_format (const fsdp_media_description_t * dsc, + unsigned int index); + +/** + * + **/ +const char *fsdp_get_media_title (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_network_type_t +fsdp_get_media_network_type (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_address_type_t +fsdp_get_media_address_type (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_address (const fsdp_media_description_t * dsc); + +unsigned int +fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc); + +unsigned int +fsdp_get_media_address_count (const fsdp_media_description_t * mdsc); + +/** + * + **/ +fsdp_bw_modifier_type_t +fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc, + unsigned int index); + +/** + * + **/ +const char *fsdp_get_media_bw_modifier_type_unknown (const + fsdp_media_description_t + * dsc, + unsigned int index); + +/** + * + **/ +unsigned long int +fsdp_get_media_bw_value (const fsdp_media_description_t * dsc, + unsigned int index); + +/** + * + **/ +fsdp_encryption_method_t +fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_encryption_content (const fsdp_media_description_t + * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_ptime (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_maxptime (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int +fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc); + +/** + * + **/ +const char *fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc, + unsigned int index); + +/** + * + **/ +unsigned int +fsdp_get_media_sdplang_count (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_sdplang (const fsdp_media_description_t * dsc, + unsigned int index); + +/** + * + **/ +unsigned int fsdp_get_media_lang_count (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_lang (const fsdp_media_description_t * dsc, + unsigned int index); + + +unsigned int fsdp_get_control_count (const fsdp_description_t * dsc); + +const char *fsdp_get_control (const fsdp_description_t * dsc, + unsigned int index); + +const char *fsdp_get_range (const fsdp_description_t * dsc); + +unsigned int +fsdp_get_media_control_count (const fsdp_media_description_t * mdsc); + +char *fsdp_get_media_control (const fsdp_media_description_t * mdsc, + unsigned int index); + +char *fsdp_get_media_range (const fsdp_media_description_t * mdsc); + +/** + * + **/ +fsdp_orient_t fsdp_get_media_orient (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_sendrecv_mode_t +fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc); + +/** + * + **/ +float fsdp_get_media_framerate (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_quality (const fsdp_media_description_t * dsc); + +/** + * + **/ +unsigned int fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_network_type_t +fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc); + +/** + * + **/ +fsdp_address_type_t +fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc); + +/** + * + **/ +const char *fsdp_get_media_rtcp_address (const fsdp_media_description_t * + dsc); + +/** + * + **/ +unsigned int +fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t + * mdsc); + +/** + * + **/ +const char *fsdp_get_media_unidentified_attribute (const + fsdp_media_description_t * + mdsc, unsigned int index); + + + /** @} *//* closes parser group */ + +END_C_DECLS +#endif /* FSDP_PARSER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/parserpriv.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,118 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@suidzer0.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 +*/ + +/** + * @file parserpriv.h + * + * @short Private header for parser module. + **/ + +#ifndef FSDP_PARSERPRIV_H +#define FSDP_PARSERPRIV_H + +#include "priv.h" +#include "parser.h" + +/** + * Parse a connection (c=<network type> <address type> <connection + * address>) line. If the textual description in <code>p</code> begins + * with a connection line, it is parsed. If not, nothing is done. + * + * @param p fraction of textual SDP description. + * @param ntype where to store the network type. + * @param atype where to store the address type. + * @param address where to store the connection address as a string. + * + * @return parse error code. + **/ +static fsdp_error_t +fsdp_parse_c (const char **p, fsdp_network_type_t * ntype, + fsdp_address_type_t * atype, + fsdp_connection_address_t * address); + +/** + * Parse b (b=<modifier>:<bandwidth-value>) consecutive lines. If the + * textual description in <code>p</code> begins with a bandwidth line, + * it is parsed as well as all b lines inmediately after it. If not, + * nothing is done. + * + * @param p fraction of textual SDP description. + * @param bw_modifiers pointer to empty array of bandwidth modifiers to fill. + * @param bw_modifiers_count where to set the number of bandwidth + * modifiers successfully parsed. + * + * @return parse error code. + **/ +static fsdp_error_t +fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers, + unsigned int *bw_modifiers_count); + +/** + * Parse a k (k=<method>) or (k=<method>:<encryption key>) line. If + * the textual description in <code>p</code> begins with an encryption + * line, it is parsed. If not, nothing is done. + * + * @param p fraction of textual SDP description. + * @param method where to store the encryption method. + * @param content where to store the encryption key if provided. + * + * @return parse error code. + **/ +static fsdp_error_t +fsdp_parse_k (const char **p, fsdp_encryption_method_t * method, + char **content); + + +/** + * Parses a string whose first token (first characters before the + * first space or end of string) is supposed to be a time in SDP + * syntax. Some examples of SDP times are: 2d, 5h, 3444, 7778s, + * + * @param time time in SDP syntax as a string. + * @param seconds where to store the value in seconds as an integer. + * + * @return parse error code. + **/ +static fsdp_error_t +fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds); + +static fsdp_error_t +fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter, + const char *value); + +/** + * Maximun default field len for "expected to be short" fields, like + * username, session_id or inet addresses. + * + * MDFLENS value must be MAXSHORTFIELDLEN - 1 + **/ +#define MAXSHORTFIELDLEN 96 +#define MSFLENS "95" + +/** + * Maximun default field len for "maybe very long" fields, like + * information, attribute values. This can also be used for lines + * where there is only a string field, like phone and email. + * + * MLFLENS value must be MAXLONGFIELDLEN - 1 + **/ +#define MAXLONGFIELDLEN 1024 +#define MLFLENS "1023" + +#endif /* FSDP_PARSERPRIV_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/freesdp/priv.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,274 @@ +/* + This file is part of FreeSDP + Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org> + + FreeSDP is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU 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 + + Benjamin Zores, (C) 2006 + added support in parser for the a=control: lines. + added support in parser for the a=range: lines. +*/ + +/** + * @file priv.h + * + * @short Common private header for both formatting and parsing modules. + **/ + +#ifndef FSDP_PRIV_H +#define FSDP_PRIV_H + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common.h" + +#define NTP_EPOCH_OFFSET 2208988800UL + +#define FSDP_MAX_LENGTH 2000 + +/* Tags for doxygen documentation */ + +/** + * @mainpage FreeSDP Library Reference Manual + * @section overview Overview (README) + * @verbinclude ../../README + * + **/ + +/** + * @example formatdemo.c + * + * A basic SDP descriptions formatter based on FreeSDP. + **/ + +/** + * @example parsedemo.c + * + * A basic SDP descriptions parser based on FreeSDP. + **/ + +/* Private routines declarations */ + +BEGIN_C_DECLS +/** + * @short bandwidth modifier + * + * Holds type of modifier and value. Also holds the literal bandwidth + * modifier if unknown. + **/ + typedef struct +{ + fsdp_bw_modifier_type_t b_mod_type; + unsigned long int b_value; + char *b_unknown_bw_modt; +} fsdp_bw_modifier_t; + +/** + * @short a=rtpmap: attribute + * + * Holds payload type, enconding name, RTP clock rate, and encofing + * parameters. + **/ +typedef struct +{ + char *pt; + char *encoding_name; + unsigned int clock_rate; + char *parameters; +} fsdp_rtpmap_t; + +/** + * @short Connection address specification + * + * Holds address (unicast or multicast) as well as TTL and number of + * ports, when it is an IP4 multicast address. + **/ +typedef struct fsdp_connection_address_t_s +{ + char *address; + unsigned int address_ttl; + unsigned int address_count; +} fsdp_connection_address_t; + +/** + * @short Struct for each media in a session description. + **/ +struct fsdp_media_description_t_s +{ + /* from `m=<media> <port> <transport> <fmt list>' line */ + fsdp_media_t media_type; + unsigned int port; + unsigned int port_count; + fsdp_transport_protocol_t transport; + char **formats; + unsigned int formats_count; + /* from i=<media title> */ + char *i_title; + /* from `c=<network type> <address type> <connection address>' line + (optional) */ + fsdp_network_type_t c_network_type; + fsdp_address_type_t c_address_type; + fsdp_connection_address_t c_address; + /* from `b=<modifier>:<bandwidth-value>' lines (optional) */ + fsdp_bw_modifier_t *bw_modifiers; + unsigned int bw_modifiers_count; + /* from `k=<method>' or `k=<method>:<encryption key>' line + (optional) */ + fsdp_encryption_method_t k_encryption_method; + char *k_encryption_content; + /* from `a=<attribute>' or `a=<attribute>:<value>' lines (opt) */ + unsigned long int a_ptime; + unsigned long int a_maxptime; + /* rtpmap */ + fsdp_rtpmap_t **a_rtpmaps; + unsigned int a_rtpmaps_count; + fsdp_orient_t a_orient; + fsdp_sendrecv_mode_t a_sendrecv_mode; + + char **a_sdplangs; + unsigned int a_sdplangs_count; + char **a_langs; + unsigned int a_langs_count; + + char **a_controls; + unsigned int a_controls_count; + + char *a_range; + + float a_framerate; + unsigned int a_quality; + char **a_fmtps; + unsigned int a_fmtps_count; + /* rtcp attribute */ + unsigned int a_rtcp_port; + fsdp_network_type_t a_rtcp_network_type; + fsdp_address_type_t a_rtcp_address_type; + char *a_rtcp_address; + /* media attributes that are not directly supported */ + char **unidentified_attributes; + unsigned int unidentified_attributes_count; +}; + +typedef struct fsdp_media_description_t_s fsdp_media_announcement_t; + +/** + * @short Information for a repeat (struct for r= lines) + **/ +typedef struct +{ + /* times in seconds */ + unsigned long int interval; + unsigned long int duration; + unsigned long int *offsets; + unsigned int offsets_count; +} fsdp_repeat_t; + +/** + * @short Information about a time period + * + * The start and stop times as well as the information from the r= + * lines for a t= line are stored in this structures. + **/ +typedef struct +{ + time_t start; + time_t stop; + fsdp_repeat_t **repeats; + unsigned int repeats_count; +} fsdp_time_period_t; + +/** + * @short Struct for session descriptions. + **/ +struct fsdp_description_t_s +{ + /* from v=... line */ + unsigned int version; + /* from o=... line */ + char *o_username; + char *o_session_id; + char *o_announcement_version; + fsdp_network_type_t o_network_type; + fsdp_address_type_t o_address_type; + char *o_address; + /* from s=... line */ + char *s_name; + /* from i=... line (opt) */ + char *i_information; + /* from u=... line (opt) */ + char *u_uri; + /* from e=... lines (0 or more) */ + const char **emails; + unsigned int emails_count; + /* from p=... lines (0 or more) */ + const char **phones; + unsigned int phones_count; + /* from `c=<network type> <address type> <connection address>' line */ + fsdp_network_type_t c_network_type; + fsdp_address_type_t c_address_type; + fsdp_connection_address_t c_address; + /* from `b=<modifier>:<bandwidth-value>' lines (optional) */ + fsdp_bw_modifier_t *bw_modifiers; + unsigned int bw_modifiers_count; + /* from `t=<start time> <stop time>' lines (1 or more) */ + /* from `r=<repeat interval> <active duration> <list of offsets from + start-time>' */ + fsdp_time_period_t **time_periods; + unsigned int time_periods_count; + /* from `z=<adjustment time> <offset> <adjustment time> <offset> + ....' lines */ + char *timezone_adj; + /* from `k=<method>' or `k=<method>:<encryption key>' line (opt) */ + fsdp_encryption_method_t k_encryption_method; + char *k_encryption_content; + /* from `a=<attribute>' or `a=<attribute>:<value>' lines (opt) */ + char *a_category; + char *a_keywords; + char *a_tool; + char *a_range; + /* rtpmap */ + fsdp_rtpmap_t **a_rtpmaps; + unsigned int a_rtpmaps_count; + fsdp_sendrecv_mode_t a_sendrecv_mode; + fsdp_session_type_t a_type; + char *a_charset; + + char **a_sdplangs; + unsigned int a_sdplangs_count; + char **a_langs; + unsigned int a_langs_count; + + char **a_controls; + unsigned int a_controls_count; + /* from `m=<media> <port>/<number of ports> <transport> <fmt list>' + lines [one or more] */ + fsdp_media_announcement_t **media_announcements; + unsigned int media_announcements_count; + /* session attributes that are not directly supported */ + char **unidentified_attributes; + unsigned int unidentified_attributes_count; +}; + +#define MEDIA_RTPMAPS_MAX_COUNT 5 +#define SDPLANGS_MAX_COUNT 5 +#define SDPCONTROLS_MAX_COUNT 10 +#define UNIDENTIFIED_ATTRIBUTES_MAX_COUNT 5 + +END_C_DECLS +#endif /* FSDP_PRIV_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/frequencies.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,1169 @@ +#include <stdlib.h> +#include <sys/time.h> + +#include "frequencies.h" + +/* --------------------------------------------------------------------- */ + +/* US broadcast */ +static const struct CHANLIST ntsc_bcast[] = { + { "2", 55250 }, + { "3", 61250 }, + { "4", 67250 }, + { "5", 77250 }, + { "6", 83250 }, + { "7", 175250 }, + { "8", 181250 }, + { "9", 187250 }, + { "10", 193250 }, + { "11", 199250 }, + { "12", 205250 }, + { "13", 211250 }, + { "14", 471250 }, + { "15", 477250 }, + { "16", 483250 }, + { "17", 489250 }, + { "18", 495250 }, + { "19", 501250 }, + { "20", 507250 }, + { "21", 513250 }, + { "22", 519250 }, + { "23", 525250 }, + { "24", 531250 }, + { "25", 537250 }, + { "26", 543250 }, + { "27", 549250 }, + { "28", 555250 }, + { "29", 561250 }, + { "30", 567250 }, + { "31", 573250 }, + { "32", 579250 }, + { "33", 585250 }, + { "34", 591250 }, + { "35", 597250 }, + { "36", 603250 }, + { "37", 609250 }, + { "38", 615250 }, + { "39", 621250 }, + { "40", 627250 }, + { "41", 633250 }, + { "42", 639250 }, + { "43", 645250 }, + { "44", 651250 }, + { "45", 657250 }, + { "46", 663250 }, + { "47", 669250 }, + { "48", 675250 }, + { "49", 681250 }, + { "50", 687250 }, + { "51", 693250 }, + { "52", 699250 }, + { "53", 705250 }, + { "54", 711250 }, + { "55", 717250 }, + { "56", 723250 }, + { "57", 729250 }, + { "58", 735250 }, + { "59", 741250 }, + { "60", 747250 }, + { "61", 753250 }, + { "62", 759250 }, + { "63", 765250 }, + { "64", 771250 }, + { "65", 777250 }, + { "66", 783250 }, + { "67", 789250 }, + { "68", 795250 }, + { "69", 801250 }, + + { "70", 807250 }, + { "71", 813250 }, + { "72", 819250 }, + { "73", 825250 }, + { "74", 831250 }, + { "75", 837250 }, + { "76", 843250 }, + { "77", 849250 }, + { "78", 855250 }, + { "79", 861250 }, + { "80", 867250 }, + { "81", 873250 }, + { "82", 879250 }, + { "83", 885250 }, +}; + +/* US cable */ +static const struct CHANLIST ntsc_cable[] = { + { "1", 73250 }, + { "2", 55250 }, + { "3", 61250 }, + { "4", 67250 }, + { "5", 77250 }, + { "6", 83250 }, + { "7", 175250 }, + { "8", 181250 }, + { "9", 187250 }, + { "10", 193250 }, + { "11", 199250 }, + { "12", 205250 }, + + { "13", 211250 }, + { "14", 121250 }, + { "15", 127250 }, + { "16", 133250 }, + { "17", 139250 }, + { "18", 145250 }, + { "19", 151250 }, + { "20", 157250 }, + + { "21", 163250 }, + { "22", 169250 }, + { "23", 217250 }, + { "24", 223250 }, + { "25", 229250 }, + { "26", 235250 }, + { "27", 241250 }, + { "28", 247250 }, + { "29", 253250 }, + { "30", 259250 }, + { "31", 265250 }, + { "32", 271250 }, + { "33", 277250 }, + { "34", 283250 }, + { "35", 289250 }, + { "36", 295250 }, + { "37", 301250 }, + { "38", 307250 }, + { "39", 313250 }, + { "40", 319250 }, + { "41", 325250 }, + { "42", 331250 }, + { "43", 337250 }, + { "44", 343250 }, + { "45", 349250 }, + { "46", 355250 }, + { "47", 361250 }, + { "48", 367250 }, + { "49", 373250 }, + { "50", 379250 }, + { "51", 385250 }, + { "52", 391250 }, + { "53", 397250 }, + { "54", 403250 }, + { "55", 409250 }, + { "56", 415250 }, + { "57", 421250 }, + { "58", 427250 }, + { "59", 433250 }, + { "60", 439250 }, + { "61", 445250 }, + { "62", 451250 }, + { "63", 457250 }, + { "64", 463250 }, + { "65", 469250 }, + { "66", 475250 }, + { "67", 481250 }, + { "68", 487250 }, + { "69", 493250 }, + + { "70", 499250 }, + { "71", 505250 }, + { "72", 511250 }, + { "73", 517250 }, + { "74", 523250 }, + { "75", 529250 }, + { "76", 535250 }, + { "77", 541250 }, + { "78", 547250 }, + { "79", 553250 }, + { "80", 559250 }, + { "81", 565250 }, + { "82", 571250 }, + { "83", 577250 }, + { "84", 583250 }, + { "85", 589250 }, + { "86", 595250 }, + { "87", 601250 }, + { "88", 607250 }, + { "89", 613250 }, + { "90", 619250 }, + { "91", 625250 }, + { "92", 631250 }, + { "93", 637250 }, + { "94", 643250 }, + { "95", 91250 }, + { "96", 97250 }, + { "97", 103250 }, + { "98", 109250 }, + { "99", 115250 }, + { "100", 649250 }, + { "101", 655250 }, + { "102", 661250 }, + { "103", 667250 }, + { "104", 673250 }, + { "105", 679250 }, + { "106", 685250 }, + { "107", 691250 }, + { "108", 697250 }, + { "109", 703250 }, + { "110", 709250 }, + { "111", 715250 }, + { "112", 721250 }, + { "113", 727250 }, + { "114", 733250 }, + { "115", 739250 }, + { "116", 745250 }, + { "117", 751250 }, + { "118", 757250 }, + { "119", 763250 }, + { "120", 769250 }, + { "121", 775250 }, + { "122", 781250 }, + { "123", 787250 }, + { "124", 793250 }, + { "125", 799250 }, + + { "T7", 8250 }, + { "T8", 14250 }, + { "T9", 20250 }, + { "T10", 26250 }, + { "T11", 32250 }, + { "T12", 38250 }, + { "T13", 44250 }, + { "T14", 50250 } +}; + +/* US HRC */ +static const struct CHANLIST ntsc_hrc[] = { + { "1", 72000 }, + { "2", 54000 }, + { "3", 60000 }, + { "4", 66000 }, + { "5", 78000 }, + { "6", 84000 }, + { "7", 174000 }, + { "8", 180000 }, + { "9", 186000 }, + { "10", 192000 }, + { "11", 198000 }, + { "12", 204000 }, + + { "13", 210000 }, + { "14", 120000 }, + { "15", 126000 }, + { "16", 132000 }, + { "17", 138000 }, + { "18", 144000 }, + { "19", 150000 }, + { "20", 156000 }, + + { "21", 162000 }, + { "22", 168000 }, + { "23", 216000 }, + { "24", 222000 }, + { "25", 228000 }, + { "26", 234000 }, + { "27", 240000 }, + { "28", 246000 }, + { "29", 252000 }, + { "30", 258000 }, + { "31", 264000 }, + { "32", 270000 }, + { "33", 276000 }, + { "34", 282000 }, + { "35", 288000 }, + { "36", 294000 }, + { "37", 300000 }, + { "38", 306000 }, + { "39", 312000 }, + { "40", 318000 }, + { "41", 324000 }, + { "42", 330000 }, + { "43", 336000 }, + { "44", 342000 }, + { "45", 348000 }, + { "46", 354000 }, + { "47", 360000 }, + { "48", 366000 }, + { "49", 372000 }, + { "50", 378000 }, + { "51", 384000 }, + { "52", 390000 }, + { "53", 396000 }, + { "54", 402000 }, + { "55", 408000 }, + { "56", 414000 }, + { "57", 420000 }, + { "58", 426000 }, + { "59", 432000 }, + { "60", 438000 }, + { "61", 444000 }, + { "62", 450000 }, + { "63", 456000 }, + { "64", 462000 }, + { "65", 468000 }, + { "66", 474000 }, + { "67", 480000 }, + { "68", 486000 }, + { "69", 492000 }, + + { "70", 498000 }, + { "71", 504000 }, + { "72", 510000 }, + { "73", 516000 }, + { "74", 522000 }, + { "75", 528000 }, + { "76", 534000 }, + { "77", 540000 }, + { "78", 546000 }, + { "79", 552000 }, + { "80", 558000 }, + { "81", 564000 }, + { "82", 570000 }, + { "83", 576000 }, + { "84", 582000 }, + { "85", 588000 }, + { "86", 594000 }, + { "87", 600000 }, + { "88", 606000 }, + { "89", 612000 }, + { "90", 618000 }, + { "91", 624000 }, + { "92", 630000 }, + { "93", 636000 }, + { "94", 642000 }, + { "95", 900000 }, + { "96", 960000 }, + { "97", 102000 }, + { "98", 108000 }, + { "99", 114000 }, + { "100", 648000 }, + { "101", 654000 }, + { "102", 660000 }, + { "103", 666000 }, + { "104", 672000 }, + { "105", 678000 }, + { "106", 684000 }, + { "107", 690000 }, + { "108", 696000 }, + { "109", 702000 }, + { "110", 708000 }, + { "111", 714000 }, + { "112", 720000 }, + { "113", 726000 }, + { "114", 732000 }, + { "115", 738000 }, + { "116", 744000 }, + { "117", 750000 }, + { "118", 756000 }, + { "119", 762000 }, + { "120", 768000 }, + { "121", 774000 }, + { "122", 780000 }, + { "123", 786000 }, + { "124", 792000 }, + { "125", 798000 }, + + { "T7", 7000 }, + { "T8", 13000 }, + { "T9", 19000 }, + { "T10", 25000 }, + { "T11", 31000 }, + { "T12", 37000 }, + { "T13", 43000 }, + { "T14", 49000 }, +}; + +/* --------------------------------------------------------------------- */ + +/* JP broadcast */ +static const struct CHANLIST ntsc_bcast_jp[] = { + { "1", 91250 }, + { "2", 97250 }, + { "3", 103250 }, + { "4", 171250 }, + { "5", 177250 }, + { "6", 183250 }, + { "7", 189250 }, + { "8", 193250 }, + { "9", 199250 }, + { "10", 205250 }, + { "11", 211250 }, + { "12", 217250 }, + + { "13", 471250 }, + { "14", 477250 }, + { "15", 483250 }, + { "16", 489250 }, + { "17", 495250 }, + { "18", 501250 }, + { "19", 507250 }, + { "20", 513250 }, + { "21", 519250 }, + { "22", 525250 }, + { "23", 531250 }, + { "24", 537250 }, + { "25", 543250 }, + { "26", 549250 }, + { "27", 555250 }, + { "28", 561250 }, + { "29", 567250 }, + { "30", 573250 }, + { "31", 579250 }, + { "32", 585250 }, + { "33", 591250 }, + { "34", 597250 }, + { "35", 603250 }, + { "36", 609250 }, + { "37", 615250 }, + { "38", 621250 }, + { "39", 627250 }, + { "40", 633250 }, + { "41", 639250 }, + { "42", 645250 }, + { "43", 651250 }, + { "44", 657250 }, + + { "45", 663250 }, + { "46", 669250 }, + { "47", 675250 }, + { "48", 681250 }, + { "49", 687250 }, + { "50", 693250 }, + { "51", 699250 }, + { "52", 705250 }, + { "53", 711250 }, + { "54", 717250 }, + { "55", 723250 }, + { "56", 729250 }, + { "57", 735250 }, + { "58", 741250 }, + { "59", 747250 }, + { "60", 753250 }, + { "61", 759250 }, + { "62", 765250 }, +}; + +/* JP cable */ +static const struct CHANLIST ntsc_cable_jp[] = { + { "13", 109250 }, + { "14", 115250 }, + { "15", 121250 }, + { "16", 127250 }, + { "17", 133250 }, + { "18", 139250 }, + { "19", 145250 }, + { "20", 151250 }, + + { "21", 157250 }, + { "22", 165250 }, + { "23", 223250 }, + { "24", 231250 }, + { "25", 237250 }, + { "26", 243250 }, + { "27", 249250 }, + { "28", 253250 }, + { "29", 259250 }, + { "30", 265250 }, + { "31", 271250 }, + { "32", 277250 }, + { "33", 283250 }, + { "34", 289250 }, + { "35", 295250 }, + { "36", 301250 }, + { "37", 307250 }, + { "38", 313250 }, + { "39", 319250 }, + { "40", 325250 }, + { "41", 331250 }, + { "42", 337250 }, + { "43", 343250 }, + { "44", 349250 }, + { "45", 355250 }, + { "46", 361250 }, + { "47", 367250 }, + { "48", 373250 }, + { "49", 379250 }, + { "50", 385250 }, + { "51", 391250 }, + { "52", 397250 }, + { "53", 403250 }, + { "54", 409250 }, + { "55", 415250 }, + { "56", 421250 }, + { "57", 427250 }, + { "58", 433250 }, + { "59", 439250 }, + { "60", 445250 }, + { "61", 451250 }, + { "62", 457250 }, + { "63", 463250 }, +}; + +/* --------------------------------------------------------------------- */ + +/* australia */ +static const struct CHANLIST pal_australia[] = { + { "0", 46250 }, + { "1", 57250 }, + { "2", 64250 }, + { "3", 86250 }, + { "4", 95250 }, + { "5", 102250 }, + { "5A", 138250 }, + { "6", 175250 }, + { "7", 182250 }, + { "8", 189250 }, + { "9", 196250 }, + { "10", 209250 }, + { "11", 216250 }, + { "28", 527250 }, + { "29", 534250 }, + { "30", 541250 }, + { "31", 548250 }, + { "32", 555250 }, + { "33", 562250 }, + { "34", 569250 }, + { "35", 576250 }, + { "36", 591250 }, + { "39", 604250 }, + { "40", 611250 }, + { "41", 618250 }, + { "42", 625250 }, + { "43", 632250 }, + { "44", 639250 }, + { "45", 646250 }, + { "46", 653250 }, + { "47", 660250 }, + { "48", 667250 }, + { "49", 674250 }, + { "50", 681250 }, + { "51", 688250 }, + { "52", 695250 }, + { "53", 702250 }, + { "54", 709250 }, + { "55", 716250 }, + { "56", 723250 }, + { "57", 730250 }, + { "58", 737250 }, + { "59", 744250 }, + { "60", 751250 }, + { "61", 758250 }, + { "62", 765250 }, + { "63", 772250 }, + { "64", 779250 }, + { "65", 786250 }, + { "66", 793250 }, + { "67", 800250 }, + { "68", 807250 }, + { "69", 814250 }, +}; + +/* --------------------------------------------------------------------- */ +/* europe */ + +/* CCIR frequencies */ + +#define FREQ_CCIR_I_III \ + { "E2", 48250 }, \ + { "E3", 55250 }, \ + { "E4", 62250 }, \ + \ + { "S01", 69250 }, \ + { "S02", 76250 }, \ + { "S03", 83250 }, \ + \ + { "E5", 175250 }, \ + { "E6", 182250 }, \ + { "E7", 189250 }, \ + { "E8", 196250 }, \ + { "E9", 203250 }, \ + { "E10", 210250 }, \ + { "E11", 217250 }, \ + { "E12", 224250 } + +#define FREQ_CCIR_SL_SH \ + { "SE1", 105250 }, \ + { "SE2", 112250 }, \ + { "SE3", 119250 }, \ + { "SE4", 126250 }, \ + { "SE5", 133250 }, \ + { "SE6", 140250 }, \ + { "SE7", 147250 }, \ + { "SE8", 154250 }, \ + { "SE9", 161250 }, \ + { "SE10", 168250 }, \ + \ + { "SE11", 231250 }, \ + { "SE12", 238250 }, \ + { "SE13", 245250 }, \ + { "SE14", 252250 }, \ + { "SE15", 259250 }, \ + { "SE16", 266250 }, \ + { "SE17", 273250 }, \ + { "SE18", 280250 }, \ + { "SE19", 287250 }, \ + { "SE20", 294250 } + +#define FREQ_CCIR_H \ + { "S21", 303250 }, \ + { "S22", 311250 }, \ + { "S23", 319250 }, \ + { "S24", 327250 }, \ + { "S25", 335250 }, \ + { "S26", 343250 }, \ + { "S27", 351250 }, \ + { "S28", 359250 }, \ + { "S29", 367250 }, \ + { "S30", 375250 }, \ + { "S31", 383250 }, \ + { "S32", 391250 }, \ + { "S33", 399250 }, \ + { "S34", 407250 }, \ + { "S35", 415250 }, \ + { "S36", 423250 }, \ + { "S37", 431250 }, \ + { "S38", 439250 }, \ + { "S39", 447250 }, \ + { "S40", 455250 }, \ + { "S41", 463250 } + +/* OIRT frequencies */ + +#define FREQ_OIRT_I_III \ + { "R1", 49750 }, \ + { "R2", 59250 }, \ + \ + { "R3", 77250 }, \ + { "R4", 85250 }, \ + { "R5", 93250 }, \ + \ + { "R6", 175250 }, \ + { "R7", 183250 }, \ + { "R8", 191250 }, \ + { "R9", 199250 }, \ + { "R10", 207250 }, \ + { "R11", 215250 }, \ + { "R12", 223250 } + +#define FREQ_OIRT_SL_SH \ + { "SR1", 111250 }, \ + { "SR2", 119250 }, \ + { "SR3", 127250 }, \ + { "SR4", 135250 }, \ + { "SR5", 143250 }, \ + { "SR6", 151250 }, \ + { "SR7", 159250 }, \ + { "SR8", 167250 }, \ + \ + { "SR11", 231250 }, \ + { "SR12", 239250 }, \ + { "SR13", 247250 }, \ + { "SR14", 255250 }, \ + { "SR15", 263250 }, \ + { "SR16", 271250 }, \ + { "SR17", 279250 }, \ + { "SR18", 287250 }, \ + { "SR19", 295250 } + +#define FREQ_UHF \ + { "21", 471250 }, \ + { "22", 479250 }, \ + { "23", 487250 }, \ + { "24", 495250 }, \ + { "25", 503250 }, \ + { "26", 511250 }, \ + { "27", 519250 }, \ + { "28", 527250 }, \ + { "29", 535250 }, \ + { "30", 543250 }, \ + { "31", 551250 }, \ + { "32", 559250 }, \ + { "33", 567250 }, \ + { "34", 575250 }, \ + { "35", 583250 }, \ + { "36", 591250 }, \ + { "37", 599250 }, \ + { "38", 607250 }, \ + { "39", 615250 }, \ + { "40", 623250 }, \ + { "41", 631250 }, \ + { "42", 639250 }, \ + { "43", 647250 }, \ + { "44", 655250 }, \ + { "45", 663250 }, \ + { "46", 671250 }, \ + { "47", 679250 }, \ + { "48", 687250 }, \ + { "49", 695250 }, \ + { "50", 703250 }, \ + { "51", 711250 }, \ + { "52", 719250 }, \ + { "53", 727250 }, \ + { "54", 735250 }, \ + { "55", 743250 }, \ + { "56", 751250 }, \ + { "57", 759250 }, \ + { "58", 767250 }, \ + { "59", 775250 }, \ + { "60", 783250 }, \ + { "61", 791250 }, \ + { "62", 799250 }, \ + { "63", 807250 }, \ + { "64", 815250 }, \ + { "65", 823250 }, \ + { "66", 831250 }, \ + { "67", 839250 }, \ + { "68", 847250 }, \ + { "69", 855250 } + +static const struct CHANLIST europe_west[] = { + FREQ_CCIR_I_III, + FREQ_CCIR_SL_SH, + FREQ_CCIR_H, + FREQ_UHF +}; + +static const struct CHANLIST europe_east[] = { + FREQ_OIRT_I_III, + FREQ_OIRT_SL_SH, + FREQ_CCIR_I_III, + FREQ_CCIR_SL_SH, + FREQ_CCIR_H, + FREQ_UHF +}; + +static const struct CHANLIST pal_italy[] = { + { "A", 53750 }, + { "B", 62250 }, + { "C", 82250 }, + { "D", 175250 }, + { "E", 183750 }, + { "F", 192250 }, + { "G", 201250 }, + { "H", 210250 }, + { "H1", 217250 }, + { "H2", 224250 }, + FREQ_UHF +}; + +static const struct CHANLIST pal_ireland[] = { + { "0", 45750 }, + { "1", 53750 }, + { "2", 61750 }, + { "3", 175250 }, + { "4", 183250 }, + { "5", 191250 }, + { "6", 199250 }, + { "7", 207250 }, + { "8", 215250 }, + FREQ_UHF, +}; + +static const struct CHANLIST secam_france[] = { + { "K01", 47750 }, + { "K02", 55750 }, + { "K03", 60500 }, + { "K04", 63750 }, + { "K05", 176000 }, + { "K06", 184000 }, + { "K07", 192000 }, + { "K08", 200000 }, + { "K09", 208000 }, + { "K10", 216000 }, + { "KB", 116750 }, + { "KC", 128750 }, + { "KD", 140750 }, + { "KE", 159750 }, + { "KF", 164750 }, + { "KG", 176750 }, + { "KH", 188750 }, + { "KI", 200750 }, + { "KJ", 212750 }, + { "KK", 224750 }, + { "KL", 236750 }, + { "KM", 248750 }, + { "KN", 260750 }, + { "KO", 272750 }, + { "KP", 284750 }, + { "KQ", 296750 }, + { "H01", 303250 }, + { "H02", 311250 }, + { "H03", 319250 }, + { "H04", 327250 }, + { "H05", 335250 }, + { "H06", 343250 }, + { "H07", 351250 }, + { "H08", 359250 }, + { "H09", 367250 }, + { "H10", 375250 }, + { "H11", 383250 }, + { "H12", 391250 }, + { "H13", 399250 }, + { "H14", 407250 }, + { "H15", 415250 }, + { "H16", 423250 }, + { "H17", 431250 }, + { "H18", 439250 }, + { "H19", 447250 }, + FREQ_UHF, +}; + +/* --------------------------------------------------------------------- */ + +static const struct CHANLIST pal_newzealand[] = { + { "1", 45250 }, + { "2", 55250 }, + { "3", 62250 }, + { "4", 175250 }, + { "5", 182250 }, + { "6", 189250 }, + { "7", 196250 }, + { "8", 203250 }, + { "9", 210250 }, + { "10", 217250 }, + { "11", 224250 }, + FREQ_UHF, +}; + +/* --------------------------------------------------------------------- */ + +/* China broadcast */ +static const struct CHANLIST pal_bcast_cn[] = { + { "1", 49750 }, + { "2", 57750 }, + { "3", 65750 }, + { "4", 77250 }, + { "5", 85250 }, + { "6", 112250 }, + { "7", 120250 }, + { "8", 128250 }, + { "9", 136250 }, + { "10", 144250 }, + { "11", 152250 }, + { "12", 160250 }, + { "13", 168250 }, + { "14", 176250 }, + { "15", 184250 }, + { "16", 192250 }, + { "17", 200250 }, + { "18", 208250 }, + { "19", 216250 }, + { "20", 224250 }, + { "21", 232250 }, + { "22", 240250 }, + { "23", 248250 }, + { "24", 256250 }, + { "25", 264250 }, + { "26", 272250 }, + { "27", 280250 }, + { "28", 288250 }, + { "29", 296250 }, + { "30", 304250 }, + { "31", 312250 }, + { "32", 320250 }, + { "33", 328250 }, + { "34", 336250 }, + { "35", 344250 }, + { "36", 352250 }, + { "37", 360250 }, + { "38", 368250 }, + { "39", 376250 }, + { "40", 384250 }, + { "41", 392250 }, + { "42", 400250 }, + { "43", 408250 }, + { "44", 416250 }, + { "45", 424250 }, + { "46", 432250 }, + { "47", 440250 }, + { "48", 448250 }, + { "49", 456250 }, + { "50", 463250 }, + { "51", 471250 }, + { "52", 479250 }, + { "53", 487250 }, + { "54", 495250 }, + { "55", 503250 }, + { "56", 511250 }, + { "57", 519250 }, + { "58", 527250 }, + { "59", 535250 }, + { "60", 543250 }, + { "61", 551250 }, + { "62", 559250 }, + { "63", 607250 }, + { "64", 615250 }, + { "65", 623250 }, + { "66", 631250 }, + { "67", 639250 }, + { "68", 647250 }, + { "69", 655250 }, + { "70", 663250 }, + { "71", 671250 }, + { "72", 679250 }, + { "73", 687250 }, + { "74", 695250 }, + { "75", 703250 }, + { "76", 711250 }, + { "77", 719250 }, + { "78", 727250 }, + { "79", 735250 }, + { "80", 743250 }, + { "81", 751250 }, + { "82", 759250 }, + { "83", 767250 }, + { "84", 775250 }, + { "85", 783250 }, + { "86", 791250 }, + { "87", 799250 }, + { "88", 807250 }, + { "89", 815250 }, + { "90", 823250 }, + { "91", 831250 }, + { "92", 839250 }, + { "93", 847250 }, + { "94", 855250 }, +}; + +/* --------------------------------------------------------------------- */ +/* South Africa Broadcast */ + +static const struct CHANLIST pal_bcast_za[] ={ + { "1", 175250 }, + { "2", 183250 }, + { "3", 191250 }, + { "4", 199250 }, + { "5", 207250 }, + { "6", 215250 }, + { "7", 223250 }, + { "8", 231250 }, + FREQ_UHF +}; + +/* --------------------------------------------------------------------- */ + +static const struct CHANLIST argentina[] = { + { "001", 56250 }, + { "002", 62250 }, + { "003", 68250 }, + { "004", 78250 }, + { "005", 84250 }, + { "006", 176250 }, + { "007", 182250 }, + { "008", 188250 }, + { "009", 194250 }, + { "010", 200250 }, + { "011", 206250 }, + { "012", 212250 }, + { "013", 122250 }, + { "014", 128250 }, + { "015", 134250 }, + { "016", 140250 }, + { "017", 146250 }, + { "018", 152250 }, + { "019", 158250 }, + { "020", 164250 }, + { "021", 170250 }, + { "022", 218250 }, + { "023", 224250 }, + { "024", 230250 }, + { "025", 236250 }, + { "026", 242250 }, + { "027", 248250 }, + { "028", 254250 }, + { "029", 260250 }, + { "030", 266250 }, + { "031", 272250 }, + { "032", 278250 }, + { "033", 284250 }, + { "034", 290250 }, + { "035", 296250 }, + { "036", 302250 }, + { "037", 308250 }, + { "038", 314250 }, + { "039", 320250 }, + { "040", 326250 }, + { "041", 332250 }, + { "042", 338250 }, + { "043", 344250 }, + { "044", 350250 }, + { "045", 356250 }, + { "046", 362250 }, + { "047", 368250 }, + { "048", 374250 }, + { "049", 380250 }, + { "050", 386250 }, + { "051", 392250 }, + { "052", 398250 }, + { "053", 404250 }, + { "054", 410250 }, + { "055", 416250 }, + { "056", 422250 }, + { "057", 428250 }, + { "058", 434250 }, + { "059", 440250 }, + { "060", 446250 }, + { "061", 452250 }, + { "062", 458250 }, + { "063", 464250 }, + { "064", 470250 }, + { "065", 476250 }, + { "066", 482250 }, + { "067", 488250 }, + { "068", 494250 }, + { "069", 500250 }, + { "070", 506250 }, + { "071", 512250 }, + { "072", 518250 }, + { "073", 524250 }, + { "074", 530250 }, + { "075", 536250 }, + { "076", 542250 }, + { "077", 548250 }, + { "078", 554250 }, + { "079", 560250 }, + { "080", 566250 }, + { "081", 572250 }, + { "082", 578250 }, + { "083", 584250 }, + { "084", 590250 }, + { "085", 596250 }, + { "086", 602250 }, + { "087", 608250 }, + { "088", 614250 }, + { "089", 620250 }, + { "090", 626250 }, + { "091", 632250 }, + { "092", 638250 }, + { "093", 644250 }, +}; + +/* --------------------------------------------------------------------- */ + +static const struct CHANLIST russia[] = { + {"1", 49750 }, + {"2", 59250 }, + {"3", 77250 }, + {"4", 85250 }, + {"5", 93250 }, + {"SK1", 111250 }, + {"SK2", 119250 }, + {"SK3", 127250 }, + {"SK4", 135250 }, + {"SK5", 143250 }, + {"SK6", 151250 }, + {"SK7", 159250 }, + {"SK8", 167250 }, + {"6", 175250 }, + {"7", 183250 }, + {"8", 191250 }, + {"9", 199250 }, + {"10", 207250 }, + {"11", 215250 }, + {"12", 223250 }, + {"SK11", 231250 }, + {"SK12", 239250 }, + {"SK13", 247250 }, + {"SK14", 255250 }, + {"SK15", 263250 }, + {"SK16", 271250 }, + {"SK17", 279250 }, + {"SK18", 287250 }, + {"S19", 295250 }, + {"S20", 303250 }, + {"S21", 311250 }, + {"S22", 319250 }, + {"S23", 327250 }, + {"S24", 335250 }, + {"S25", 343250 }, + {"S26", 351250 }, + {"S27", 359250 }, + {"S28", 367250 }, + {"S29", 375250 }, + {"S30", 383250 }, + {"S31", 391250 }, + {"S32", 399250 }, + {"S33", 407250 }, + {"S34", 415250 }, + {"S35", 423250 }, + {"S36", 431250 }, + {"S37", 439250 }, + {"S38", 447250 }, + {"S39", 455250 }, + {"S40", 463250 }, + {"21", 471250 }, + {"22", 479250 }, + {"23", 487250 }, + {"24", 495250 }, + {"25", 503250 }, + {"26", 511250 }, + {"27", 519250 }, + {"28", 527250 }, + {"29", 535250 }, + {"30", 543250 }, + {"31", 551250 }, + {"32", 559250 }, + {"33", 567250 }, + {"34", 575250 }, + {"35", 583250 }, + {"36", 591250 }, + {"37", 599250 }, + {"38", 607250 }, + {"39", 615250 }, + {"40", 623250 }, + {"41", 631250 }, + {"42", 639250 }, + {"43", 647250 }, + {"44", 655250 }, + {"45", 663250 }, + {"46", 671250 }, + {"47", 679250 }, + {"48", 687250 }, + {"49", 695250 }, + {"50", 703250 }, + {"51", 711250 }, + {"52", 719250 }, + {"53", 727250 }, + {"54", 735250 }, + {"55", 743250 }, + {"56", 751250 }, + {"57", 759250 }, + {"58", 767250 }, + {"59", 775250 }, + {"60", 783250 }, + {"61", 791250 }, + {"62", 799250 }, + {"63", 807250 }, + {"64", 815250 }, + {"65", 523250 }, + {"66", 831250 }, + {"67", 839250 }, + {"68", 847250 }, + {"69", 855250 }, +}; +/* --------------------------------------------------------------------- */ + +const struct CHANLISTS chanlists[] = { + { "us-bcast", ntsc_bcast, CHAN_COUNT(ntsc_bcast) }, + { "us-cable", ntsc_cable, CHAN_COUNT(ntsc_cable) }, + { "us-cable-hrc", ntsc_hrc, CHAN_COUNT(ntsc_hrc) }, + { "japan-bcast", ntsc_bcast_jp, CHAN_COUNT(ntsc_bcast_jp) }, + { "japan-cable", ntsc_cable_jp, CHAN_COUNT(ntsc_cable_jp) }, + { "europe-west", europe_west, CHAN_COUNT(europe_west) }, + { "europe-east", europe_east, CHAN_COUNT(europe_east) }, + { "italy", pal_italy, CHAN_COUNT(pal_italy) }, + { "newzealand", pal_newzealand, CHAN_COUNT(pal_newzealand) }, + { "australia", pal_australia, CHAN_COUNT(pal_australia) }, + { "ireland", pal_ireland, CHAN_COUNT(pal_ireland) }, + { "france", secam_france, CHAN_COUNT(secam_france) }, + { "china-bcast", pal_bcast_cn, CHAN_COUNT(pal_bcast_cn) }, + { "southafrica", pal_bcast_za, CHAN_COUNT(pal_bcast_za) }, + { "argentina", argentina, CHAN_COUNT(argentina) }, + { "russia", russia, CHAN_COUNT(russia) }, + { NULL, NULL, 0 } /* EOF */ +}; + +int chantab = 5; +const struct CHANLIST *chanlist = europe_west; +int chancount = CHAN_COUNT(europe_west);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/frequencies.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,111 @@ +/* + * Worldwide channel/frequency list + * + * Nathan Laredo (laredo@broked.net) + * + * Frequencies are given in kHz + */ +#define NTSC_AUDIO_CARRIER 4500 +#define PAL_AUDIO_CARRIER_I 6000 +#define PAL_AUDIO_CARRIER_BGHN 5500 +#define PAL_AUDIO_CARRIER_MN 4500 +#define PAL_AUDIO_CARRIER_D 6500 +#define SEACAM_AUDIO_DKK1L 6500 +#define SEACAM_AUDIO_BG 5500 +/* NICAM 728 32-kHz, 14-bit digital stereo audio is transmitted in 1ms frames + containing 8 bits frame sync, 5 bits control, 11 bits additional data, and + 704 bits audio data. The bit rate is reduced by transmitting only 10 bits + plus parity of each 14 bit sample, the largest sample in a frame determines + which 10 bits are transmitted. The parity bits for audio samples also + specify the scaling factor used for that channel during that frame. The + companeded audio data is interleaved to reduce the influence of dropouts + and the whole frame except for sync bits is scrambled for spectrum shaping. + Data is modulated using QPSK, at below following subcarrier freqs */ +#define NICAM728_PAL_BGH 5850 +#define NICAM728_PAL_I 6552 + +/* COMPREHENSIVE LIST OF FORMAT BY COUNTRY + (M) NTSC used in: + Antigua, Aruba, Bahamas, Barbados, Belize, Bermuda, Bolivia, Burma, + Canada, Chile, Colombia, Costa Rica, Cuba, Curacao, Dominican Republic, + Ecuador, El Salvador, Guam Guatemala, Honduras, Jamaica, Japan, + South Korea, Mexico, Montserrat, Myanmar, Nicaragua, Panama, Peru, + Philippines, Puerto Rico, St Christopher and Nevis, Samoa, Suriname, + Taiwan, Trinidad/Tobago, United States, Venezuela, Virgin Islands + (B) PAL used in: + Albania, Algeria, Australia, Austria, Bahrain, Bangladesh, Belgium, + Bosnia-Herzegovinia, Brunei Darussalam, Cambodia, Cameroon, Croatia, + Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, Finland, Germany, + Ghana, Gibraltar, Greenland, Iceland, India, Indonesia, Israel, Italy, + Jordan, Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysa, Maldives, + Malta, Nepal, Netherlands, New Zeland, Nigeria, Norway, Oman, Pakistan, + Papua New Guinea, Portugal, Qatar, Sao Tome and Principe, Saudi Arabia, + Seychelles, Sierra Leone, Singapore, Slovenia, Somali, Spain, + Sri Lanka, Sudan, Swaziland, Sweden, Switzeland, Syria, Thailand, + Tunisia, Turkey, Uganda, United Arab Emirates, Yemen + (N) PAL used in: (Combination N = 4.5MHz audio carrier, 3.58MHz burst) + Argentina (Combination N), Paraguay, Uruguay + (M) PAL (525/60, 3.57MHz burst) used in: + Brazil + (G) PAL used in: + Albania, Algeria, Austria, Bahrain, Bosnia/Herzegovinia, Cambodia, + Cameroon, Croatia, Cyprus, Denmark, Egypt, Ethiopia, Equatorial Guinea, + Finland, Germany, Gibraltar, Greenland, Iceland, Israel, Italy, Jordan, + Kenya, Kuwait, Liberia, Libya, Luxembourg, Malaysia, Monaco, + Mozambique, Netherlands, New Zealand, Norway, Oman, Pakistan, + Papa New Guinea, Portugal, Qatar, Romania, Sierra Leone, Singapore, + Slovenia, Somalia, Spain, Sri Lanka, Sudan, Swaziland, Sweeden, + Switzerland, Syria, Thailand, Tunisia, Turkey, United Arab Emirates, + Yemen, Zambia, Zimbabwe + (D) PAL used in: + China, North Korea, Romania, Czech Republic + (H) PAL used in: + Belgium + (I) PAL used in: + Angola, Botswana, Gambia, Guinea-Bissau, Hong Kong, Ireland, Lesotho, + Malawi, Nambia, Nigeria, South Africa, Tanzania, United Kingdom, + Zanzibar + (B) SECAM used in: + Djibouti, Greece, Iran, Iraq, Lebanon, Mali, Mauritania, Mauritus, + Morocco + (D) SECAM used in: + Afghanistan, Armenia, Azerbaijan, Belarus, Bulgaria, + Estonia, Georgia, Hungary, Zazakhstan, Lithuania, Mongolia, Moldova, + Russia, Slovak Republic, Ukraine, Vietnam + (G) SECAM used in: + Greecem Iran, Iraq, Mali, Mauritus, Morocco, Saudi Arabia + (K) SECAM used in: + Armenia, Azerbaijan, Bulgaria, Estonia, Georgia, + Hungary, Kazakhstan, Lithuania, Madagascar, Moldova, Poland, Russia, + Slovak Republic, Ukraine, Vietnam + (K1) SECAM used in: + Benin, Burkina Faso, Burundi, Chad, Cape Verde, Central African + Republic, Comoros, Congo, Gabon, Madagascar, Niger, Rwanda, Senegal, + Togo, Zaire + (L) SECAM used in: + France +*/ + +/* --------------------------------------------------------------------- */ + +struct CHANLIST { + char name[8]; + int freq; +}; + +struct CHANLISTS { + const char *name; + const struct CHANLIST *list; + int count; +}; + +#define CHAN_COUNT(x) (sizeof(x)/sizeof(struct CHANLIST)) + +/* --------------------------------------------------------------------- */ + +extern const struct CHANLISTS chanlists[]; +//extern struct STRTAB chanlist_names[]; + +extern int chantab; +extern const struct CHANLIST *chanlist; +extern int chancount;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/http.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,948 @@ +/* + * HTTP Helper + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#endif + +#include "http.h" +#include "url.h" +#include "mp_msg.h" + +#include "stream.h" +#include "demuxer.h" +#include "network.h" +#include "help_mp.h" + + +extern mime_struct_t mime_type_table[]; +extern int stream_cache_size; +extern int network_bandwidth; + +extern int http_seek(stream_t *stream, off_t pos); + +typedef struct { + unsigned metaint; + unsigned metapos; + int is_ultravox; +} scast_data_t; + +/** + * \brief first read any data from sc->buffer then from fd + * \param fd file descriptor to read data from + * \param buffer buffer to read into + * \param len how many bytes to read + * \param sc streaming control containing buffer to read from first + * \return len unless there is a read error or eof + */ +static unsigned my_read(int fd, char *buffer, int len, streaming_ctrl_t *sc) { + unsigned pos = 0; + unsigned cp_len = sc->buffer_size - sc->buffer_pos; + if (cp_len > len) + cp_len = len; + memcpy(buffer, &sc->buffer[sc->buffer_pos], cp_len); + sc->buffer_pos += cp_len; + pos += cp_len; + while (pos < len) { + int ret = recv(fd, &buffer[pos], len - pos, 0); + if (ret <= 0) + break; + pos += ret; + } + return pos; +} + +/** + * \brief read and process (i.e. discard *g*) a block of ultravox metadata + * \param fd file descriptor to read from + * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd + * \return number of real data before next metadata block starts or 0 on error + */ +static unsigned uvox_meta_read(int fd, streaming_ctrl_t *sc) { + unsigned metaint; + unsigned char info[6] = {0, 0, 0, 0, 0, 0}; + int info_read; + do { + info_read = my_read(fd, info, 1, sc); + if (info[0] == 0x00) + info_read = my_read(fd, info, 6, sc); + else + info_read += my_read(fd, &info[1], 5, sc); + if (info_read != 6) // read error or eof + return 0; + // sync byte and reserved flags + if (info[0] != 0x5a || (info[1] & 0xfc) != 0x00) { + mp_msg(MSGT_DEMUXER, MSGL_ERR, "Invalid or unknown uvox metadata\n"); + return 0; + } + if (info[1] & 0x01) + mp_msg(MSGT_DEMUXER, MSGL_WARN, "Encrypted ultravox data\n"); + metaint = info[4] << 8 | info[5]; + if ((info[3] & 0xf) < 0x07) { // discard any metadata nonsense + char *metabuf = malloc(metaint); + my_read(fd, metabuf, metaint, sc); + free(metabuf); + } + } while ((info[3] & 0xf) < 0x07); + return metaint; +} + +/** + * \brief read one scast meta data entry and print it + * \param fd file descriptor to read from + * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd + */ +static void scast_meta_read(int fd, streaming_ctrl_t *sc) { + unsigned char tmp = 0; + unsigned metalen; + my_read(fd, &tmp, 1, sc); + metalen = tmp * 16; + if (metalen > 0) { + char *info = malloc(metalen + 1); + unsigned nlen = my_read(fd, info, metalen, sc); + info[nlen] = 0; + mp_msg(MSGT_DEMUXER, MSGL_INFO, "\nICY Info: %s\n", info); + free(info); + } +} + +/** + * \brief read data from scast/ultravox stream without any metadata + * \param fd file descriptor to read from + * \param buffer buffer to read data into + * \param size number of bytes to read + * \param sc streaming_ctrl_t whose buffer is consumed before reading from fd + */ +static int scast_streaming_read(int fd, char *buffer, int size, + streaming_ctrl_t *sc) { + scast_data_t *sd = (scast_data_t *)sc->data; + unsigned block, ret; + unsigned done = 0; + + // first read remaining data up to next metadata + block = sd->metaint - sd->metapos; + if (block > size) + block = size; + ret = my_read(fd, buffer, block, sc); + sd->metapos += ret; + done += ret; + if (ret != block) // read problems or eof + size = done; + + while (done < size) { // now comes the metadata + if (sd->is_ultravox) + { + sd->metaint = uvox_meta_read(fd, sc); + if (!sd->metaint) + size = done; + } + else + scast_meta_read(fd, sc); // read and display metadata + sd->metapos = 0; + block = size - done; + if (block > sd->metaint) + block = sd->metaint; + ret = my_read(fd, &buffer[done], block, sc); + sd->metapos += ret; + done += ret; + if (ret != block) // read problems or eof + size = done; + } + return done; +} + +static int scast_streaming_start(stream_t *stream) { + int metaint; + scast_data_t *scast_data; + HTTP_header_t *http_hdr = stream->streaming_ctrl->data; + int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; + if (!stream || stream->fd < 0 || !http_hdr) + return -1; + if (is_ultravox) + metaint = 0; + else { + metaint = atoi(http_get_field(http_hdr, "Icy-MetaInt")); + if (metaint <= 0) + return -1; + } + stream->streaming_ctrl->buffer = malloc(http_hdr->body_size); + stream->streaming_ctrl->buffer_size = http_hdr->body_size; + stream->streaming_ctrl->buffer_pos = 0; + memcpy(stream->streaming_ctrl->buffer, http_hdr->body, http_hdr->body_size); + scast_data = malloc(sizeof(scast_data_t)); + scast_data->metaint = metaint; + scast_data->metapos = 0; + scast_data->is_ultravox = is_ultravox; + http_free(http_hdr); + stream->streaming_ctrl->data = scast_data; + stream->streaming_ctrl->streaming_read = scast_streaming_read; + stream->streaming_ctrl->streaming_seek = NULL; + stream->streaming_ctrl->prebuffer_size = 64 * 1024; // 64 KBytes + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + return 0; +} + +static int nop_streaming_start( stream_t *stream ) { + HTTP_header_t *http_hdr = NULL; + char *next_url=NULL; + URL_t *rd_url=NULL; + int fd,ret; + if( stream==NULL ) return -1; + + fd = stream->fd; + if( fd<0 ) { + fd = http_send_request( stream->streaming_ctrl->url, 0 ); + if( fd<0 ) return -1; + http_hdr = http_read_response( fd ); + if( http_hdr==NULL ) return -1; + + switch( http_hdr->status_code ) { + case 200: // OK + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); + if( http_hdr->body_size>0 ) { + if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { + http_free( http_hdr ); + return -1; + } + } + break; + // Redirect + case 301: // Permanently + case 302: // Temporarily + ret=-1; + next_url = http_get_field( http_hdr, "Location" ); + + if (next_url != NULL) + rd_url=url_new(next_url); + + if (next_url != NULL && rd_url != NULL) { + mp_msg(MSGT_NETWORK,MSGL_STATUS,"Redirected: Using this url instead %s\n",next_url); + stream->streaming_ctrl->url=check4proxies(rd_url); + ret=nop_streaming_start(stream); //recursively get streaming started + } else { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n"); + closesocket( fd ); + fd = -1; + } + return ret; + break; + case 401: //Authorization required + case 403: //Forbidden + case 404: //Not found + case 500: //Server Error + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); + closesocket( fd ); + fd = -1; + return -1; + break; + } + stream->fd = fd; + } else { + http_hdr = (HTTP_header_t*)stream->streaming_ctrl->data; + if( http_hdr->body_size>0 ) { + if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { + http_free( http_hdr ); + stream->streaming_ctrl->data = NULL; + return -1; + } + } + } + + if( http_hdr ) { + http_free( http_hdr ); + stream->streaming_ctrl->data = NULL; + } + + stream->streaming_ctrl->streaming_read = nop_streaming_read; + stream->streaming_ctrl->streaming_seek = nop_streaming_seek; + stream->streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + return 0; +} + +HTTP_header_t * +http_new_header(void) { + HTTP_header_t *http_hdr; + + http_hdr = malloc(sizeof(HTTP_header_t)); + if( http_hdr==NULL ) return NULL; + memset( http_hdr, 0, sizeof(HTTP_header_t) ); + + return http_hdr; +} + +void +http_free( HTTP_header_t *http_hdr ) { + HTTP_field_t *field, *field2free; + if( http_hdr==NULL ) return; + if( http_hdr->protocol!=NULL ) free( http_hdr->protocol ); + if( http_hdr->uri!=NULL ) free( http_hdr->uri ); + if( http_hdr->reason_phrase!=NULL ) free( http_hdr->reason_phrase ); + if( http_hdr->field_search!=NULL ) free( http_hdr->field_search ); + if( http_hdr->method!=NULL ) free( http_hdr->method ); + if( http_hdr->buffer!=NULL ) free( http_hdr->buffer ); + field = http_hdr->first_field; + while( field!=NULL ) { + field2free = field; + if (field->field_name) + free(field->field_name); + field = field->next; + free( field2free ); + } + free( http_hdr ); + http_hdr = NULL; +} + +int +http_response_append( HTTP_header_t *http_hdr, char *response, int length ) { + if( http_hdr==NULL || response==NULL || length<0 ) return -1; + + if( (unsigned)length > SIZE_MAX - http_hdr->buffer_size - 1) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Bad size in memory (re)allocation\n"); + return -1; + } + http_hdr->buffer = (char*)realloc( http_hdr->buffer, http_hdr->buffer_size+length+1 ); + if( http_hdr->buffer==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory (re)allocation failed\n"); + return -1; + } + memcpy( http_hdr->buffer+http_hdr->buffer_size, response, length ); + http_hdr->buffer_size += length; + http_hdr->buffer[http_hdr->buffer_size]=0; // close the string! + return http_hdr->buffer_size; +} + +int +http_is_header_entire( HTTP_header_t *http_hdr ) { + if( http_hdr==NULL ) return -1; + if( http_hdr->buffer==NULL ) return 0; // empty + + if( strstr(http_hdr->buffer, "\r\n\r\n")==NULL && + strstr(http_hdr->buffer, "\n\n")==NULL ) return 0; + return 1; +} + +int +http_response_parse( HTTP_header_t *http_hdr ) { + char *hdr_ptr, *ptr; + char *field=NULL; + int pos_hdr_sep, hdr_sep_len; + size_t len; + if( http_hdr==NULL ) return -1; + if( http_hdr->is_parsed ) return 0; + + // Get the protocol + hdr_ptr = strstr( http_hdr->buffer, " " ); + if( hdr_ptr==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. No space separator found.\n"); + return -1; + } + len = hdr_ptr-http_hdr->buffer; + http_hdr->protocol = malloc(len+1); + if( http_hdr->protocol==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return -1; + } + strncpy( http_hdr->protocol, http_hdr->buffer, len ); + http_hdr->protocol[len]='\0'; + if( !strncasecmp( http_hdr->protocol, "HTTP", 4) ) { + if( sscanf( http_hdr->protocol+5,"1.%d", &(http_hdr->http_minor_version) )!=1 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get HTTP minor version.\n"); + return -1; + } + } + + // Get the status code + if( sscanf( ++hdr_ptr, "%d", &(http_hdr->status_code) )!=1 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get status code.\n"); + return -1; + } + hdr_ptr += 4; + + // Get the reason phrase + ptr = strstr( hdr_ptr, "\n" ); + if( hdr_ptr==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Malformed answer. Unable to get the reason phrase.\n"); + return -1; + } + len = ptr-hdr_ptr; + http_hdr->reason_phrase = malloc(len+1); + if( http_hdr->reason_phrase==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return -1; + } + strncpy( http_hdr->reason_phrase, hdr_ptr, len ); + if( http_hdr->reason_phrase[len-1]=='\r' ) { + len--; + } + http_hdr->reason_phrase[len]='\0'; + + // Set the position of the header separator: \r\n\r\n + hdr_sep_len = 4; + ptr = strstr( http_hdr->buffer, "\r\n\r\n" ); + if( ptr==NULL ) { + ptr = strstr( http_hdr->buffer, "\n\n" ); + if( ptr==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Header may be incomplete. No CRLF CRLF found.\n"); + return -1; + } + hdr_sep_len = 2; + } + pos_hdr_sep = ptr-http_hdr->buffer; + + // Point to the first line after the method line. + hdr_ptr = strstr( http_hdr->buffer, "\n" )+1; + do { + ptr = hdr_ptr; + while( *ptr!='\r' && *ptr!='\n' ) ptr++; + len = ptr-hdr_ptr; + if( len==0 ) break; + field = (char*)realloc(field, len+1); + if( field==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); + return -1; + } + strncpy( field, hdr_ptr, len ); + field[len]='\0'; + http_set_field( http_hdr, field ); + hdr_ptr = ptr+((*ptr=='\r')?2:1); + } while( hdr_ptr<(http_hdr->buffer+pos_hdr_sep) ); + + if( field!=NULL ) free( field ); + + if( pos_hdr_sep+hdr_sep_len<http_hdr->buffer_size ) { + // Response has data! + http_hdr->body = http_hdr->buffer+pos_hdr_sep+hdr_sep_len; + http_hdr->body_size = http_hdr->buffer_size-(pos_hdr_sep+hdr_sep_len); + } + + http_hdr->is_parsed = 1; + return 0; +} + +char * +http_build_request( HTTP_header_t *http_hdr ) { + char *ptr, *uri=NULL; + int len; + HTTP_field_t *field; + if( http_hdr==NULL ) return NULL; + + if( http_hdr->method==NULL ) http_set_method( http_hdr, "GET"); + if( http_hdr->uri==NULL ) http_set_uri( http_hdr, "/"); + else { + uri = malloc(strlen(http_hdr->uri) + 1); + if( uri==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); + return NULL; + } + strcpy(uri,http_hdr->uri); + } + + //**** Compute the request length + // Add the Method line + len = strlen(http_hdr->method)+strlen(uri)+12; + // Add the fields + field = http_hdr->first_field; + while( field!=NULL ) { + len += strlen(field->field_name)+2; + field = field->next; + } + // Add the CRLF + len += 2; + // Add the body + if( http_hdr->body!=NULL ) { + len += http_hdr->body_size; + } + // Free the buffer if it was previously used + if( http_hdr->buffer!=NULL ) { + free( http_hdr->buffer ); + http_hdr->buffer = NULL; + } + http_hdr->buffer = malloc(len+1); + if( http_hdr->buffer==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Memory allocation failed\n"); + return NULL; + } + http_hdr->buffer_size = len; + + //*** Building the request + ptr = http_hdr->buffer; + // Add the method line + ptr += sprintf( ptr, "%s %s HTTP/1.%d\r\n", http_hdr->method, uri, http_hdr->http_minor_version ); + field = http_hdr->first_field; + // Add the field + while( field!=NULL ) { + ptr += sprintf( ptr, "%s\r\n", field->field_name ); + field = field->next; + } + ptr += sprintf( ptr, "\r\n" ); + // Add the body + if( http_hdr->body!=NULL ) { + memcpy( ptr, http_hdr->body, http_hdr->body_size ); + } + + if( uri ) free( uri ); + return http_hdr->buffer; +} + +char * +http_get_field( HTTP_header_t *http_hdr, const char *field_name ) { + if( http_hdr==NULL || field_name==NULL ) return NULL; + http_hdr->field_search_pos = http_hdr->first_field; + http_hdr->field_search = (char*)realloc( http_hdr->field_search, strlen(field_name)+1 ); + if( http_hdr->field_search==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return NULL; + } + strcpy( http_hdr->field_search, field_name ); + return http_get_next_field( http_hdr ); +} + +char * +http_get_next_field( HTTP_header_t *http_hdr ) { + char *ptr; + HTTP_field_t *field; + if( http_hdr==NULL ) return NULL; + + field = http_hdr->field_search_pos; + while( field!=NULL ) { + ptr = strstr( field->field_name, ":" ); + if( ptr==NULL ) return NULL; + if( !strncasecmp( field->field_name, http_hdr->field_search, ptr-(field->field_name) ) ) { + ptr++; // Skip the column + while( ptr[0]==' ' ) ptr++; // Skip the spaces if there is some + http_hdr->field_search_pos = field->next; + return ptr; // return the value without the field name + } + field = field->next; + } + return NULL; +} + +void +http_set_field( HTTP_header_t *http_hdr, const char *field_name ) { + HTTP_field_t *new_field; + if( http_hdr==NULL || field_name==NULL ) return; + + new_field = malloc(sizeof(HTTP_field_t)); + if( new_field==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return; + } + new_field->next = NULL; + new_field->field_name = malloc(strlen(field_name)+1); + if( new_field->field_name==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return; + } + strcpy( new_field->field_name, field_name ); + + if( http_hdr->last_field==NULL ) { + http_hdr->first_field = new_field; + } else { + http_hdr->last_field->next = new_field; + } + http_hdr->last_field = new_field; + http_hdr->field_nb++; +} + +void +http_set_method( HTTP_header_t *http_hdr, const char *method ) { + if( http_hdr==NULL || method==NULL ) return; + + http_hdr->method = malloc(strlen(method)+1); + if( http_hdr->method==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return; + } + strcpy( http_hdr->method, method ); +} + +void +http_set_uri( HTTP_header_t *http_hdr, const char *uri ) { + if( http_hdr==NULL || uri==NULL ) return; + + http_hdr->uri = malloc(strlen(uri)+1); + if( http_hdr->uri==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + return; + } + strcpy( http_hdr->uri, uri ); +} + +int +http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ) { + char *auth = NULL, *usr_pass = NULL, *b64_usr_pass = NULL; + int encoded_len, pass_len=0, out_len; + int res = -1; + if( http_hdr==NULL || username==NULL ) return -1; + + if( password!=NULL ) { + pass_len = strlen(password); + } + + usr_pass = malloc(strlen(username)+pass_len+2); + if( usr_pass==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + goto out; + } + + sprintf( usr_pass, "%s:%s", username, (password==NULL)?"":password ); + + // Base 64 encode with at least 33% more data than the original size + encoded_len = strlen(usr_pass)*2; + b64_usr_pass = malloc(encoded_len); + if( b64_usr_pass==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + goto out; + } + + out_len = base64_encode( usr_pass, strlen(usr_pass), b64_usr_pass, encoded_len); + if( out_len<0 ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Base64 out overflow\n"); + goto out; + } + + b64_usr_pass[out_len]='\0'; + + auth = malloc(encoded_len+22); + if( auth==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,"Memory allocation failed\n"); + goto out; + } + + sprintf( auth, "Authorization: Basic %s", b64_usr_pass); + http_set_field( http_hdr, auth ); + res = 0; + +out: + free( usr_pass ); + free( b64_usr_pass ); + free( auth ); + + return res; +} + +void +http_debug_hdr( HTTP_header_t *http_hdr ) { + HTTP_field_t *field; + int i = 0; + if( http_hdr==NULL ) return; + + mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- START ---\n"); + mp_msg(MSGT_NETWORK,MSGL_V,"protocol: [%s]\n", http_hdr->protocol ); + mp_msg(MSGT_NETWORK,MSGL_V,"http minor version: [%d]\n", http_hdr->http_minor_version ); + mp_msg(MSGT_NETWORK,MSGL_V,"uri: [%s]\n", http_hdr->uri ); + mp_msg(MSGT_NETWORK,MSGL_V,"method: [%s]\n", http_hdr->method ); + mp_msg(MSGT_NETWORK,MSGL_V,"status code: [%d]\n", http_hdr->status_code ); + mp_msg(MSGT_NETWORK,MSGL_V,"reason phrase: [%s]\n", http_hdr->reason_phrase ); + mp_msg(MSGT_NETWORK,MSGL_V,"body size: [%d]\n", http_hdr->body_size ); + + mp_msg(MSGT_NETWORK,MSGL_V,"Fields:\n"); + field = http_hdr->first_field; + while( field!=NULL ) { + mp_msg(MSGT_NETWORK,MSGL_V," %d - %s\n", i++, field->field_name ); + field = field->next; + } + mp_msg(MSGT_NETWORK,MSGL_V,"--- HTTP DEBUG HEADER --- END ---\n"); +} + +int +base64_encode(const void *enc, int encLen, char *out, int outMax) { + static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + unsigned char *encBuf; + int outLen; + unsigned int bits; + unsigned int shift; + + encBuf = (unsigned char*)enc; + outLen = 0; + bits = 0; + shift = 0; + outMax &= ~3; + + while( outLen<outMax ) { + if( encLen>0 ) { + // Shift in byte + bits <<= 8; + bits |= *encBuf; + shift += 8; + // Next byte + encBuf++; + encLen--; + } else if( shift>0 ) { + // Pad last bits to 6 bits - will end next loop + bits <<= 6 - shift; + shift = 6; + } else { + // As per RFC 2045, section 6.8, + // pad output as necessary: 0 to 2 '=' chars. + while( outLen & 3 ){ + *out++ = '='; + outLen++; + } + + return outLen; + } + + // Encode 6 bit segments + while( shift>=6 ) { + shift -= 6; + *out = b64[ (bits >> shift) & 0x3F ]; + out++; + outLen++; + } + } + + // Output overflow + return -1; +} + +static int http_streaming_start(stream_t *stream, int* file_format) { + HTTP_header_t *http_hdr; + unsigned int i; + int fd=-1; + int redirect = 0; + int auth_retry=0; + int seekable=0; + char *content_type; + char *next_url; + URL_t *url = stream->streaming_ctrl->url; + + do + { + fd = http_send_request( url, 0 ); + if( fd<0 ) { + return -1; + } + + http_hdr = http_read_response( fd ); + if( http_hdr==NULL ) { + closesocket( fd ); + http_free( http_hdr ); + return -1; + } + + stream->fd=fd; + if( mp_msg_test(MSGT_NETWORK,MSGL_V) ) { + http_debug_hdr( http_hdr ); + } + + stream->streaming_ctrl->data = (void*)http_hdr; + + // Check if we can make partial content requests and thus seek in http-streams + if( http_hdr!=NULL && http_hdr->status_code==200 ) { + char *accept_ranges; + if( (accept_ranges = http_get_field(http_hdr,"Accept-Ranges")) != NULL ) + seekable = strncmp(accept_ranges,"bytes",5)==0; + } + + // Check if the response is an ICY status_code reason_phrase + if( !strcasecmp(http_hdr->protocol, "ICY") ) { + switch( http_hdr->status_code ) { + case 200: { // OK + char *field_data = NULL; + // note: I skip icy-notice1 and 2, as they contain html <BR> + // and are IMHO useless info ::atmos + if( (field_data = http_get_field(http_hdr, "icy-name")) != NULL ) + mp_msg(MSGT_NETWORK,MSGL_INFO,"Name : %s\n", field_data); field_data = NULL; + if( (field_data = http_get_field(http_hdr, "icy-genre")) != NULL ) + mp_msg(MSGT_NETWORK,MSGL_INFO,"Genre : %s\n", field_data); field_data = NULL; + if( (field_data = http_get_field(http_hdr, "icy-url")) != NULL ) + mp_msg(MSGT_NETWORK,MSGL_INFO,"Website: %s\n", field_data); field_data = NULL; + // XXX: does this really mean public server? ::atmos + if( (field_data = http_get_field(http_hdr, "icy-pub")) != NULL ) + mp_msg(MSGT_NETWORK,MSGL_INFO,"Public : %s\n", atoi(field_data)?"yes":"no"); field_data = NULL; + if( (field_data = http_get_field(http_hdr, "icy-br")) != NULL ) + mp_msg(MSGT_NETWORK,MSGL_INFO,"Bitrate: %skbit/s\n", field_data); field_data = NULL; + + // If content-type == video/nsv we most likely have a winamp video stream + // otherwise it should be mp3. if there are more types consider adding mime type + // handling like later + if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "video/nsv") || !strcmp(field_data, "misc/ultravox"))) + *file_format = DEMUXER_TYPE_NSV; + else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac"))) + *file_format = DEMUXER_TYPE_AAC; + else + *file_format = DEMUXER_TYPE_AUDIO; + return 0; + } + case 400: // Server Full + mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server is full, skipping!\n"); + return -1; + case 401: // Service Unavailable + mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return service unavailable, skipping!\n"); + return -1; + case 403: // Service Forbidden + mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server return 'Service Forbidden'\n"); + return -1; + case 404: // Resource Not Found + mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: ICY-Server couldn't find requested stream, skipping!\n"); + return -1; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Error: unhandled ICY-Errorcode, contact MPlayer developers!\n"); + return -1; + } + } + + // Assume standard http if not ICY + switch( http_hdr->status_code ) { + case 200: // OK + // Look if we can use the Content-Type + content_type = http_get_field( http_hdr, "Content-Type" ); + if( content_type!=NULL ) { + char *content_length = NULL; + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", content_type ); + if( (content_length = http_get_field(http_hdr, "Content-Length")) != NULL) + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length")); + // Check in the mime type table for a demuxer type + i = 0; + while(mime_type_table[i].mime_type != NULL) { + if( !strcasecmp( content_type, mime_type_table[i].mime_type ) ) { + *file_format = mime_type_table[i].demuxer_type; + return seekable; + } + i++; + } + } + // Not found in the mime type table, don't fail, + // we should try raw HTTP + return seekable; + // Redirect + case 301: // Permanently + case 302: // Temporarily + // TODO: RFC 2616, recommand to detect infinite redirection loops + next_url = http_get_field( http_hdr, "Location" ); + if( next_url!=NULL ) { + closesocket( fd ); + url_free( url ); + stream->streaming_ctrl->url = url = url_new( next_url ); + http_free( http_hdr ); + redirect = 1; + } + break; + case 401: // Authentication required + if( http_authenticate(http_hdr, url, &auth_retry)<0 ) return STREAM_UNSUPORTED; + redirect = 1; + break; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase ); + return -1; + } + } while( redirect ); + + return -1; +} + +static int fixup_open(stream_t *stream,int seekable) { + HTTP_header_t *http_hdr = stream->streaming_ctrl->data; + int is_icy = http_hdr && http_get_field(http_hdr, "Icy-MetaInt"); + int is_ultravox = strcasecmp(stream->streaming_ctrl->url->protocol, "unsv") == 0; + + stream->type = STREAMTYPE_STREAM; + if(!is_icy && !is_ultravox && seekable) + { + stream->flags |= STREAM_SEEK; + stream->seek = http_seek; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + if ((!is_icy && !is_ultravox) || scast_streaming_start(stream)) + if(nop_streaming_start( stream )) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n"); + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + fixup_network_stream_cache(stream); + return STREAM_OK; +} + +static int open_s1(stream_t *stream,int mode, void* opts, int* file_format) { + int seekable=0; + URL_t *url; + + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + url_free(url); + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_HTTP(1), URL: %s\n", stream->url); + seekable = http_streaming_start(stream, file_format); + if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) { + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + return fixup_open(stream, seekable); +} + +static int open_s2(stream_t *stream,int mode, void* opts, int* file_format) { + int seekable=0; + URL_t *url; + + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + url_free(url); + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_HTTP(2), URL: %s\n", stream->url); + seekable = http_streaming_start(stream, file_format); + if(seekable < 0) { + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + return fixup_open(stream, seekable); +} + + +stream_info_t stream_info_http1 = { + "http streaming", + "null", + "Bertrand, Albeau, Reimar Doeffinger, Arpi?", + "plain http", + open_s1, + {"http", "http_proxy", "unsv", NULL}, + NULL, + 0 // Urls are an option string +}; + +stream_info_t stream_info_http2 = { + "http streaming", + "null", + "Bertrand, Albeu, Arpi? who?", + "plain http, also used as fallback for many other protocols", + open_s2, + {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL}, //all the others as fallback + NULL, + 0 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/http.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,52 @@ +/* + * HTTP Helper + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + */ + +#ifndef __HTTP_H +#define __HTTP_H + +typedef struct HTTP_field_type { + char *field_name; + struct HTTP_field_type *next; +} HTTP_field_t; + +typedef struct { + char *protocol; + char *method; + char *uri; + unsigned int status_code; + char *reason_phrase; + unsigned int http_minor_version; + // Field variables + HTTP_field_t *first_field; + HTTP_field_t *last_field; + unsigned int field_nb; + char *field_search; + HTTP_field_t *field_search_pos; + // Body variables + char *body; + size_t body_size; + char *buffer; + size_t buffer_size; + unsigned int is_parsed; +} HTTP_header_t; + +HTTP_header_t* http_new_header(void); +void http_free( HTTP_header_t *http_hdr ); +int http_response_append( HTTP_header_t *http_hdr, char *data, int length ); +int http_response_parse( HTTP_header_t *http_hdr ); +int http_is_header_entire( HTTP_header_t *http_hdr ); +char* http_build_request( HTTP_header_t *http_hdr ); +char* http_get_field( HTTP_header_t *http_hdr, const char *field_name ); +char* http_get_next_field( HTTP_header_t *http_hdr ); +void http_set_field( HTTP_header_t *http_hdr, const char *field_name ); +void http_set_method( HTTP_header_t *http_hdr, const char *method ); +void http_set_uri( HTTP_header_t *http_hdr, const char *uri ); +int http_add_basic_authentication( HTTP_header_t *http_hdr, const char *username, const char *password ); + +void http_debug_hdr( HTTP_header_t *http_hdr ); + +int base64_encode(const void *enc, int encLen, char *out, int outMax); +#endif // __HTTP_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,804 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp.c,v 1.9 2003/04/10 02:30:48 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * a minimalistic implementation of rtsp protocol, + * *not* RFC 2326 compilant yet. + * + * 2006, Benjamin Zores and Vincent Mussard + * fixed a lot of RFC compliance issues. + */ + +#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include "config.h" +#ifndef HAVE_WINSOCK2 +#define closesocket close +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#else +#include <winsock2.h> +#endif +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#include <inttypes.h> + +#include "mp_msg.h" +#include "rtsp.h" +#include "rtsp_session.h" +#include "osdep/timer.h" + +/* +#define LOG +*/ + +#define BUF_SIZE 4096 +#define HEADER_SIZE 1024 +#define MAX_FIELDS 256 + +struct rtsp_s { + + int s; + + char *host; + int port; + char *path; + char *param; + char *mrl; + char *user_agent; + + char *server; + unsigned int server_state; + uint32_t server_caps; + + unsigned int cseq; + char *session; + + char *answers[MAX_FIELDS]; /* data of last message */ + char *scheduled[MAX_FIELDS]; /* will be sent with next message */ +}; + +/* + * constants + */ + +#define RTSP_PROTOCOL_VERSION "RTSP/1.0" + +/* server states */ +#define RTSP_CONNECTED 1 +#define RTSP_INIT 2 +#define RTSP_READY 4 +#define RTSP_PLAYING 8 +#define RTSP_RECORDING 16 + +/* server capabilities */ +#define RTSP_OPTIONS 0x001 +#define RTSP_DESCRIBE 0x002 +#define RTSP_ANNOUNCE 0x004 +#define RTSP_SETUP 0x008 +#define RTSP_GET_PARAMETER 0x010 +#define RTSP_SET_PARAMETER 0x020 +#define RTSP_TEARDOWN 0x040 +#define RTSP_PLAY 0x080 +#define RTSP_RECORD 0x100 + +/* + * network utilities + */ + +static int write_stream(int s, const char *buf, int len) { + int total, timeout; + + total = 0; timeout = 30; + while (total < len){ + int n; + + n = send (s, &buf[total], len - total, 0); + + if (n > 0) + total += n; + else if (n < 0) { +#ifndef HAVE_WINSOCK2 + if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { +#else + if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { +#endif + usec_sleep (1000000); timeout--; + } else + return -1; + } + } + + return total; +} + +static ssize_t read_stream(int fd, void *buf, size_t count) { + + ssize_t ret, total; + + total = 0; + + while (total < count) { + + ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); + + if (ret<0) { + if(errno == EAGAIN) { + fd_set rset; + struct timeval timeout; + + FD_ZERO (&rset); + FD_SET (fd, &rset); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { + return -1; + } + continue; + } + + mp_msg(MSGT_OPEN, MSGL_ERR, "rtsp: read error.\n"); + return ret; + } else + total += ret; + + /* end of stream */ + if (!ret) break; + } + + return total; +} + +/* + * rtsp_get gets a line from stream + * and returns a null terminated string. + */ + +static char *rtsp_get(rtsp_t *s) { + + int n=1; + char *buffer = malloc(BUF_SIZE); + char *string = NULL; + + read_stream(s->s, buffer, 1); + while (n<BUF_SIZE) { + read_stream(s->s, &(buffer[n]), 1); + if ((buffer[n-1]==0x0d)&&(buffer[n]==0x0a)) break; + n++; + } + + if (n>=BUF_SIZE) { + mp_msg(MSGT_OPEN, MSGL_FATAL, "librtsp: buffer overflow in rtsp_get\n"); + exit(1); + } + string=malloc(n); + memcpy(string,buffer,n-1); + string[n-1]=0; + +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: << '%s'\n", string); +#endif + + + free(buffer); + return string; +} + +/* + * rtsp_put puts a line on stream + */ + +static void rtsp_put(rtsp_t *s, const char *string) { + + int len=strlen(string); + char *buf=malloc(len+2); + +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: >> '%s'", string); +#endif + + memcpy(buf,string,len); + buf[len]=0x0d; + buf[len+1]=0x0a; + + write_stream(s->s, buf, len+2); + +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, " done.\n"); +#endif + + free(buf); +} + +/* + * extract server status code + */ + +static int rtsp_get_code(const char *string) { + + char buf[4]; + int code=0; + + if (!strncmp(string, RTSP_PROTOCOL_VERSION, strlen(RTSP_PROTOCOL_VERSION))) + { + memcpy(buf, string+strlen(RTSP_PROTOCOL_VERSION)+1, 3); + buf[3]=0; + code=atoi(buf); + } else if (!strncmp(string, RTSP_METHOD_SET_PARAMETER,8)) + { + return RTSP_STATUS_SET_PARAMETER; + } + + if(code != RTSP_STATUS_OK) mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: server responds: '%s'\n",string); + + return code; +} + +/* + * send a request + */ + +static void rtsp_send_request(rtsp_t *s, const char *type, const char *what) { + + char **payload=s->scheduled; + char *buf; + + buf = malloc(strlen(type)+strlen(what)+strlen(RTSP_PROTOCOL_VERSION)+3); + + sprintf(buf,"%s %s %s",type, what, RTSP_PROTOCOL_VERSION); + rtsp_put(s,buf); + free(buf); + if (payload) + while (*payload) { + rtsp_put(s,*payload); + payload++; + } + rtsp_put(s,""); + rtsp_unschedule_all(s); +} + +/* + * schedule standard fields + */ + +static void rtsp_schedule_standard(rtsp_t *s) { + + char tmp[17]; + + snprintf(tmp, 17, "CSeq: %u", s->cseq); + rtsp_schedule_field(s, tmp); + + if (s->session) { + char *buf; + buf = malloc(strlen(s->session)+15); + sprintf(buf, "Session: %s", s->session); + rtsp_schedule_field(s, buf); + free(buf); + } +} +/* + * get the answers, if server responses with something != 200, return NULL + */ + +static int rtsp_get_answers(rtsp_t *s) { + + char *answer=NULL; + unsigned int answer_seq; + char **answer_ptr=s->answers; + int code; + int ans_count = 0; + + answer=rtsp_get(s); + if (!answer) + return 0; + code=rtsp_get_code(answer); + free(answer); + + rtsp_free_answers(s); + + do { /* while we get answer lines */ + + answer=rtsp_get(s); + if (!answer) + return 0; + + if (!strncasecmp(answer,"CSeq:",5)) { + sscanf(answer,"%*s %u",&answer_seq); + if (s->cseq != answer_seq) { +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_WARN, "librtsp: warning: CSeq mismatch. got %u, assumed %u", answer_seq, s->cseq); +#endif + s->cseq=answer_seq; + } + } + if (!strncasecmp(answer,"Server:",7)) { + char *buf = malloc(strlen(answer)); + sscanf(answer,"%*s %s",buf); + if (s->server) free(s->server); + s->server=strdup(buf); + free(buf); + } + if (!strncasecmp(answer,"Session:",8)) { + char *buf = calloc(1, strlen(answer)); + sscanf(answer,"%*s %s",buf); + if (s->session) { + if (strcmp(buf, s->session)) { + mp_msg(MSGT_OPEN, MSGL_WARN, "rtsp: warning: setting NEW session: %s\n", buf); + free(s->session); + s->session=strdup(buf); + } + } else + { +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "rtsp: setting session id to: %s\n", buf); +#endif + s->session=strdup(buf); + } + free(buf); + } + *answer_ptr=answer; + answer_ptr++; + } while ((strlen(answer)!=0) && (++ans_count < MAX_FIELDS)); + + s->cseq++; + + *answer_ptr=NULL; + rtsp_schedule_standard(s); + + return code; +} + +/* + * send an ok message + */ + +int rtsp_send_ok(rtsp_t *s) { + char cseq[16]; + + rtsp_put(s, "RTSP/1.0 200 OK"); + sprintf(cseq,"CSeq: %u", s->cseq); + rtsp_put(s, cseq); + rtsp_put(s, ""); + return 0; +} + +/* + * implementation of must-have rtsp requests; functions return + * server status code. + */ + +int rtsp_request_options(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(strlen(s->host)+16); + sprintf(buf,"rtsp://%s:%i", s->host, s->port); + } + rtsp_send_request(s,RTSP_METHOD_OPTIONS,buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_describe(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(strlen(s->host)+strlen(s->path)+16); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,RTSP_METHOD_DESCRIBE,buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_setup(rtsp_t *s, const char *what, char *control) { + + char *buf = NULL; + + if (what) + buf = strdup (what); + else + { + int len = strlen (s->host) + strlen (s->path) + 16; + if (control) + len += strlen (control) + 1; + + buf = malloc (len); + sprintf (buf, "rtsp://%s:%i/%s%s%s", s->host, s->port, s->path, + control ? "/" : "", control ? control : ""); + } + + rtsp_send_request (s, RTSP_METHOD_SETUP, buf); + free (buf); + return rtsp_get_answers (s); +} + +int rtsp_request_setparameter(rtsp_t *s, const char *what) { + + char *buf; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(strlen(s->host)+strlen(s->path)+16); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,RTSP_METHOD_SET_PARAMETER,buf); + free(buf); + + return rtsp_get_answers(s); +} + +int rtsp_request_play(rtsp_t *s, const char *what) { + + char *buf; + int ret; + + if (what) { + buf=strdup(what); + } else + { + buf=malloc(strlen(s->host)+strlen(s->path)+16); + sprintf(buf,"rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request(s,RTSP_METHOD_PLAY,buf); + free(buf); + + ret = rtsp_get_answers (s); + if (ret == RTSP_STATUS_OK) + s->server_state = RTSP_PLAYING; + + return ret; +} + +int rtsp_request_teardown(rtsp_t *s, const char *what) { + + char *buf; + + if (what) + buf = strdup (what); + else + { + buf = + malloc (strlen (s->host) + strlen (s->path) + 16); + sprintf (buf, "rtsp://%s:%i/%s", s->host, s->port, s->path); + } + rtsp_send_request (s, RTSP_METHOD_TEARDOWN, buf); + free (buf); + + /* after teardown we're done with RTSP streaming, no need to get answer as + reading more will only result to garbage and buffer overflow */ + return RTSP_STATUS_OK; +} + +/* + * read opaque data from stream + */ + +int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size) { + + int i,seq; + + if (size>=4) { + i=read_stream(s->s, buffer, 4); + if (i<4) return i; + if (((buffer[0]=='S')&&(buffer[1]=='E')&&(buffer[2]=='T')&&(buffer[3]=='_')) || + ((buffer[0]=='O')&&(buffer[1]=='P')&&(buffer[2]=='T')&&(buffer[3]=='I'))) // OPTIONS + { + char *rest=rtsp_get(s); + if (!rest) + return -1; + + seq=-1; + do { + free(rest); + rest=rtsp_get(s); + if (!rest) + return -1; + if (!strncasecmp(rest,"CSeq:",5)) + sscanf(rest,"%*s %u",&seq); + } while (strlen(rest)!=0); + free(rest); + if (seq<0) { +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_WARN, "rtsp: warning: CSeq not recognized!\n"); +#endif + seq=1; + } + /* let's make the server happy */ + rtsp_put(s, "RTSP/1.0 451 Parameter Not Understood"); + rest=malloc(17); + sprintf(rest,"CSeq: %u", seq); + rtsp_put(s, rest); + free(rest); + rtsp_put(s, ""); + i=read_stream(s->s, buffer, size); + } else + { + i=read_stream(s->s, buffer+4, size-4); + i+=4; + } + } else + i=read_stream(s->s, buffer, size); +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "librtsp: << %d of %d bytes\n", i, size); +#endif + + return i; +} + +/* + * connect to a rtsp server + */ + +//rtsp_t *rtsp_connect(const char *mrl, const char *user_agent) { +rtsp_t *rtsp_connect(int fd, char* mrl, char *path, char *host, int port, char *user_agent) { + + rtsp_t *s=malloc(sizeof(rtsp_t)); + int i; + + for (i=0; i<MAX_FIELDS; i++) { + s->answers[i]=NULL; + s->scheduled[i]=NULL; + } + + s->server=NULL; + s->server_state=0; + s->server_caps=0; + + s->cseq=0; + s->session=NULL; + + if (user_agent) + s->user_agent=strdup(user_agent); + else + s->user_agent=strdup("User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)"); + + s->mrl = strdup(mrl); + s->host = strdup(host); + s->port = port; + s->path = strdup(path); + while (*path == '/') + path++; + if ((s->param = strchr(s->path, '?')) != NULL) + s->param++; + //mp_msg(MSGT_OPEN, MSGL_INFO, "path=%s\n", s->path); + //mp_msg(MSGT_OPEN, MSGL_INFO, "param=%s\n", s->param ? s->param : "NULL"); + s->s = fd; + + if (s->s < 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, "rtsp: failed to connect to '%s'\n", s->host); + rtsp_close(s); + return NULL; + } + + s->server_state=RTSP_CONNECTED; + + /* now let's send an options request. */ + rtsp_schedule_field(s, "CSeq: 1"); + rtsp_schedule_field(s, s->user_agent); + rtsp_schedule_field(s, "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7"); + rtsp_schedule_field(s, "PlayerStarttime: [28/03/2003:22:50:23 00:00]"); + rtsp_schedule_field(s, "CompanyID: KnKV4M4I/B2FjJ1TToLycw=="); + rtsp_schedule_field(s, "GUID: 00000000-0000-0000-0000-000000000000"); + rtsp_schedule_field(s, "RegionData: 0"); + rtsp_schedule_field(s, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); + /*rtsp_schedule_field(s, "Pragma: initiate-session");*/ + rtsp_request_options(s, NULL); + + return s; +} + + +/* + * closes an rtsp connection + */ + +void rtsp_close(rtsp_t *s) { + + if (s->server_state) + { + if (s->server_state == RTSP_PLAYING) + rtsp_request_teardown (s, NULL); + closesocket (s->s); + } + + if (s->path) free(s->path); + if (s->host) free(s->host); + if (s->mrl) free(s->mrl); + if (s->session) free(s->session); + if (s->user_agent) free(s->user_agent); + rtsp_free_answers(s); + rtsp_unschedule_all(s); + free(s); +} + +/* + * search in answers for tags. returns a pointer to the content + * after the first matched tag. returns NULL if no match found. + */ + +char *rtsp_search_answers(rtsp_t *s, const char *tag) { + + char **answer; + char *ptr; + + if (!s->answers) return NULL; + answer=s->answers; + + while (*answer) { + if (!strncasecmp(*answer,tag,strlen(tag))) { + ptr=strchr(*answer,':'); + if (!ptr) return NULL; + ptr++; + while(*ptr==' ') ptr++; + return ptr; + } + answer++; + } + + return NULL; +} + +/* + * session id management + */ + +void rtsp_set_session(rtsp_t *s, const char *id) { + + if (s->session) free(s->session); + + s->session=strdup(id); + +} + +char *rtsp_get_session(rtsp_t *s) { + + return s->session; + +} + +char *rtsp_get_mrl(rtsp_t *s) { + + return s->mrl; + +} + +char *rtsp_get_param(rtsp_t *s, const char *p) { + int len; + char *param; + if (!s->param) + return NULL; + if (!p) + return strdup(s->param); + len = strlen(p); + param = s->param; + while (param && *param) { + char *nparam = strchr(param, '&'); + if (strncmp(param, p, len) == 0 && param[len] == '=') { + param += len + 1; + len = nparam ? nparam - param : strlen(param); + nparam = malloc(len + 1); + memcpy(nparam, param, len); + nparam[len] = 0; + return nparam; + } + param = nparam ? nparam + 1 : NULL; + } + return NULL; +} + +/* + * schedules a field for transmission + */ + +void rtsp_schedule_field(rtsp_t *s, const char *string) { + + int i=0; + + if (!string) return; + + while(s->scheduled[i]) { + i++; + } + s->scheduled[i]=strdup(string); +} + +/* + * removes the first scheduled field which prefix matches string. + */ + +void rtsp_unschedule_field(rtsp_t *s, const char *string) { + + char **ptr=s->scheduled; + + if (!string) return; + + while(*ptr) { + if (!strncmp(*ptr, string, strlen(string))) + break; + else + ptr++; + } + if (*ptr) free(*ptr); + ptr++; + do { + *(ptr-1)=*ptr; + } while(*ptr); +} + +/* + * unschedule all fields + */ + +void rtsp_unschedule_all(rtsp_t *s) { + + char **ptr; + + if (!s->scheduled) return; + ptr=s->scheduled; + + while (*ptr) { + free(*ptr); + *ptr=NULL; + ptr++; + } +} +/* + * free answers + */ + +void rtsp_free_answers(rtsp_t *s) { + + char **answer; + + if (!s->answers) return; + answer=s->answers; + + while (*answer) { + free(*answer); + *answer=NULL; + answer++; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,84 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp.h,v 1.2 2002/12/16 21:50:55 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * a minimalistic implementation of rtsp protocol, + * *not* RFC 2326 compilant yet. + * + * 2006, Benjamin Zores and Vincent Mussard + * fixed a lot of RFC compliance issues. + */ + +#ifndef HAVE_RTSP_H +#define HAVE_RTSP_H + + +/* some codes returned by rtsp_request_* functions */ + +#define RTSP_STATUS_SET_PARAMETER 10 +#define RTSP_STATUS_OK 200 + +#define RTSP_METHOD_OPTIONS "OPTIONS" +#define RTSP_METHOD_DESCRIBE "DESCRIBE" +#define RTSP_METHOD_SETUP "SETUP" +#define RTSP_METHOD_PLAY "PLAY" +#define RTSP_METHOD_TEARDOWN "TEARDOWN" +#define RTSP_METHOD_SET_PARAMETER "SET_PARAMETER" + +typedef struct rtsp_s rtsp_t; + +rtsp_t* rtsp_connect (int fd, char *mrl, char *path, char *host, int port, char *user_agent); + +int rtsp_request_options(rtsp_t *s, const char *what); +int rtsp_request_describe(rtsp_t *s, const char *what); +int rtsp_request_setup(rtsp_t *s, const char *what, char *control); +int rtsp_request_setparameter(rtsp_t *s, const char *what); +int rtsp_request_play(rtsp_t *s, const char *what); +int rtsp_request_teardown(rtsp_t *s, const char *what); + +int rtsp_send_ok(rtsp_t *s); + +int rtsp_read_data(rtsp_t *s, char *buffer, unsigned int size); + +char* rtsp_search_answers(rtsp_t *s, const char *tag); +void rtsp_add_to_payload(char **payload, const char *string); + +void rtsp_free_answers(rtsp_t *this); + +int rtsp_read (rtsp_t *this, char *data, int len); +void rtsp_close (rtsp_t *this); + +void rtsp_set_session(rtsp_t *s, const char *id); +char *rtsp_get_session(rtsp_t *s); + +char *rtsp_get_mrl(rtsp_t *s); +char *rtsp_get_param(rtsp_t *s, const char *param); + +/*int rtsp_peek_header (rtsp_t *this, char *data); */ + +void rtsp_schedule_field(rtsp_t *s, const char *string); +void rtsp_unschedule_field(rtsp_t *s, const char *string); +void rtsp_unschedule_all(rtsp_t *s); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp_rtp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2006 Benjamin Zores + * based on the Freebox patch for xine by Vincent Mussard + * but with many enhancements for better RTSP RFC compliance. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <inttypes.h> + +#include "config.h" + +#ifndef HAVE_WINSOCK2 +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#endif + +#include "mp_msg.h" +#include "rtsp.h" +#include "rtsp_rtp.h" +#include "rtsp_session.h" +#include "../freesdp/common.h" +#include "../freesdp/parser.h" + +#define RTSP_DEFAULT_PORT 31336 +#define MAX_LENGTH 256 + +#define RTSP_ACCEPT_SDP "Accept: application/sdp" +#define RTSP_CONTENT_LENGTH "Content-length" +#define RTSP_CONTENT_TYPE "Content-Type" +#define RTSP_APPLICATION_SDP "application/sdp" +#define RTSP_RANGE "Range: " +#define RTSP_NPT_NOW "npt=now-" +#define RTSP_MEDIA_CONTAINER_MPEG_TS "33" +#define RTSP_TRANSPORT_REQUEST "Transport: RTP/AVP;%s;%s%i-%i;mode=\"PLAY\"" + +#define RTSP_TRANSPORT_MULTICAST "multicast" +#define RTSP_TRANSPORT_UNICAST "unicast" + +#define RTSP_MULTICAST_PORT "port=" +#define RTSP_UNICAST_CLIENT_PORT "client_port=" +#define RTSP_UNICAST_SERVER_PORT "server_port=" +#define RTSP_SETUP_DESTINATION "destination=" + +#define RTSP_SESSION "Session" +#define RTSP_TRANSPORT "Transport" + +/* hardcoded RTCP RR - this is _NOT_ RFC compliant */ +#define RTCP_RR_SIZE 32 +#define RTCP_RR "\201\311\0\7(.JD\31+\306\343\0\0\0\0\0\0/E\0\0\2&\0\0\0\0\0\0\0\0\201" +#define RTCP_SEND_FREQUENCY 1024 + +int rtsp_port = 0; +char *rtsp_destination = NULL; + +void +rtcp_send_rr (rtsp_t *s, struct rtp_rtsp_session_t *st) +{ + if (st->rtcp_socket == -1) + return; + + /* send RTCP RR every RTCP_SEND_FREQUENCY packets + * FIXME : NOT CORRECT, HARDCODED, BUT MAKES SOME SERVERS HAPPY + * not rfc compliant + * http://www.faqs.org/rfcs/rfc1889.html chapter 6 for RTCP + */ + + if (st->count == RTCP_SEND_FREQUENCY) + { + char rtcp_content[RTCP_RR_SIZE]; + strcpy (rtcp_content, RTCP_RR); + send (st->rtcp_socket, rtcp_content, RTCP_RR_SIZE, 0); + + /* ping RTSP server to keep connection alive. + we use OPTIONS instead of PING as not all servers support it */ + rtsp_request_options (s, "*"); + st->count = 0; + } + else + st->count++; +} + +static struct rtp_rtsp_session_t * +rtp_session_new (void) +{ + struct rtp_rtsp_session_t *st = NULL; + + st = malloc (sizeof (struct rtp_rtsp_session_t)); + + st->rtp_socket = -1; + st->rtcp_socket = -1; + st->control_url = NULL; + st->count = 0; + + return st; +} + +void +rtp_session_free (struct rtp_rtsp_session_t *st) +{ + if (!st) + return; + + if (st->rtp_socket != -1) + close (st->rtp_socket); + if (st->rtcp_socket != -1) + close (st->rtcp_socket); + + if (st->control_url) + free (st->control_url); + free (st); +} + +static void +rtp_session_set_fd (struct rtp_rtsp_session_t *st, + int rtp_sock, int rtcp_sock) +{ + if (!st) + return; + + st->rtp_socket = rtp_sock; + st->rtcp_socket = rtcp_sock; +} + +static int +parse_port (const char *line, const char *param, + int *rtp_port, int *rtcp_port) +{ + char *parse1; + char *parse2; + char *parse3; + + char *line_copy = strdup (line); + + parse1 = strstr (line_copy, param); + + if (parse1) + { + parse2 = strstr (parse1, "-"); + + if (parse2) + { + parse3 = strstr (parse2, ";"); + + if (parse3) + parse3[0] = 0; + + parse2[0] = 0; + } + else + { + free (line_copy); + return 0; + } + } + else + { + free (line_copy); + return 0; + } + + *rtp_port = atoi (parse1 + strlen (param)); + *rtcp_port = atoi (parse2 + 1); + + free (line_copy); + + return 1; +} + +static char * +parse_destination (const char *line) +{ + char *parse1; + char *parse2; + + char *dest = NULL; + char *line_copy = strdup (line); + int len; + + parse1 = strstr (line_copy, RTSP_SETUP_DESTINATION); + if (!parse1) + { + free (line_copy); + return NULL; + } + + parse2 = strstr (parse1, ";"); + if (!parse2) + { + free (line_copy); + return NULL; + } + + len = strlen (parse1) - strlen (parse2) + - strlen (RTSP_SETUP_DESTINATION) + 1; + dest = (char *) malloc (len + 1); + snprintf (dest, len, parse1 + strlen (RTSP_SETUP_DESTINATION)); + free (line_copy); + + return dest; +} + +static int +rtcp_connect (int client_port, int server_port, const char* server_hostname) +{ + struct sockaddr_in sin; + struct hostent *hp; + int s; + + if (client_port <= 1023) + return -1; + + s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) + return -1; + + hp = gethostbyname (server_hostname); + if (!hp) + { + close (s); + return -1; + } + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons (client_port); + + if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) + { +#ifndef HAVE_WINSOCK2 + if (errno != EINPROGRESS) +#else + if (WSAGetLastError() != WSAEINPROGRESS) +#endif + { + close (s); + return -1; + } + } + + sin.sin_family = AF_INET; + memcpy (&(sin.sin_addr.s_addr), hp->h_addr, sizeof (hp->h_addr)); + sin.sin_port = htons (server_port); + + /* datagram socket */ + if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) < 0) + { + close (s); + return -1; + } + + return s; +} + +static int +rtp_connect (char *hostname, int port) +{ + struct sockaddr_in sin; + struct timeval tv; + int err, err_len; + int rxsockbufsz; + int s; + fd_set set; + + if (port <= 1023) + return -1; + + s = socket (PF_INET, SOCK_DGRAM, 0); + if (s == -1) + return -1; + + sin.sin_family = AF_INET; + if (!hostname || !strcmp (hostname, "0.0.0.0")) + sin.sin_addr.s_addr = htonl (INADDR_ANY); + else +#ifndef HAVE_WINSOCK2 +#ifdef USE_ATON + inet_aton (hostname, &sin.sin_addr); +#else + inet_pton (AF_INET, hostname, &sin.sin_addr); +#endif +#else + sin.sin_addr.s_addr = htonl (INADDR_ANY); +#endif + sin.sin_port = htons (port); + + /* Increase the socket rx buffer size to maximum -- this is UDP */ + rxsockbufsz = 240 * 1024; + if (setsockopt (s, SOL_SOCKET, SO_RCVBUF, + &rxsockbufsz, sizeof (rxsockbufsz))) + mp_msg (MSGT_OPEN, MSGL_ERR, "Couldn't set receive socket buffer size\n"); + + /* if multicast address, add membership */ + if ((ntohl (sin.sin_addr.s_addr) >> 28) == 0xe) + { + struct ip_mreq mcast; + mcast.imr_multiaddr.s_addr = sin.sin_addr.s_addr; + mcast.imr_interface.s_addr = 0; + + if (setsockopt (s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof (mcast))) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "IP_ADD_MEMBERSHIP failed\n"); + close (s); + return -1; + } + } + + /* datagram socket */ + if (bind (s, (struct sockaddr *) &sin, sizeof (sin))) + { +#ifndef HAVE_WINSOCK2 + if (errno != EINPROGRESS) +#else + if (WSAGetLastError() != WSAEINPROGRESS) +#endif + { + mp_msg (MSGT_OPEN, MSGL_ERR, "bind: %s\n", strerror (errno)); + close (s); + return -1; + } + } + + tv.tv_sec = 0; + tv.tv_usec = (1 * 1000000); /* 1 second timeout */ + + FD_ZERO (&set); + FD_SET (s, &set); + + err = select (s + 1, &set, NULL, NULL, &tv); + if (err < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "Select failed: %s\n", strerror (errno)); + close (s); + return -1; + } + else if (err == 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "Timeout! No data from host %s\n", hostname); + close (s); + return -1; + } + + err_len = sizeof (err); + getsockopt (s, SOL_SOCKET, SO_ERROR, &err, (socklen_t *) &err_len); + if (err) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "Socket error: %d\n", err); + close (s); + return -1; + } + + return s; +} + +static int +is_multicast_address (char *addr) +{ + struct sockaddr_in sin; + + if (!addr) + return -1; + + sin.sin_family = AF_INET; + +#ifndef HAVE_WINSOCK2 +#ifdef USE_ATON + inet_aton (addr, &sin.sin_addr); +#else + inet_pton (AF_INET, addr, &sin.sin_addr); +#endif +#else + sin.sin_addr.s_addr = htonl (INADDR_ANY); +#endif + + if ((ntohl (sin.sin_addr.s_addr) >> 28) == 0xe) + return 1; + + return 0; +} + +struct rtp_rtsp_session_t * +rtp_setup_and_play (rtsp_t *rtsp_session) +{ + struct rtp_rtsp_session_t* rtp_session = NULL; + const fsdp_media_description_t *med_dsc = NULL; + char temp_buf[MAX_LENGTH + 1]; + char npt[256]; + + char* answer; + char* sdp; + char *server_addr = NULL; + char *destination = NULL; + + int statut; + int content_length = 0; + int is_multicast = 0; + + fsdp_description_t *dsc = NULL; + fsdp_error_t result; + + int client_rtp_port = -1; + int client_rtcp_port = -1; + int server_rtp_port = -1; + int server_rtcp_port = -1; + int rtp_sock = -1; + int rtcp_sock = -1; + + /* 1. send a RTSP DESCRIBE request to server */ + rtsp_schedule_field (rtsp_session, RTSP_ACCEPT_SDP); + statut = rtsp_request_describe (rtsp_session, NULL); + if (statut < 200 || statut > 299) + return NULL; + + answer = rtsp_search_answers (rtsp_session, RTSP_CONTENT_LENGTH); + if (answer) + content_length = atoi (answer); + else + return NULL; + + answer = rtsp_search_answers (rtsp_session, RTSP_CONTENT_TYPE); + if (!answer || !strstr (answer, RTSP_APPLICATION_SDP)) + return NULL; + + /* 2. read SDP message from server */ + sdp = (char *) malloc (content_length + 1); + if (rtsp_read_data (rtsp_session, sdp, content_length) <= 0) + { + free (sdp); + return NULL; + } + sdp[content_length] = 0; + + /* 3. parse SDP message */ + dsc = fsdp_description_new (); + result = fsdp_parse (sdp, dsc); + if (result != FSDPE_OK) + { + free (sdp); + fsdp_description_delete (dsc); + return NULL; + } + mp_msg (MSGT_OPEN, MSGL_V, "SDP:\n%s\n", sdp); + free (sdp); + + /* 4. check for number of media streams: only one is supported */ + if (fsdp_get_media_count (dsc) != 1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "A single media stream only is supported atm.\n"); + fsdp_description_delete (dsc); + return NULL; + } + + /* 5. set the Normal Play Time parameter + * use range provided by server in SDP or start now if empty */ + sprintf (npt, RTSP_RANGE); + if (fsdp_get_range (dsc)) + strcat (npt, fsdp_get_range (dsc)); + else + strcat (npt, RTSP_NPT_NOW); + + /* 5. check for a valid media stream */ + med_dsc = fsdp_get_media (dsc, 0); + if (!med_dsc) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* 6. parse the `m=<media> <port> <transport> <fmt list>' line */ + + /* check for an A/V media */ + if (fsdp_get_media_type (med_dsc) != FSDP_MEDIA_VIDEO && + fsdp_get_media_type (med_dsc) != FSDP_MEDIA_AUDIO) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* only RTP/AVP transport method is supported right now */ + if (fsdp_get_media_transport_protocol (med_dsc) != FSDP_TP_RTP_AVP) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* only MPEG-TS is supported at the moment */ + if (!strstr (fsdp_get_media_format (med_dsc, 0), + RTSP_MEDIA_CONTAINER_MPEG_TS)) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* get client port (if any) advised by server */ + client_rtp_port = fsdp_get_media_port (med_dsc); + if (client_rtp_port == -1) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* if client_rtp_port = 0 => let client randomly pick one */ + if (client_rtp_port == 0) + { + /* TODO: we should check if the port is in use first */ + if (rtsp_port) + client_rtp_port = rtsp_port; + else + client_rtp_port = RTSP_DEFAULT_PORT; + } + + /* RTCP port generally is RTP port + 1 */ + client_rtcp_port = client_rtp_port + 1; + + mp_msg (MSGT_OPEN, MSGL_V, + "RTP Port from SDP appears to be: %d\n", client_rtp_port); + mp_msg (MSGT_OPEN, MSGL_V, + "RTCP Port from SDP appears to be: %d\n", client_rtcp_port); + + /* 7. parse the `c=<network type> <addr type> <connection address>' line */ + + /* check for a valid media network type (inet) */ + if (fsdp_get_media_network_type (med_dsc) != FSDP_NETWORK_TYPE_INET) + { + /* no control for media: try global one instead */ + if (fsdp_get_global_conn_network_type (dsc) != FSDP_NETWORK_TYPE_INET) + { + fsdp_description_delete (dsc); + return NULL; + } + } + + /* only IPv4 is supported atm. */ + if (fsdp_get_media_address_type (med_dsc) != FSDP_ADDRESS_TYPE_IPV4) + { + /* no control for media: try global one instead */ + if (fsdp_get_global_conn_address_type (dsc) != FSDP_ADDRESS_TYPE_IPV4) + { + fsdp_description_delete (dsc); + return NULL; + } + } + + /* get the media server address to connect to */ + if (fsdp_get_media_address (med_dsc)) + server_addr = strdup (fsdp_get_media_address (med_dsc)); + else if (fsdp_get_global_conn_address (dsc)) + { + /* no control for media: try global one instead */ + server_addr = strdup (fsdp_get_global_conn_address (dsc)); + } + + if (!server_addr) + { + fsdp_description_delete (dsc); + return NULL; + } + + /* check for a UNICAST or MULTICAST address to connect to */ + is_multicast = is_multicast_address (server_addr); + + /* 8. initiate an RTP session */ + rtp_session = rtp_session_new (); + if (!rtp_session) + { + free (server_addr); + fsdp_description_delete (dsc); + return NULL; + } + + /* get the media control URL */ + if (fsdp_get_media_control (med_dsc, 0)) + rtp_session->control_url = strdup (fsdp_get_media_control (med_dsc, 0)); + fsdp_description_delete (dsc); + if (!rtp_session->control_url) + { + free (server_addr); + rtp_session_free (rtp_session); + return NULL; + } + + /* 9. create the payload for RTSP SETUP request */ + memset (temp_buf, '\0', MAX_LENGTH); + snprintf (temp_buf, MAX_LENGTH, + RTSP_TRANSPORT_REQUEST, + is_multicast ? RTSP_TRANSPORT_MULTICAST : RTSP_TRANSPORT_UNICAST, + is_multicast ? RTSP_MULTICAST_PORT : RTSP_UNICAST_CLIENT_PORT, + client_rtp_port, client_rtcp_port); + mp_msg (MSGT_OPEN, MSGL_V, "RTSP Transport: %s\n", temp_buf); + + rtsp_unschedule_field (rtsp_session, RTSP_SESSION); + rtsp_schedule_field (rtsp_session, temp_buf); + + /* 10. check for the media control URL type and initiate RTSP SETUP */ + if (!strncmp (rtp_session->control_url, "rtsp://", 7)) /* absolute URL */ + statut = rtsp_request_setup (rtsp_session, + rtp_session->control_url, NULL); + else /* relative URL */ + statut = rtsp_request_setup (rtsp_session, + NULL, rtp_session->control_url); + + if (statut < 200 || statut > 299) + { + free (server_addr); + rtp_session_free (rtp_session); + return NULL; + } + + /* 11. parse RTSP SETUP response: we need it to actually determine + * the real address and port to connect to */ + answer = rtsp_search_answers (rtsp_session, RTSP_TRANSPORT); + if (!answer) + { + free (server_addr); + rtp_session_free (rtp_session); + return NULL; + } + + /* check for RTP and RTCP ports to bind according to how request was done */ + is_multicast = 0; + if (strstr (answer, RTSP_TRANSPORT_MULTICAST)) + is_multicast = 1; + + if (is_multicast) + parse_port (answer, RTSP_MULTICAST_PORT, + &client_rtp_port, &client_rtcp_port); + else + { + parse_port (answer, RTSP_UNICAST_CLIENT_PORT, + &client_rtp_port, &client_rtcp_port); + parse_port (answer, RTSP_UNICAST_SERVER_PORT, + &server_rtp_port, &server_rtcp_port); + } + + /* now check network settings as determined by server */ + if (rtsp_destination) + destination = strdup (rtsp_destination); + else + destination = parse_destination (answer); + if (!destination) + destination = strdup (server_addr); + free (server_addr); + + mp_msg (MSGT_OPEN, MSGL_V, "RTSP Destination: %s\n", destination); + mp_msg (MSGT_OPEN, MSGL_V, "Client RTP port : %d\n", client_rtp_port); + mp_msg (MSGT_OPEN, MSGL_V, "Client RTCP port : %d\n", client_rtcp_port); + mp_msg (MSGT_OPEN, MSGL_V, "Server RTP port : %d\n", server_rtp_port); + mp_msg (MSGT_OPEN, MSGL_V, "Server RTCP port : %d\n", server_rtcp_port); + + /* 12. performs RTSP PLAY request */ + rtsp_schedule_field (rtsp_session, npt); + statut = rtsp_request_play (rtsp_session, NULL); + if (statut < 200 || statut > 299) + { + free (destination); + rtp_session_free (rtp_session); + return NULL; + } + + /* 13. create RTP and RTCP connections */ + rtp_sock = rtp_connect (destination, client_rtp_port); + rtcp_sock = rtcp_connect (client_rtcp_port, server_rtcp_port, destination); + rtp_session_set_fd (rtp_session, rtp_sock, rtcp_sock); + free (destination); + + mp_msg (MSGT_OPEN, MSGL_V, "RTP Sock : %d\nRTCP Sock : %d\n", + rtp_session->rtp_socket, rtp_session->rtcp_socket); + + if (rtp_session->rtp_socket == -1) + { + rtp_session_free (rtp_session); + return NULL; + } + + return rtp_session; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp_rtp.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006 Benjamin Zores + * heavily base on the Freebox patch for xine by Vincent Mussard + * but with many enhancements for better RTSP RFC compliance. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAVE_RTSP_RTP_H_ +#define _HAVE_RTSP_RTP_H_ + +#include "rtsp.h" + +#define MAX_PREVIEW_SIZE 4096 + +struct rtp_rtsp_session_t { + int rtp_socket; + int rtcp_socket; + char *control_url; + int count; +}; + +struct rtp_rtsp_session_t *rtp_setup_and_play (rtsp_t* rtsp_session); +off_t rtp_read (struct rtp_rtsp_session_t* st, char *buf, off_t length); +void rtp_session_free (struct rtp_rtsp_session_t *st); +void rtcp_send_rr (rtsp_t *s, struct rtp_rtsp_session_t *st); + +#endif /* _HAVE_RTSP_RTP_H_ */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp_session.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,269 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp_session.c,v 1.9 2003/02/11 16:20:40 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * high level interface to rtsp servers. + * + * 2006, Benjamin Zores and Vincent Mussard + * Support for MPEG-TS streaming through RFC compliant RTSP servers + */ + +#include <sys/types.h> +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#else +#include <winsock2.h> +#endif +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "mp_msg.h" +#include "../rtp.h" +#include "rtsp.h" +#include "rtsp_rtp.h" +#include "rtsp_session.h" +#include "../realrtsp/real.h" +#include "../realrtsp/rmff.h" +#include "../realrtsp/asmrp.h" +#include "../realrtsp/xbuffer.h" + +/* +#define LOG +*/ + +#define RTSP_OPTIONS_PUBLIC "Public" +#define RTSP_OPTIONS_SERVER "Server" +#define RTSP_OPTIONS_LOCATION "Location" +#define RTSP_OPTIONS_REAL "RealChallenge1" +#define RTSP_SERVER_TYPE_REAL "Real" +#define RTSP_SERVER_TYPE_HELIX "Helix" +#define RTSP_SERVER_TYPE_UNKNOWN "unknown" + +struct rtsp_session_s { + rtsp_t *s; + struct real_rtsp_session_t* real_session; + struct rtp_rtsp_session_t* rtp_session; +}; + +//rtsp_session_t *rtsp_session_start(char *mrl) { +rtsp_session_t *rtsp_session_start(int fd, char **mrl, char *path, char *host, int port, int *redir, uint32_t bandwidth) { + + rtsp_session_t *rtsp_session = NULL; + char *server; + char *mrl_line = NULL; + rmff_header_t *h; + + rtsp_session = malloc (sizeof (rtsp_session_t)); + rtsp_session->s = NULL; + rtsp_session->real_session = NULL; + rtsp_session->rtp_session = NULL; + +//connect: + *redir = 0; + + /* connect to server */ + rtsp_session->s=rtsp_connect(fd,*mrl,path,host,port,NULL); + if (!rtsp_session->s) + { + mp_msg (MSGT_OPEN, MSGL_ERR,"rtsp_session: failed to connect to server %s\n", path); + free(rtsp_session); + return NULL; + } + + /* looking for server type */ + if (rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_SERVER)) + server=strdup(rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_SERVER)); + else { + if (rtsp_search_answers(rtsp_session->s,RTSP_OPTIONS_REAL)) + server=strdup(RTSP_SERVER_TYPE_REAL); + else + server=strdup(RTSP_SERVER_TYPE_UNKNOWN); + } + if (strstr(server,RTSP_SERVER_TYPE_REAL) || strstr(server,RTSP_SERVER_TYPE_HELIX)) + { + /* we are talking to a real server ... */ + + h=real_setup_and_get_header(rtsp_session->s, bandwidth); + if (!h) { + /* got an redirect? */ + if (rtsp_search_answers(rtsp_session->s, RTSP_OPTIONS_LOCATION)) + { + free(mrl_line); + mrl_line=strdup(rtsp_search_answers(rtsp_session->s, RTSP_OPTIONS_LOCATION)); + mp_msg (MSGT_OPEN, MSGL_INFO,"rtsp_session: redirected to %s\n", mrl_line); + rtsp_close(rtsp_session->s); + free(server); + free(*mrl); + free(rtsp_session); + /* tell the caller to redirect, return url to redirect to in mrl */ + *mrl = mrl_line; + *redir = 1; + return NULL; +// goto connect; /* *shudder* i made a design mistake somewhere */ + } else + { + mp_msg (MSGT_OPEN, MSGL_ERR,"rtsp_session: session can not be established.\n"); + rtsp_close(rtsp_session->s); + free (server); + free(rtsp_session); + return NULL; + } + } + + rtsp_session->real_session = init_real_rtsp_session (); + rtsp_session->real_session->header_len = + rmff_dump_header (h, (char *) rtsp_session->real_session->header, 1024); + + rtsp_session->real_session->recv = + xbuffer_copyin (rtsp_session->real_session->recv, 0, + rtsp_session->real_session->header, + rtsp_session->real_session->header_len); + + rtsp_session->real_session->recv_size = + rtsp_session->real_session->header_len; + rtsp_session->real_session->recv_read = 0; + } else /* not a Real server : try RTP instead */ + { + char *public = NULL; + + /* look for the Public: field in response to RTSP OPTIONS */ + public = strdup (rtsp_search_answers (rtsp_session->s, + RTSP_OPTIONS_PUBLIC)); + if (!public) + { + rtsp_close (rtsp_session->s); + free (server); + free (mrl_line); + free (rtsp_session); + return NULL; + } + + /* check for minimalistic RTSP RFC compliance */ + if (!strstr (public, RTSP_METHOD_DESCRIBE) + || !strstr (public, RTSP_METHOD_SETUP) + || !strstr (public, RTSP_METHOD_PLAY) + || !strstr (public, RTSP_METHOD_TEARDOWN)) + { + free (public); + mp_msg (MSGT_OPEN, MSGL_ERR, + "Remote server does not meet minimal RTSP 1.0 compliance.\n"); + rtsp_close (rtsp_session->s); + free (server); + free (mrl_line); + free (rtsp_session); + return NULL; + } + + free (public); + rtsp_session->rtp_session = rtp_setup_and_play (rtsp_session->s); + + /* neither a Real or an RTP server */ + if (!rtsp_session->rtp_session) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "rtsp_session: unsupported RTSP server. "); + mp_msg (MSGT_OPEN, MSGL_ERR, "Server type is '%s'.\n", server); + rtsp_close (rtsp_session->s); + free (server); + free (mrl_line); + free (rtsp_session); + return NULL; + } + } + free(server); + + return rtsp_session; +} + +int rtsp_session_read (rtsp_session_t *this, char *data, int len) { + + if (this->real_session) { + int to_copy=len; + char *dest=data; + char *source = + (char *) (this->real_session->recv + this->real_session->recv_read); + int fill = this->real_session->recv_size - this->real_session->recv_read; + + if (len < 0) return 0; + while (to_copy > fill) { + + memcpy(dest, source, fill); + to_copy -= fill; + dest += fill; + this->real_session->recv_read = 0; + this->real_session->recv_size = + real_get_rdt_chunk (this->s, (char **)&(this->real_session->recv)); + if (this->real_session->recv_size < 0) + return -1; + source = (char *) this->real_session->recv; + fill = this->real_session->recv_size; + + if (this->real_session->recv_size == 0) { +#ifdef LOG + mp_msg (MSGT_OPEN, MSGL_INFO, "librtsp: %d of %d bytes provided\n", len-to_copy, len); +#endif + return len-to_copy; + } + } + + memcpy(dest, source, to_copy); + this->real_session->recv_read += to_copy; + +#ifdef LOG + mp_msg (MSGT_OPEN, MSGL_INFO, "librtsp: %d bytes provided\n", len); +#endif + + return len; + } + else if (this->rtp_session) + { + int l = 0; + + l = read_rtp_from_server (this->rtp_session->rtp_socket, data, len); + /* send RTSP and RTCP keepalive */ + rtcp_send_rr (this->s, this->rtp_session); + + if (l == 0) + rtsp_session_end (this); + + return l; + } + + return 0; +} + +void rtsp_session_end(rtsp_session_t *session) { + + rtsp_close(session->s); + if (session->real_session) + free_real_rtsp_session (session->real_session); + if (session->rtp_session) + rtp_session_free (session->rtp_session); + free(session); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/librtsp/rtsp_session.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,42 @@ +/* + * This file was ported to MPlayer from xine CVS rtsp_session.h,v 1.4 2003/01/31 14:06:18 + */ + +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * high level interface to rtsp servers. + * + * 2006, Benjamin Zores and Vincent Mussard + * Support for MPEG-TS streaming through RFC compliant RTSP servers + */ + +#ifndef HAVE_RTSP_SESSION_H +#define HAVE_RTSP_SESSION_H + +typedef struct rtsp_session_s rtsp_session_t; + +rtsp_session_t *rtsp_session_start(int fd, char **mrl, char *path, char *host, int port, int *redir, uint32_t bandwidth); + +int rtsp_session_read(rtsp_session_t *session, char *data, int len); + +void rtsp_session_end(rtsp_session_t *session); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/mf.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,153 @@ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "config.h" + +#ifdef HAVE_GLOB +#include <glob.h> +#else +#include "osdep/glob.h" +#endif + +#include "mp_msg.h" +#include "help_mp.h" +#include "stream.h" + +#include "mf.h" + +int mf_w = 0; //352; // let codecs to detect it +int mf_h = 0; //288; +float mf_fps = 25.0; +char * mf_type = NULL; //"jpg"; + +mf_t* open_mf(char * filename){ +#if defined(HAVE_GLOB) || defined(__MINGW32__) + glob_t gg; + struct stat fs; + int i; + char * fname; + mf_t * mf; + int error_count = 0; + int count = 0; + + mf=calloc( 1,sizeof( mf_t ) ); + + if( filename[0] == '@' ) + { + FILE *lst_f=fopen(filename + 1,"r"); + if ( lst_f ) + { + fname=malloc( 255 ); + while ( fgets( fname,255,lst_f ) ) + { + /* remove spaces from end of fname */ + char *t=fname + strlen( fname ) - 1; + while ( t > fname && isspace( *t ) ) *(t--)=0; + if ( stat( fname,&fs ) ) + { + mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); + } + else + { + mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); + mf->names[mf->nr_of_files]=strdup( fname ); + mf->nr_of_files++; + } + } + fclose( lst_f ); + + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); + goto exit_mf; + } + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] %s is not indirect filelist\n",filename+1 ); + } + + if( strchr( filename,',') ) + { + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] filelist: %s\n",filename ); + + while ( ( fname=strsep( &filename,"," ) ) ) + { + if ( stat( fname,&fs ) ) + { + mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); + } + else + { + mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); + mf->names[mf->nr_of_files]=strdup( fname ); +// mp_msg( MSGT_STREAM,MSGL_V,"[mf] added file %d.: %s\n",mf->nr_of_files,mf->names[mf->nr_of_files] ); + mf->nr_of_files++; + } + } + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); + + goto exit_mf; + } + + fname=malloc( strlen( filename ) + 32 ); + + if ( !strchr( filename,'%' ) ) + { + strcpy( fname,filename ); + if ( !strchr( filename,'*' ) ) strcat( fname,"*" ); + + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] search expr: %s\n",fname ); + + if ( glob( fname,0,NULL,&gg ) ) + { free( mf ); free( fname ); return NULL; } + + mf->nr_of_files=gg.gl_pathc; + mf->names=calloc( gg.gl_pathc, sizeof( char* ) ); + + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d (%d)\n",mf->nr_of_files, gg.gl_pathc * sizeof( char* ) ); + + for( i=0;i < gg.gl_pathc;i++ ) + { + stat( gg.gl_pathv[i],&fs ); + if( S_ISDIR( fs.st_mode ) ) continue; + mf->names[i]=strdup( gg.gl_pathv[i] ); +// mp_msg( MSGT_STREAM,MSGL_DBG2,"[mf] added file %d.: %s\n",i,mf->names[i] ); + } + globfree( &gg ); + goto exit_mf; + } + + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] search expr: %s\n",filename ); + + while ( error_count < 5 ) + { + sprintf( fname,filename,count++ ); + if ( stat( fname,&fs ) ) + { + error_count++; + mp_msg( MSGT_STREAM,MSGL_V,"[mf] file not found: '%s'\n",fname ); + } + else + { + mf->names=realloc( mf->names,( mf->nr_of_files + 1 ) * sizeof( char* ) ); + mf->names[mf->nr_of_files]=strdup( fname ); +// mp_msg( MSGT_STREAM,MSGL_V,"[mf] added file %d.: %s\n",mf->nr_of_files,mf->names[mf->nr_of_files] ); + mf->nr_of_files++; + } + } + + mp_msg( MSGT_STREAM,MSGL_INFO,"[mf] number of files: %d\n",mf->nr_of_files ); + +exit_mf: + free( fname ); + return mf; +#else + mp_msg(MSGT_STREAM,MSGL_FATAL,"[mf] mf support is disabled on your os\n"); + return 0; +#endif +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/mf.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,19 @@ + +#ifndef _MF_H +#define _MF_H + +extern int mf_w; +extern int mf_h; +extern float mf_fps; +extern char * mf_type; + +typedef struct +{ + int curr_frame; + int nr_of_files; + char ** names; +} mf_t; + +mf_t* open_mf(char * filename); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/netstream.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,136 @@ + +/* + * Common stuff for netstream + * Packets and so on are defined here along with a few helpers + * wich are used by both the client and the server + * + * Data is always low endian + */ + +typedef struct mp_net_stream_packet_st { + uint16_t len; + uint8_t cmd; + char data[0]; +} __attribute__ ((packed)) mp_net_stream_packet_t; + +#define PACKET_MAX_SIZE 4096 + +// Commands sent by the client +#define NET_STREAM_OPEN 0 +// data is the url +#define NET_STREAM_FILL_BUFFER 1 +// data is an uint16 wich is the max len of the data to return +#define NET_STREAM_SEEK 3 +// data is an uint64 wich the pos where to seek +#define NET_STREAM_CLOSE 4 +// no data +#define NET_STREAM_RESET 5 +// no data + +// Server response +#define NET_STREAM_OK 128 +// Data returned if open is successful +typedef struct mp_net_stream_opened_st { + uint32_t file_format; + uint32_t flags; + uint32_t sector_size; + uint64_t start_pos; + uint64_t end_pos; +} __attribute__ ((packed)) mp_net_stream_opened_t; +// FILL_BUFFER return the data +// CLOSE return nothing +#define NET_STREAM_ERROR 129 +// Data is the error message (if any ;) + +static int net_read(int fd, char* buf, int len) { + int r = 0; + while(len) { + r = recv(fd,buf,len,0); + if(r <= 0) { + if(errno == EINTR) continue; + if(r < 0) + mp_msg(MSGT_NETST,MSGL_ERR,"Read failed: %s\n",strerror(errno)); + return 0; + } + len -= r; + buf += r; + } + return 1; +} + +static mp_net_stream_packet_t* read_packet(int fd) { + uint16_t len; + mp_net_stream_packet_t* pack = + (mp_net_stream_packet_t*)malloc(sizeof(mp_net_stream_packet_t)); + + if(!net_read(fd,(char*)pack,sizeof(mp_net_stream_packet_t))) { + free(pack); + return NULL; + } + pack->len = le2me_16(pack->len); + + if(pack->len < sizeof(mp_net_stream_packet_t)) { + mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid packet (too small: %d)\n",pack->len); + free(pack); + return NULL; + } + if(pack->len > PACKET_MAX_SIZE) { + mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid packet (too big: %d)\n",pack->len); + free(pack); + return NULL; + } + len = pack->len; + if(len > sizeof(mp_net_stream_packet_t)) { + pack = realloc(pack,len); + if(!pack) { + mp_msg(MSGT_NETST,MSGL_ERR,"Failed to get memory for the packet (%d bytes)\n",len); + return NULL; + } + if(!net_read(fd,pack->data,len - sizeof(mp_net_stream_packet_t))) + return NULL; + } + // printf ("Read packet %d %d %d\n",fd,pack->cmd,pack->len); + return pack; +} + +static int net_write(int fd, char* buf, int len) { + int w; + while(len) { + w = send(fd,buf,len,0); + if(w <= 0) { + if(errno == EINTR) continue; + if(w < 0) + mp_msg(MSGT_NETST,MSGL_ERR,"Write failed: %s\n",strerror(errno)); + return 0; + } + len -= w; + buf += w; + } + return 1; +} + +static int write_packet(int fd, uint8_t cmd,char* data,int len) { + mp_net_stream_packet_t* pack = malloc(len + sizeof(mp_net_stream_packet_t)); + + if(len > 0 && data) + memcpy(pack->data,data,len); + pack->len = len + sizeof(mp_net_stream_packet_t); + pack->cmd = cmd; + + // printf("Write packet %d %d (%p) %d\n",fd,cmd,data,len); + pack->len = le2me_16(pack->len); + if(net_write(fd,(char*)pack,pack->len)) { + free(pack); + return 1; + } + free(pack); + return 0; +} + +static void net_stream_opened_2_me(mp_net_stream_opened_t* o) { + o->file_format = le2me_32(o->file_format); + o->flags = le2me_32(o->flags); + o->sector_size = le2me_32(o->sector_size); + o->start_pos = le2me_64(o->start_pos); + o->end_pos = le2me_64(o->end_pos); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/network.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,657 @@ +/* + * Network layer for MPlayer + * by Bertrand BAUDET <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + */ + +//#define DUMP2FILE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <errno.h> +#include <ctype.h> + +#include "config.h" + +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#endif + +#include "stream.h" +#include "demuxer.h" +#include "m_config.h" + +#include "network.h" +#include "http.h" +#include "cookies.h" +#include "url.h" + +#include "version.h" + +extern int stream_cache_size; + +extern int mp_input_check_interrupt(int time); + +/* Variables for the command line option -user, -passwd, -bandwidth, + -user-agent and -nocookies */ + +char *network_username=NULL; +char *network_password=NULL; +int network_bandwidth=0; +int network_cookies_enabled = 0; +char *network_useragent=NULL; + +/* IPv6 options */ +int network_prefer_ipv4 = 0; +int network_ipv4_only_proxy = 0; + + +mime_struct_t mime_type_table[] = { + // MP3 streaming, some MP3 streaming server answer with audio/mpeg + { "audio/mpeg", DEMUXER_TYPE_AUDIO }, + // MPEG streaming + { "video/mpeg", DEMUXER_TYPE_UNKNOWN }, + { "video/x-mpeg", DEMUXER_TYPE_UNKNOWN }, + { "video/x-mpeg2", DEMUXER_TYPE_UNKNOWN }, + // AVI ??? => video/x-msvideo + { "video/x-msvideo", DEMUXER_TYPE_AVI }, + // MOV => video/quicktime + { "video/quicktime", DEMUXER_TYPE_MOV }, + // ASF + { "audio/x-ms-wax", DEMUXER_TYPE_ASF }, + { "audio/x-ms-wma", DEMUXER_TYPE_ASF }, + { "video/x-ms-asf", DEMUXER_TYPE_ASF }, + { "video/x-ms-afs", DEMUXER_TYPE_ASF }, + { "video/x-ms-wvx", DEMUXER_TYPE_ASF }, + { "video/x-ms-wmv", DEMUXER_TYPE_ASF }, + { "video/x-ms-wma", DEMUXER_TYPE_ASF }, + { "application/x-mms-framed", DEMUXER_TYPE_ASF }, + { "application/vnd.ms.wms-hdr.asfv1", DEMUXER_TYPE_ASF }, + { "application/octet-stream", DEMUXER_TYPE_ASF }, + // Playlists + { "video/x-ms-wmx", DEMUXER_TYPE_PLAYLIST }, + { "audio/x-scpls", DEMUXER_TYPE_PLAYLIST }, + { "audio/x-mpegurl", DEMUXER_TYPE_PLAYLIST }, + { "audio/x-pls", DEMUXER_TYPE_PLAYLIST }, + // Real Media +// { "audio/x-pn-realaudio", DEMUXER_TYPE_REAL }, + // OGG Streaming + { "application/x-ogg", DEMUXER_TYPE_OGG }, + // NullSoft Streaming Video + { "video/nsv", DEMUXER_TYPE_NSV}, + { "misc/ultravox", DEMUXER_TYPE_NSV}, + { NULL, DEMUXER_TYPE_UNKNOWN}, +}; + + +streaming_ctrl_t * +streaming_ctrl_new(void) { + streaming_ctrl_t *streaming_ctrl; + streaming_ctrl = malloc(sizeof(streaming_ctrl_t)); + if( streaming_ctrl==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return NULL; + } + memset( streaming_ctrl, 0, sizeof(streaming_ctrl_t) ); + return streaming_ctrl; +} + +void +streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) { + if( streaming_ctrl==NULL ) return; + if( streaming_ctrl->url ) url_free( streaming_ctrl->url ); + if( streaming_ctrl->buffer ) free( streaming_ctrl->buffer ); + if( streaming_ctrl->data ) free( streaming_ctrl->data ); + free( streaming_ctrl ); +} + + +// Converts an address family constant to a string + +const char *af2String(int af) { + switch (af) { + case AF_INET: return "AF_INET"; + +#ifdef HAVE_AF_INET6 + case AF_INET6: return "AF_INET6"; +#endif + default: return "Unknown address family!"; + } +} + + + +// Connect to a server using a TCP connection, with specified address family +// return -2 for fatal error, like unable to resolve name, connection timeout... +// return -1 is unable to connect to a particular port + +int +connect2Server_with_af(char *host, int port, int af,int verb) { + int socket_server_fd; + int err, err_len; + int ret,count = 0; + fd_set set; + struct timeval tv; + union { + struct sockaddr_in four; +#ifdef HAVE_AF_INET6 + struct sockaddr_in6 six; +#endif + } server_address; + size_t server_address_size; + void *our_s_addr; // Pointer to sin_addr or sin6_addr + struct hostent *hp=NULL; + char buf[255]; + +#ifdef HAVE_WINSOCK2 + u_long val; +#endif + + socket_server_fd = socket(af, SOCK_STREAM, 0); + + + if( socket_server_fd==-1 ) { +// mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af)); + return -2; + } + + switch (af) { + case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break; +#ifdef HAVE_AF_INET6 + case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break; +#endif + default: + mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); + return -2; + } + + + memset(&server_address, 0, sizeof(server_address)); + +#ifndef HAVE_WINSOCK2 +#ifdef USE_ATON + if (inet_aton(host, our_s_addr)!=1) +#else + if (inet_pton(af, host, our_s_addr)!=1) +#endif +#else + if ( inet_addr(host)==INADDR_NONE ) +#endif + { + if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af)); + +#ifdef HAVE_GETHOSTBYNAME2 + hp=(struct hostent*)gethostbyname2( host, af ); +#else + hp=(struct hostent*)gethostbyname( host ); +#endif + if( hp==NULL ) { + if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host); + return -2; + } + + memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length ); + } +#ifdef HAVE_WINSOCK2 + else { + unsigned long addr = inet_addr(host); + memcpy( our_s_addr, (void*)&addr, sizeof(addr) ); + } +#endif + + switch (af) { + case AF_INET: + server_address.four.sin_family=af; + server_address.four.sin_port=htons(port); + server_address_size = sizeof(server_address.four); + break; +#ifdef HAVE_AF_INET6 + case AF_INET6: + server_address.six.sin6_family=af; + server_address.six.sin6_port=htons(port); + server_address_size = sizeof(server_address.six); + break; +#endif + default: + mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); + return -2; + } + +#if defined(USE_ATON) || defined(HAVE_WINSOCK2) + strncpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255); +#else + inet_ntop(af, our_s_addr, buf, 255); +#endif + if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port ); + + // Turn the socket as non blocking so we can timeout on the connection +#ifndef HAVE_WINSOCK2 + fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); +#else + val = 1; + ioctlsocket( socket_server_fd, FIONBIO, &val ); +#endif + if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) { +#ifndef HAVE_WINSOCK2 + if( errno!=EINPROGRESS ) { +#else + if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) { +#endif + if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af)); + closesocket(socket_server_fd); + return -1; + } + } + tv.tv_sec = 0; + tv.tv_usec = 500000; + FD_ZERO( &set ); + FD_SET( socket_server_fd, &set ); + // When the connection will be made, we will have a writable fd + while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) { + if( ret<0 ) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed); + else if(ret > 0) break; + else if(count > 30 || mp_input_check_interrupt(500)) { + if(count > 30) + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout); + else + mp_msg(MSGT_NETWORK,MSGL_V,"Connection interuppted by user\n"); + return -3; + } + count++; + FD_ZERO( &set ); + FD_SET( socket_server_fd, &set ); + tv.tv_sec = 0; + tv.tv_usec = 500000; + } + + // Turn back the socket as blocking +#ifndef HAVE_WINSOCK2 + fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK ); +#else + val = 0; + ioctlsocket( socket_server_fd, FIONBIO, &val ); +#endif + // Check if there were any error + err_len = sizeof(int); + ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len); + if(ret < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno)); + return -2; + } + if(err > 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err)); + return -1; + } + + return socket_server_fd; +} + +// Connect to a server using a TCP connection +// return -2 for fatal error, like unable to resolve name, connection timeout... +// return -1 is unable to connect to a particular port + + +int +connect2Server(char *host, int port, int verb) { +#ifdef HAVE_AF_INET6 + int r; + int s = -2; + + r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb); + if (r > -1) return r; + + s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb); + if (s == -2) return r; + return s; +#else + return connect2Server_with_af(host, port, AF_INET,verb); +#endif + + +} + +URL_t* +check4proxies( URL_t *url ) { + URL_t *url_out = NULL; + if( url==NULL ) return NULL; + url_out = url_new( url->url ); + if( !strcasecmp(url->protocol, "http_proxy") ) { + mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: http://%s:%d\n", url->hostname, url->port ); + return url_out; + } + // Check if the http_proxy environment variable is set. + if( !strcasecmp(url->protocol, "http") ) { + char *proxy; + proxy = getenv("http_proxy"); + if( proxy!=NULL ) { + // We got a proxy, build the URL to use it + int len; + char *new_url; + URL_t *tmp_url; + URL_t *proxy_url = url_new( proxy ); + + if( proxy_url==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_WARN, + MSGTR_MPDEMUX_NW_InvalidProxySettingTryingWithout); + return url_out; + } + +#ifdef HAVE_AF_INET6 + if (network_ipv4_only_proxy && (gethostbyname(url->hostname)==NULL)) { + mp_msg(MSGT_NETWORK,MSGL_WARN, + MSGTR_MPDEMUX_NW_CantResolvTryingWithoutProxy); + url_free(proxy_url); + return url_out; + } +#endif + + mp_msg(MSGT_NETWORK,MSGL_V,"Using HTTP proxy: %s\n", proxy_url->url ); + len = strlen( proxy_url->hostname ) + strlen( url->url ) + 20; // 20 = http_proxy:// + port + new_url = malloc( len+1 ); + if( new_url==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + url_free(proxy_url); + return url_out; + } + sprintf(new_url, "http_proxy://%s:%d/%s", proxy_url->hostname, proxy_url->port, url->url ); + tmp_url = url_new( new_url ); + if( tmp_url==NULL ) { + free( new_url ); + url_free( proxy_url ); + return url_out; + } + url_free( url_out ); + url_out = tmp_url; + free( new_url ); + url_free( proxy_url ); + } + } + return url_out; +} + +int +http_send_request( URL_t *url, off_t pos ) { + HTTP_header_t *http_hdr; + URL_t *server_url; + char str[256]; + int fd; + int ret; + int proxy = 0; // Boolean + + http_hdr = http_new_header(); + + if( !strcasecmp(url->protocol, "http_proxy") ) { + proxy = 1; + server_url = url_new( (url->file)+1 ); + http_set_uri( http_hdr, server_url->url ); + } else { + server_url = url; + http_set_uri( http_hdr, server_url->file ); + } + if (server_url->port && server_url->port != 80) + snprintf(str, 256, "Host: %s:%d", server_url->hostname, server_url->port ); + else + snprintf(str, 256, "Host: %s", server_url->hostname ); + http_set_field( http_hdr, str); + if (network_useragent) + { + snprintf(str, 256, "User-Agent: %s", network_useragent); + http_set_field(http_hdr, str); + } + else + http_set_field( http_hdr, "User-Agent: MPlayer/"VERSION); + + http_set_field(http_hdr, "Icy-MetaData: 1"); + + if(pos>0) { + // Extend http_send_request with possibility to do partial content retrieval + snprintf(str, 256, "Range: bytes=%"PRId64"-", (int64_t)pos); + http_set_field(http_hdr, str); + } + + if (network_cookies_enabled) cookies_set( http_hdr, server_url->hostname, server_url->url ); + + http_set_field( http_hdr, "Connection: close"); + http_add_basic_authentication( http_hdr, url->username, url->password ); + if( http_build_request( http_hdr )==NULL ) { + goto err_out; + } + + if( proxy ) { + if( url->port==0 ) url->port = 8080; // Default port for the proxy server + fd = connect2Server( url->hostname, url->port,1 ); + url_free( server_url ); + server_url = NULL; + } else { + if( server_url->port==0 ) server_url->port = 80; // Default port for the web server + fd = connect2Server( server_url->hostname, server_url->port,1 ); + } + if( fd<0 ) { + goto err_out; + } + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request: [%s]\n", http_hdr->buffer ); + + ret = send( fd, http_hdr->buffer, http_hdr->buffer_size, 0 ); + if( ret!=(int)http_hdr->buffer_size ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrSendingHTTPRequest); + goto err_out; + } + + http_free( http_hdr ); + + return fd; +err_out: + http_free(http_hdr); + if (proxy && server_url) + url_free(server_url); + return -1; +} + +HTTP_header_t * +http_read_response( int fd ) { + HTTP_header_t *http_hdr; + char response[BUFFER_SIZE]; + int i; + + http_hdr = http_new_header(); + if( http_hdr==NULL ) { + return NULL; + } + + do { + i = recv( fd, response, BUFFER_SIZE, 0 ); + if( i<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ReadFailed); + http_free( http_hdr ); + return NULL; + } + if( i==0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_Read0CouldBeEOF); + http_free( http_hdr ); + return NULL; + } + http_response_append( http_hdr, response, i ); + } while( !http_is_header_entire( http_hdr ) ); + http_response_parse( http_hdr ); + return http_hdr; +} + +int +http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry) { + char *aut; + + if( *auth_retry==1 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_AuthFailed); + return -1; + } + if( *auth_retry>0 ) { + if( url->username ) { + free( url->username ); + url->username = NULL; + } + if( url->password ) { + free( url->password ); + url->password = NULL; + } + } + + aut = http_get_field(http_hdr, "WWW-Authenticate"); + if( aut!=NULL ) { + char *aut_space; + aut_space = strstr(aut, "realm="); + if( aut_space!=NULL ) aut_space += 6; + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_AuthRequiredFor, aut_space); + } else { + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_AuthRequired); + } + if( network_username ) { + url->username = strdup(network_username); + if( url->username==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return -1; + } + } else { + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_AuthFailed); + return -1; + } + if( network_password ) { + url->password = strdup(network_password); + if( url->password==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return -1; + } + } else { + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_NoPasswdProvidedTryingBlank); + } + (*auth_retry)++; + return 0; +} + +int +http_seek( stream_t *stream, off_t pos ) { + HTTP_header_t *http_hdr = NULL; + int fd; + if( stream==NULL ) return 0; + + if( stream->fd>0 ) closesocket(stream->fd); // need to reconnect to seek in http-stream + fd = http_send_request( stream->streaming_ctrl->url, pos ); + if( fd<0 ) return 0; + + http_hdr = http_read_response( fd ); + + if( http_hdr==NULL ) return 0; + + switch( http_hdr->status_code ) { + case 200: + case 206: // OK + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Type: [%s]\n", http_get_field(http_hdr, "Content-Type") ); + mp_msg(MSGT_NETWORK,MSGL_V,"Content-Length: [%s]\n", http_get_field(http_hdr, "Content-Length") ); + if( http_hdr->body_size>0 ) { + if( streaming_bufferize( stream->streaming_ctrl, http_hdr->body, http_hdr->body_size )<0 ) { + http_free( http_hdr ); + return -1; + } + } + break; + default: + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrServerReturned, http_hdr->status_code, http_hdr->reason_phrase ); + close( fd ); + fd = -1; + } + stream->fd = fd; + + if( http_hdr ) { + http_free( http_hdr ); + stream->streaming_ctrl->data = NULL; + } + + stream->pos=pos; + + return 1; +} + + +int +streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size) { +//printf("streaming_bufferize\n"); + streaming_ctrl->buffer = malloc(size); + if( streaming_ctrl->buffer==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + return -1; + } + memcpy( streaming_ctrl->buffer, buffer, size ); + streaming_ctrl->buffer_size = size; + return size; +} + +int +nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { + int len=0; +//printf("nop_streaming_read\n"); + if( stream_ctrl->buffer_size!=0 ) { + int buffer_len = stream_ctrl->buffer_size-stream_ctrl->buffer_pos; +//printf("%d bytes in buffer\n", stream_ctrl->buffer_size); + len = (size<buffer_len)?size:buffer_len; + memcpy( buffer, (stream_ctrl->buffer)+(stream_ctrl->buffer_pos), len ); + stream_ctrl->buffer_pos += len; +//printf("buffer_pos = %d\n", stream_ctrl->buffer_pos ); + if( stream_ctrl->buffer_pos>=stream_ctrl->buffer_size ) { + free( stream_ctrl->buffer ); + stream_ctrl->buffer = NULL; + stream_ctrl->buffer_size = 0; + stream_ctrl->buffer_pos = 0; +//printf("buffer cleaned\n"); + } +//printf("read %d bytes from buffer\n", len ); + } + + if( len<size ) { + int ret; + ret = recv( fd, buffer+len, size-len, 0 ); + if( ret<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : %s\n",strerror(errno)); + } + len += ret; +//printf("read %d bytes from network\n", len ); + } + + return len; +} + +int +nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl ) { + return -1; + // To shut up gcc warning + fd++; + pos++; + stream_ctrl=NULL; +} + + +void fixup_network_stream_cache(stream_t *stream) { + if(stream->streaming_ctrl->buffering) { + if(stream_cache_size<0) { + // cache option not set, will use our computed value. + // buffer in KBytes, *5 because the prefill is 20% of the buffer. + stream_cache_size = (stream->streaming_ctrl->prebuffer_size/1024)*5; + if( stream_cache_size<64 ) stream_cache_size = 64; // 16KBytes min buffer + } + mp_msg(MSGT_NETWORK,MSGL_INFO,MSGTR_MPDEMUX_NW_CacheSizeSetTo, stream_cache_size); + } +} + + +int +streaming_stop( stream_t *stream ) { + stream->streaming_ctrl->status = streaming_stopped_e; + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/network.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,68 @@ +/* + * Network layer for MPlayer + * by Bertrand BAUDET <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + */ + +#ifndef __NETWORK_H +#define __NETWORK_H + +#include <fcntl.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#endif + +#include "url.h" +#include "http.h" +#include "stream.h" + +#define BUFFER_SIZE 2048 + +typedef struct { + const char *mime_type; + int demuxer_type; +} mime_struct_t; + +typedef enum { + streaming_stopped_e, + streaming_playing_e +} streaming_status; + +typedef struct streaming_control { + URL_t *url; + streaming_status status; + int buffering; // boolean + unsigned int prebuffer_size; + char *buffer; + unsigned int buffer_size; + unsigned int buffer_pos; + unsigned int bandwidth; // The downstream available + int (*streaming_read)( int fd, char *buffer, int buffer_size, struct streaming_control *stream_ctrl ); + int (*streaming_seek)( int fd, off_t pos, struct streaming_control *stream_ctrl ); + void *data; +} streaming_ctrl_t; + +//int streaming_start( stream_t *stream, int *demuxer_type, URL_t *url ); +streaming_ctrl_t *streaming_ctrl_new(void); +int streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size); + +int nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ); +int nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl ); +void streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ); + +int connect2Server(char *host, int port,int verb); + +int http_send_request(URL_t *url, off_t pos); +HTTP_header_t *http_read_response(int fd); + +int http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry); +URL_t* check4proxies(URL_t *url); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/open.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,49 @@ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifdef __FreeBSD__ +#include <sys/cdrio.h> +#endif + +#include "m_option.h" +#include "stream.h" +#include "demuxer.h" +#include "mf.h" + + +/// We keep these 2 for the gui atm, but they will be removed. +int vcd_track=0; +char* cdrom_device=NULL; +int dvd_chapter=1; +int dvd_last_chapter=0; +char* dvd_device=NULL; +int dvd_title=0; + +// Open a new stream (stdin/file/vcd/url) + +stream_t* open_stream(char* filename,char** options, int* file_format){ + // Check if playlist or unknown + if (*file_format != DEMUXER_TYPE_PLAYLIST){ + *file_format=DEMUXER_TYPE_UNKNOWN; + } + +if(!filename) { + mp_msg(MSGT_OPEN,MSGL_ERR,"NULL filename, report this bug\n"); + return NULL; +} + +//============ Open STDIN or plain FILE ============ + + return open_stream_full(filename,STREAM_READ,options,file_format); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/pnm.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * $Id$ + * + * pnm protocol implementation + * based upon code from joschka + */ + +#include "config.h" + +#include <unistd.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/time.h> +#include <inttypes.h> +#ifndef HAVE_WINSOCK2 +#define closesocket close +#include <sys/socket.h> +//#include <netinet/in.h> +//#include <netdb.h> +#else +#include <winsock2.h> +#endif + +#include "stream.h" +#include "demuxer.h" +#include "help_mp.h" +#include "osdep/timer.h" + +#include "pnm.h" +//#include "libreal/rmff.h" + +extern int network_bandwidth; + +#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ + (((long)(unsigned char)(ch3) ) | \ + ( (long)(unsigned char)(ch2) << 8 ) | \ + ( (long)(unsigned char)(ch1) << 16 ) | \ + ( (long)(unsigned char)(ch0) << 24 ) ) + + +#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') +#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') +#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') +#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') +#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') +#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') +#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) + +/* +#define LOG +*/ + +#define BUF_SIZE 4096 +#define HEADER_SIZE 4096 + +struct pnm_s { + + int s; + +// char *host; +// int port; + char *path; +// char *url; + + char buffer[BUF_SIZE]; /* scratch buffer */ + + /* receive buffer */ + uint8_t recv[BUF_SIZE]; + int recv_size; + int recv_read; + + uint8_t header[HEADER_SIZE]; + int header_len; + int header_read; + unsigned int seq_num[4]; /* two streams with two indices */ + unsigned int seq_current[2]; /* seqs of last stream chunk read */ + uint32_t ts_current; /* timestamp of current chunk */ + uint32_t ts_last[2]; /* timestamps of last chunks */ + unsigned int packet; /* number of last recieved packet */ +}; + +/* + * utility macros + */ + +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) +#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ + (((uint8_t*)(x))[1] << 16) | \ + (((uint8_t*)(x))[2] << 8) | \ + ((uint8_t*)(x))[3]) + +/* D means direct (no pointer) */ +#define BE_16D(x) ((x & 0xff00) >> 8)|((x & 0x00ff) << 8) + +/* sizes */ +#define PREAMBLE_SIZE 8 +#define CHECKSUM_SIZE 3 + + +/* header of rm files */ +#define RM_HEADER_SIZE 0x12 +static const unsigned char rm_header[]={ + 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */ + 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */ + 0x00, 0x00, /* object_version 0x00 */ + 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */ + 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */ +}; + +/* data chunk header */ +#define PNM_DATA_HEADER_SIZE 18 +static const unsigned char pnm_data_header[]={ + 'D','A','T','A', + 0,0,0,0, /* data chunk size */ + 0,0, /* object version */ + 0,0,0,0, /* num packets */ + 0,0,0,0}; /* next data header */ + +/* pnm request chunk ids */ + +#define PNA_CLIENT_CAPS 0x03 +#define PNA_CLIENT_CHALLANGE 0x04 +#define PNA_BANDWIDTH 0x05 +#define PNA_GUID 0x13 +#define PNA_TIMESTAMP 0x17 +#define PNA_TWENTYFOUR 0x18 + +#define PNA_CLIENT_STRING 0x63 +#define PNA_PATH_REQUEST 0x52 + +static const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56"; +static const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]"; +static const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0"; +static const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf"; +static const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l"; + +#define PNM_HEADER_SIZE 11 +static const unsigned char pnm_header[] = { + 'P','N','A', + 0x00, 0x0a, + 0x00, 0x14, + 0x00, 0x02, + 0x00, 0x01 }; + +#define PNM_CLIENT_CAPS_SIZE 126 +static const unsigned char pnm_client_caps[] = { + 0x07, 0x8a, 'p','n','r','v', + 0, 0x90, 'p','n','r','v', + 0, 0x64, 'd','n','e','t', + 0, 0x46, 'p','n','r','v', + 0, 0x32, 'd','n','e','t', + 0, 0x2b, 'p','n','r','v', + 0, 0x28, 'd','n','e','t', + 0, 0x24, 'p','n','r','v', + 0, 0x19, 'd','n','e','t', + 0, 0x18, 'p','n','r','v', + 0, 0x14, 's','i','p','r', + 0, 0x14, 'd','n','e','t', + 0, 0x24, '2','8','_','8', + 0, 0x12, 'p','n','r','v', + 0, 0x0f, 'd','n','e','t', + 0, 0x0a, 's','i','p','r', + 0, 0x0a, 'd','n','e','t', + 0, 0x08, 's','i','p','r', + 0, 0x06, 's','i','p','r', + 0, 0x12, 'l','p','c','J', + 0, 0x07, '0','5','_','6' }; + +static const uint32_t pnm_default_bandwidth=10485800; +static const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600, + 115200,262200,393216,524300,1544000,10485800}; + +#define PNM_TWENTYFOUR_SIZE 16 +static unsigned char pnm_twentyfour[]={ + 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24, + 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 }; + +/* now other data follows. marked with 0x0000 at the beginning */ +static int after_chunks_length=6; +static unsigned char after_chunks[]={ + 0x00, 0x00, /* mark */ + + 0x50, 0x84, /* seems to be fixated */ + 0x1f, 0x3a /* varies on each request (checksum ?)*/ + }; + +static void hexdump (char *buf, int length); + +static int rm_write(int s, const char *buf, int len) { + int total, timeout; + + total = 0; timeout = 30; + while (total < len){ + int n; + + n = send (s, &buf[total], len - total, 0); + + if (n > 0) + total += n; + else if (n < 0) { +#ifndef HAVE_WINSOCK2 + if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { +#else + if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { +#endif + usec_sleep (1000000); timeout--; + } else + return -1; + } + } + + return total; +} + +static ssize_t rm_read(int fd, void *buf, size_t count) { + + ssize_t ret, total; + + total = 0; + + while (total < count) { + + fd_set rset; + struct timeval timeout; + + FD_ZERO (&rset); + FD_SET (fd, &rset); + + timeout.tv_sec = 3; + timeout.tv_usec = 0; + + if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { + return -1; + } + + ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); + + if (ret<=0) { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: read error.\n"); + return ret; + } else + total += ret; + } + + return total; +} + +/* + * debugging utilities + */ + +static void hexdump (char *buf, int length) { + + int i; + + mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: ascii>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + mp_msg(MSGT_OPEN, MSGL_INFO, "%c", c); + else + mp_msg(MSGT_OPEN, MSGL_INFO, "."); + } + mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); + + mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + mp_msg(MSGT_OPEN, MSGL_INFO, "%02x", c); + + if ((i % 16) == 15) + mp_msg(MSGT_OPEN, MSGL_INFO, "\npnm: "); + + if ((i % 2) == 1) + mp_msg(MSGT_OPEN, MSGL_INFO, " "); + + } + mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); +} + +/* + * pnm_get_chunk gets a chunk from stream + * and returns number of bytes read + */ + +static int pnm_get_chunk(pnm_t *p, + unsigned int max, + unsigned int *chunk_type, + char *data, int *need_response) { + + unsigned int chunk_size; + unsigned int n; + char *ptr; + + if (max < PREAMBLE_SIZE) + return -1; + + /* get first PREAMBLE_SIZE bytes and ignore checksum */ + rm_read (p->s, data, CHECKSUM_SIZE); + if (data[0] == 0x72) + rm_read (p->s, data, PREAMBLE_SIZE); + else + rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); + + max -= PREAMBLE_SIZE; + + *chunk_type = BE_32(data); + chunk_size = BE_32(data+4); + + switch (*chunk_type) { + case PNA_TAG: + *need_response=0; + ptr=data+PREAMBLE_SIZE; + if (max < 1) + return -1; + rm_read (p->s, ptr++, 1); + max -= 1; + + while(1) { + /* expecting following chunk format: 0x4f <chunk size> <data...> */ + + if (max < 2) + return -1; + rm_read (p->s, ptr, 2); + max -= 2; + if (*ptr == 'X') /* checking for server message */ + { + mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got a message from server:\n"); + if (max < 1) + return -1; + rm_read (p->s, ptr+2, 1); + max = -1; + n=BE_16(ptr+1); + if (max < n) + return -1; + rm_read (p->s, ptr+3, n); + max -= n; + ptr[3+n]=0; + mp_msg(MSGT_OPEN, MSGL_WARN, "%s\n",ptr+3); + return -1; + } + + if (*ptr == 'F') /* checking for server error */ + { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); + return -1; + } + if (*ptr == 'i') + { + ptr+=2; + *need_response=1; + continue; + } + if (*ptr != 0x4f) break; + n=ptr[1]; + if (max < n) + return -1; + rm_read (p->s, ptr+2, n); + max -= n; + ptr+=(n+2); + } + /* the checksum of the next chunk is ignored here */ + if (max < 1) + return -1; + rm_read (p->s, ptr+2, 1); + ptr+=3; + chunk_size=ptr-data; + break; + case RMF_TAG: + case DATA_TAG: + case PROP_TAG: + case MDPR_TAG: + case CONT_TAG: + if (chunk_size > max || chunk_size < PREAMBLE_SIZE) { + mp_msg(MSGT_OPEN, MSGL_ERR, "error: max chunk size exceded (max was 0x%04x)\n", max); +#ifdef LOG + n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); + hexdump(data,n+PREAMBLE_SIZE); +#endif + return -1; + } + rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); + break; + default: + *chunk_type = 0; + chunk_size = PREAMBLE_SIZE; + break; + } + + return chunk_size; +} + +/* + * writes a chunk to a buffer, returns number of bytes written + */ + +static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, + const char *chunk, char *data) { + + data[0]=(chunk_id>>8)%0xff; + data[1]=chunk_id%0xff; + data[2]=(length>>8)%0xff; + data[3]=length%0xff; + memcpy(&data[4],chunk,length); + + return length+4; +} + +/* + * constructs a request and sends it + */ + +static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { + + uint16_t i16; + int c=PNM_HEADER_SIZE; + char fixme[]={0,1}; + + memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); + c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), + pnm_challenge,&p->buffer[c]); + c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, + pnm_client_caps,&p->buffer[c]); + c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); + c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), + pnm_timestamp,&p->buffer[c]); + c+=pnm_write_chunk(PNA_BANDWIDTH,4, + (const char *)&pnm_default_bandwidth,&p->buffer[c]); + c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); + c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), + pnm_guid,&p->buffer[c]); + c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, + pnm_twentyfour,&p->buffer[c]); + + /* data after chunks */ + memcpy(&p->buffer[c],after_chunks,after_chunks_length); + c+=after_chunks_length; + + /* client id string */ + p->buffer[c]=PNA_CLIENT_STRING; + i16=BE_16D((strlen(client_string)-1)); /* don't know why do we have -1 here */ + memcpy(&p->buffer[c+1],&i16,2); + memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); + c=c+3+strlen(client_string)+1; + + /* file path */ + p->buffer[c]=0; + p->buffer[c+1]=PNA_PATH_REQUEST; + i16=BE_16D(strlen(p->path)); + memcpy(&p->buffer[c+2],&i16,2); + memcpy(&p->buffer[c+4],p->path,strlen(p->path)); + c=c+4+strlen(p->path); + + /* some trailing bytes */ + p->buffer[c]='y'; + p->buffer[c+1]='B'; + + rm_write(p->s,p->buffer,c+2); +} + +/* + * pnm_send_response sends a response of a challenge + */ + +static void pnm_send_response(pnm_t *p, const char *response) { + + int size=strlen(response); + + p->buffer[0]=0x23; + p->buffer[1]=0; + p->buffer[2]=(unsigned char) size; + + memcpy(&p->buffer[3], response, size); + + rm_write (p->s, p->buffer, size+3); + +} + +/* + * get headers and challenge and fix headers + * write headers to p->header + * write challenge to p->buffer + * + * return 0 on error. != 0 on success + */ + +static int pnm_get_headers(pnm_t *p, int *need_response) { + + uint32_t chunk_type; + uint8_t *ptr=p->header; + uint8_t *prop_hdr=NULL; + int chunk_size,size=0; + int nr; +/* rmff_header_t *h; */ + + *need_response=0; + + while(1) { + if (HEADER_SIZE-size<=0) + { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: header buffer overflow. exiting\n"); + return 0; + } + chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); + if (chunk_size < 0) return 0; + if (chunk_type == 0) break; + if (chunk_type == PNA_TAG) + { + memcpy(ptr, rm_header, RM_HEADER_SIZE); + chunk_size=RM_HEADER_SIZE; + *need_response=nr; + } + if (chunk_type == DATA_TAG) + chunk_size=0; + if (chunk_type == RMF_TAG) + chunk_size=0; + if (chunk_type == PROP_TAG) + prop_hdr=ptr; + size+=chunk_size; + ptr+=chunk_size; + } + + if (!prop_hdr) { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: error while parsing headers.\n"); + return 0; + } + + /* set data offset */ + size--; + prop_hdr[42]=(size>>24)%0xff; + prop_hdr[43]=(size>>16)%0xff; + prop_hdr[44]=(size>>8)%0xff; + prop_hdr[45]=(size)%0xff; + size++; + + /* read challenge */ + memcpy (p->buffer, ptr, PREAMBLE_SIZE); + rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); + + /* now write a data header */ + memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); + size+=PNM_DATA_HEADER_SIZE; +/* + h=rmff_scan_header(p->header); + rmff_fix_header(h); + p->header_len=rmff_get_header_size(h); + rmff_dump_header(h, p->header, HEADER_SIZE); +*/ + p->header_len=size; + + return 1; +} + +/* + * determine correct stream number by looking at indices + */ + +static int pnm_calc_stream(pnm_t *p) { + + char str0=0,str1=0; + + /* looking at the first index to + * find possible stream types + */ + if (p->seq_current[0]==p->seq_num[0]) str0=1; + if (p->seq_current[0]==p->seq_num[2]) str1=1; + + switch (str0+str1) { + case 1: /* one is possible, good. */ + if (str0) + { + p->seq_num[0]++; + p->seq_num[1]=p->seq_current[1]+1; + return 0; + } else + { + p->seq_num[2]++; + p->seq_num[3]=p->seq_current[1]+1; + return 1; + } + break; + case 0: + case 2: /* both types or none possible, not so good */ + /* try to figure out by second index */ + if ( (p->seq_current[1] == p->seq_num[1]) + &&(p->seq_current[1] != p->seq_num[3])) + { + /* ok, only stream0 matches */ + p->seq_num[0]=p->seq_current[0]+1; + p->seq_num[1]++; + return 0; + } + if ( (p->seq_current[1] == p->seq_num[3]) + &&(p->seq_current[1] != p->seq_num[1])) + { + /* ok, only stream1 matches */ + p->seq_num[2]=p->seq_current[0]+1; + p->seq_num[3]++; + return 1; + } + /* wow, both streams match, or not. */ + /* now we try to decide by timestamps */ + if (p->ts_current < p->ts_last[1]) + return 0; + if (p->ts_current < p->ts_last[0]) + return 1; + /* does not help, we guess type 0 */ +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "guessing stream# 0\n"); +#endif + p->seq_num[0]=p->seq_current[0]+1; + p->seq_num[1]=p->seq_current[1]+1; + return 0; + break; + } + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); + return 2; +} + +/* + * gets a stream chunk and writes it to a recieve buffer + */ + +static int pnm_get_stream_chunk(pnm_t *p) { + + int n; + char keepalive='!'; + unsigned int fof1, fof2, stream; + + /* send a keepalive */ + /* realplayer seems to do that every 43th package */ + if ((p->packet%43) == 42) + { + rm_write(p->s,&keepalive,1); + } + + /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> + * where <o> is the offset to next stream chunk, + * <i1> is a 16 bit index + * <i2> is a 8 bit index which counts from 0x10 to somewhere + */ + + n = rm_read (p->s, p->buffer, 8); + if (n<0) return -1; + if (n<8) return 0; + + /* skip 8 bytes if 0x62 is read */ + if (p->buffer[0] == 0x62) + { + n = rm_read (p->s, p->buffer, 8); + if (n<8) return 0; +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek 8 bytes on 0x62\n"); +#endif + } + + /* a server message */ + if (p->buffer[0] == 'X') + { + int size=BE_16(&p->buffer[1]); + + rm_read (p->s, &p->buffer[8], size-5); + p->buffer[size+3]=0; + mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); + return -1; + } + if (p->buffer[0] == 'F') + { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); + return -1; + } + + /* skip bytewise to next chunk. + * seems, that we don't need that, if we send enough + * keepalives + */ + n=0; + while (p->buffer[0] != 0x5a) { + int i; + for (i=1; i<8; i++) { + p->buffer[i-1]=p->buffer[i]; + } + rm_read (p->s, &p->buffer[7], 1); + n++; + } + +#ifdef LOG + if (n) mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek %i bytes to next chunk\n", n); +#endif + + /* check for 'Z's */ + if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) + { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: bad boundaries\n"); + hexdump(p->buffer, 8); + return 0; + } + + /* check offsets */ + fof1=BE_16(&p->buffer[1]); + fof2=BE_16(&p->buffer[3]); + if (fof1 != fof2) + { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); + return 0; + } + + /* get first index */ + p->seq_current[0]=BE_16(&p->buffer[5]); + + /* now read the rest of stream chunk */ + n = rm_read (p->s, &p->recv[5], fof1-5); + if (n<(fof1-5)) return 0; + + /* get second index */ + p->seq_current[1]=p->recv[5]; + + /* get timestamp */ + p->ts_current=BE_32(&p->recv[6]); + + /* get stream number */ + stream=pnm_calc_stream(p); + + /* saving timestamp */ + p->ts_last[stream]=p->ts_current; + + /* constructing a data packet header */ + + p->recv[0]=0; /* object version */ + p->recv[1]=0; + + fof2=BE_16(&fof2); + memcpy(&p->recv[2], &fof2, 2); + /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ + /*p->recv[3]=(fof2)%0xff;*/ + + p->recv[4]=0; /* stream number */ + p->recv[5]=stream; + + p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ + + p->packet++; + + p->recv_size=fof1; + + return fof1; +} + +// pnm_t *pnm_connect(const char *mrl) { +static pnm_t *pnm_connect(int fd, char *path) { + + pnm_t *p=malloc(sizeof(pnm_t)); + int need_response=0; + + p->path=strdup(path); + p->s=fd; + + pnm_send_request(p,pnm_available_bandwidths[10]); + if (!pnm_get_headers(p, &need_response)) { + mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: failed to set up stream\n"); + free(p->path); + free(p); + return NULL; + } + if (need_response) + pnm_send_response(p, pnm_response); + p->ts_last[0]=0; + p->ts_last[1]=0; + + /* copy header to recv */ + + memcpy(p->recv, p->header, p->header_len); + p->recv_size = p->header_len; + p->recv_read = 0; + + return p; +} + +static int pnm_read (pnm_t *this, char *data, int len) { + + int to_copy=len; + char *dest=data; + char *source=this->recv + this->recv_read; + int fill=this->recv_size - this->recv_read; + int retval; + + if (len < 0) return 0; + while (to_copy > fill) { + + memcpy(dest, source, fill); + to_copy -= fill; + dest += fill; + this->recv_read=0; + + if ((retval = pnm_get_stream_chunk (this)) <= 0) { +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d of %d bytes provided\n", len-to_copy, len); +#endif + if (retval < 0) + return retval; + else + return len-to_copy; + } + source = this->recv; + fill = this->recv_size - this->recv_read; + } + + memcpy(dest, source, to_copy); + this->recv_read += to_copy; + +#ifdef LOG + mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d bytes provided\n", len); +#endif + + return len; +} + +static int pnm_peek_header (pnm_t *this, char *data) { + + memcpy (data, this->header, this->header_len); + return this->header_len; +} + +static void pnm_close(pnm_t *p) { + + if (p->s >= 0) closesocket(p->s); + free(p->path); + free(p); +} + +static int pnm_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { + return pnm_read(stream_ctrl->data, buffer, size); +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + int fd; + pnm_t *pnm; + URL_t *url; + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_PNM, URL: %s\n", stream->url); + stream->streaming_ctrl = streaming_ctrl_new(); + if(stream->streaming_ctrl==NULL) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + //url_free(url); + + fd = connect2Server( stream->streaming_ctrl->url->hostname, + stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 ); + + if(fd<0) + goto fail; + + pnm = pnm_connect(fd,stream->streaming_ctrl->url->file); + if(!pnm) + goto fail; + stream->type = STREAMTYPE_STREAM; + stream->fd=fd; + stream->streaming_ctrl->data=pnm; + stream->streaming_ctrl->streaming_read = pnm_streaming_read; + //stream->streaming_ctrl->streaming_seek = nop_streaming_seek; + stream->streaming_ctrl->prebuffer_size = 8*1024; // 8 KBytes + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + *file_format = DEMUXER_TYPE_REAL; + fixup_network_stream_cache(stream); + return STREAM_OK; + +fail: + streaming_ctrl_free(stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; +} + + +stream_info_t stream_info_pnm = { + "RealNetworks pnm", + "pnm", + "Arpi, xine team", + "ported from xine", + open_s, + {"pnm", NULL}, //pnm as fallback + NULL, + 0 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/asmrp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,677 @@ +/* + * This file was ported to MPlayer from xine CVS asmrp.c,v 1.2 2002/12/17 16:49:48 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * a parser for real's asm rules + * + * grammar for these rules: + * + + rule_book = { rule } + rule = ( '#' condition { ',' assignment } | [ assignment {',' assignment} ]) ';' + assignment = id '=' const + const = ( number | string ) + condition = comp_expr { ( '&&' | '||' ) comp_expr } + comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } + operand = ( '$' id | num | '(' condition ')' ) + + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* +#define LOG +*/ + +#define ASMRP_SYM_NONE 0 +#define ASMRP_SYM_EOF 1 + +#define ASMRP_SYM_NUM 2 +#define ASMRP_SYM_ID 3 +#define ASMRP_SYM_STRING 4 + +#define ASMRP_SYM_HASH 10 +#define ASMRP_SYM_SEMICOLON 11 +#define ASMRP_SYM_COMMA 12 +#define ASMRP_SYM_EQUALS 13 +#define ASMRP_SYM_AND 14 +#define ASMRP_SYM_OR 15 +#define ASMRP_SYM_LESS 16 +#define ASMRP_SYM_LEQ 17 +#define ASMRP_SYM_GEQ 18 +#define ASMRP_SYM_GREATER 19 +#define ASMRP_SYM_DOLLAR 20 +#define ASMRP_SYM_LPAREN 21 +#define ASMRP_SYM_RPAREN 22 + +#define ASMRP_MAX_ID 1024 + +#define ASMRP_MAX_SYMTAB 10 + +typedef struct { + char *id; + int v; +} asmrp_sym_t; + +typedef struct { + + /* public part */ + + int sym; + int num; + + char str[ASMRP_MAX_ID]; + + /* private part */ + + char *buf; + int pos; + char ch; + + asmrp_sym_t sym_tab[ASMRP_MAX_SYMTAB]; + int sym_tab_num; + +} asmrp_t; + +static asmrp_t *asmrp_new (void) { + + asmrp_t *p; + + p = malloc (sizeof (asmrp_t)); + + p->sym_tab_num = 0; + p->sym = ASMRP_SYM_NONE; + + return p; +} + +static void asmrp_dispose (asmrp_t *p) { + + int i; + + for (i=0; i<p->sym_tab_num; i++) + free (p->sym_tab[i].id); + + free (p); +} + +static void asmrp_getch (asmrp_t *p) { + p->ch = p->buf[p->pos]; + p->pos++; + +#ifdef LOG + printf ("%c\n", p->ch); +#endif + +} + +static void asmrp_init (asmrp_t *p, const char *str) { + + p->buf = strdup (str); + p->pos = 0; + + asmrp_getch (p); +} + +static void asmrp_number (asmrp_t *p) { + + int num; + + num = 0; + while ( (p->ch>='0') && (p->ch<='9') ) { + + num = num*10 + (p->ch - '0'); + + asmrp_getch (p); + } + + p->sym = ASMRP_SYM_NUM; + p->num = num; +} + +static void asmrp_string (asmrp_t *p) { + + int l; + + l = 0; + + while ( (p->ch!='"') && (p->ch>=32) ) { + + p->str[l] = p->ch; + + l++; + asmrp_getch (p); + } + p->str[l]=0; + + if (p->ch=='"') + asmrp_getch (p); + + p->sym = ASMRP_SYM_STRING; +} + +static void asmrp_identifier (asmrp_t *p) { + + int l; + + l = 0; + + while ( ((p->ch>='A') && (p->ch<='z')) + || ((p->ch>='0') && (p->ch<='9'))) { + + p->str[l] = p->ch; + + l++; + asmrp_getch (p); + } + p->str[l]=0; + + p->sym = ASMRP_SYM_ID; +} + +#ifdef LOG +static void asmrp_print_sym (asmrp_t *p) { + + printf ("symbol: "); + + switch (p->sym) { + + case ASMRP_SYM_NONE: + printf ("NONE\n"); + break; + + case ASMRP_SYM_EOF: + printf ("EOF\n"); + break; + + case ASMRP_SYM_NUM: + printf ("NUM %d\n", p->num); + break; + + case ASMRP_SYM_ID: + printf ("ID '%s'\n", p->str); + break; + + case ASMRP_SYM_STRING: + printf ("STRING \"%s\"\n", p->str); + break; + + case ASMRP_SYM_HASH: + printf ("#\n"); + break; + + case ASMRP_SYM_SEMICOLON: + printf (";\n"); + break; + case ASMRP_SYM_COMMA: + printf (",\n"); + break; + case ASMRP_SYM_EQUALS: + printf ("==\n"); + break; + case ASMRP_SYM_AND: + printf ("&&\n"); + break; + case ASMRP_SYM_OR: + printf ("||\n"); + break; + case ASMRP_SYM_LESS: + printf ("<\n"); + break; + case ASMRP_SYM_LEQ: + printf ("<=\n"); + break; + case ASMRP_SYM_GEQ: + printf (">=\n"); + break; + case ASMRP_SYM_GREATER: + printf (">\n"); + break; + case ASMRP_SYM_DOLLAR: + printf ("$\n"); + break; + case ASMRP_SYM_LPAREN: + printf ("(\n"); + break; + case ASMRP_SYM_RPAREN: + printf (")\n"); + break; + + default: + printf ("unknown symbol %d\n", p->sym); + } +} +#endif + +static void asmrp_get_sym (asmrp_t *p) { + + while (p->ch <= 32) { + if (p->ch == 0) { + p->sym = ASMRP_SYM_EOF; + return; + } + + asmrp_getch (p); + } + + if (p->ch == '\\') + asmrp_getch (p); + + switch (p->ch) { + + case '#': + p->sym = ASMRP_SYM_HASH; + asmrp_getch (p); + break; + case ';': + p->sym = ASMRP_SYM_SEMICOLON; + asmrp_getch (p); + break; + case ',': + p->sym = ASMRP_SYM_COMMA; + asmrp_getch (p); + break; + case '=': + p->sym = ASMRP_SYM_EQUALS; + asmrp_getch (p); + if (p->ch=='=') + asmrp_getch (p); + break; + case '&': + p->sym = ASMRP_SYM_AND; + asmrp_getch (p); + if (p->ch=='&') + asmrp_getch (p); + break; + case '|': + p->sym = ASMRP_SYM_OR; + asmrp_getch (p); + if (p->ch=='|') + asmrp_getch (p); + break; + case '<': + p->sym = ASMRP_SYM_LESS; + asmrp_getch (p); + if (p->ch=='=') { + p->sym = ASMRP_SYM_LEQ; + asmrp_getch (p); + } + break; + case '>': + p->sym = ASMRP_SYM_GREATER; + asmrp_getch (p); + if (p->ch=='=') { + p->sym = ASMRP_SYM_GEQ; + asmrp_getch (p); + } + break; + case '$': + p->sym = ASMRP_SYM_DOLLAR; + asmrp_getch (p); + break; + case '(': + p->sym = ASMRP_SYM_LPAREN; + asmrp_getch (p); + break; + case ')': + p->sym = ASMRP_SYM_RPAREN; + asmrp_getch (p); + break; + + case '"': + asmrp_getch (p); + asmrp_string (p); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + asmrp_number (p); + break; + + default: + asmrp_identifier (p); + } + +#ifdef LOG + asmrp_print_sym (p); +#endif + +} + +static int asmrp_find_id (asmrp_t *p, char *s) { + + int i; + + for (i=0; i<p->sym_tab_num; i++) { + if (!strcmp (s, p->sym_tab[i].id)) + return i; + } + + return -1; +} + +static int asmrp_set_id (asmrp_t *p, char *s, int v) { + + int i; + + i = asmrp_find_id (p, s); + + if (i<0) { + i = p->sym_tab_num; + p->sym_tab_num++; + p->sym_tab[i].id = strdup (s); + +#ifdef LOG + printf ("new symbol '%s'\n", s); +#endif + + } + + p->sym_tab[i].v = v; + +#ifdef LOG + printf ("symbol '%s' assigned %d\n", s, v); +#endif + + return i; +} + +static int asmrp_condition (asmrp_t *p) ; + +static int asmrp_operand (asmrp_t *p) { + + int i, ret; + +#ifdef LOG + printf ("operand\n"); +#endif + + ret = 0; + + switch (p->sym) { + + case ASMRP_SYM_DOLLAR: + + asmrp_get_sym (p); + + if (p->sym != ASMRP_SYM_ID) { + printf ("error: identifier expected.\n"); + abort(); + } + + i = asmrp_find_id (p, p->str); + if (i<0) { + printf ("error: unknown identifier %s\n", p->str); + } + ret = p->sym_tab[i].v; + + asmrp_get_sym (p); + break; + + case ASMRP_SYM_NUM: + ret = p->num; + + asmrp_get_sym (p); + break; + + case ASMRP_SYM_LPAREN: + asmrp_get_sym (p); + + ret = asmrp_condition (p); + + if (p->sym != ASMRP_SYM_RPAREN) { + printf ("error: ) expected.\n"); + abort(); + } + + asmrp_get_sym (p); + break; + + default: + printf ("syntax error, $ number or ( expected\n"); + abort(); + } + +#ifdef LOG + printf ("operand done, =%d\n", ret); +#endif + + return ret; +} + +static int asmrp_comp_expression (asmrp_t *p) { + + int a; + +#ifdef LOG + printf ("comp_expression\n"); +#endif + + a = asmrp_operand (p); + + while ( (p->sym == ASMRP_SYM_LESS) + || (p->sym == ASMRP_SYM_LEQ) + || (p->sym == ASMRP_SYM_EQUALS) + || (p->sym == ASMRP_SYM_GEQ) + || (p->sym == ASMRP_SYM_GREATER) ) { + int op = p->sym; + int b; + + asmrp_get_sym (p); + + b = asmrp_operand (p); + + switch (op) { + case ASMRP_SYM_LESS: + a = a<b; + break; + case ASMRP_SYM_LEQ: + a = a<=b; + break; + case ASMRP_SYM_EQUALS: + a = a==b; + break; + case ASMRP_SYM_GEQ: + a = a>=b; + break; + case ASMRP_SYM_GREATER: + a = a>b; + break; + } + + } + +#ifdef LOG + printf ("comp_expression done = %d\n", a); +#endif + return a; +} + +static int asmrp_condition (asmrp_t *p) { + + int a; + +#ifdef LOG + printf ("condition\n"); +#endif + + a = asmrp_comp_expression (p); + + while ( (p->sym == ASMRP_SYM_AND) || (p->sym == ASMRP_SYM_OR) ) { + int op, b; + + op = p->sym; + + asmrp_get_sym (p); + + b = asmrp_comp_expression (p); + + switch (op) { + case ASMRP_SYM_AND: + a = a & b; + break; + case ASMRP_SYM_OR: + a = a | b; + break; + } + } + +#ifdef LOG + printf ("condition done = %d\n", a); +#endif + return a; +} + +static void asmrp_assignment (asmrp_t *p) { + +#ifdef LOG + printf ("assignment\n"); +#endif + + if (p->sym == ASMRP_SYM_COMMA || p->sym == ASMRP_SYM_SEMICOLON) { +#ifdef LOG + printf ("empty assignment\n"); +#endif + return; + } + + if (p->sym != ASMRP_SYM_ID) { + printf ("error: identifier expected\n"); + abort (); + } + asmrp_get_sym (p); + + if (p->sym != ASMRP_SYM_EQUALS) { + printf ("error: = expected\n"); + abort (); + } + asmrp_get_sym (p); + + if ( (p->sym != ASMRP_SYM_NUM) && (p->sym != ASMRP_SYM_STRING) + && (p->sym != ASMRP_SYM_ID)) { + printf ("error: number or string expected\n"); + abort (); + } + asmrp_get_sym (p); + +#ifdef LOG + printf ("assignment done\n"); +#endif +} + +static int asmrp_rule (asmrp_t *p) { + + int ret; + +#ifdef LOG + printf ("rule\n"); +#endif + + ret = 1; + + if (p->sym == ASMRP_SYM_HASH) { + + asmrp_get_sym (p); + ret = asmrp_condition (p); + + while (p->sym == ASMRP_SYM_COMMA) { + + asmrp_get_sym (p); + + asmrp_assignment (p); + } + + } else if (p->sym != ASMRP_SYM_SEMICOLON) { + + asmrp_assignment (p); + + while (p->sym == ASMRP_SYM_COMMA) { + + asmrp_get_sym (p); + asmrp_assignment (p); + } + } + +#ifdef LOG + printf ("rule done = %d\n", ret); +#endif + + if (p->sym != ASMRP_SYM_SEMICOLON) { + printf ("semicolon expected.\n"); + abort (); + } + + asmrp_get_sym (p); + + return ret; +} + +static int asmrp_eval (asmrp_t *p, int *matches) { + + int rule_num, num_matches; + +#ifdef LOG + printf ("eval\n"); +#endif + + asmrp_get_sym (p); + + rule_num = 0; num_matches = 0; + while (p->sym != ASMRP_SYM_EOF) { + + if (asmrp_rule (p)) { +#ifdef LOG + printf ("rule #%d is true\n", rule_num); +#endif + matches[num_matches] = rule_num; + num_matches++; + } + + rule_num++; + } + + matches[num_matches] = -1; + return num_matches; +} + +int asmrp_match (const char *rules, int bandwidth, int *matches) { + + asmrp_t *p; + int num_matches; + + p = asmrp_new (); + + asmrp_init (p, rules); + + asmrp_set_id (p, "Bandwidth", bandwidth); + asmrp_set_id (p, "OldPNMPlayer", 0); + + num_matches = asmrp_eval (p, matches); + + asmrp_dispose (p); + + return num_matches; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/asmrp.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,45 @@ +/* + * This file was ported to MPlayer from xine CVS asmrp.h,v 1.1 2002/12/12 22:14:54 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * a parser for real's asm rules + * + * grammar for these rules: + * + + rule_book = { '#' rule ';'} + rule = condition {',' assignment} + assignment = id '=' const + const = ( number | string ) + condition = comp_expr { ( '&&' | '||' ) comp_expr } + comp_expr = operand { ( '<' | '<=' | '==' | '>=' | '>' ) operand } + operand = ( '$' id | num | '(' condition ')' ) + + */ + +#ifndef HAVE_ASMRP_H +#define HAVE_ASMRP_H + +int asmrp_match (const char *rules, int bandwidth, int *matches) ; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/real.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,612 @@ +/* + * This file was ported to MPlayer from xine CVS real.c,v 1.8 2003/03/30 17:11:50 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * special functions for real streams. + * adopted from joschkas real tools. + * + */ + +#include <stdio.h> +#include <string.h> + +#include "../config.h" +#include "../bswap.h" +#include "real.h" +#include "asmrp.h" +#include "sdpplin.h" +#include "xbuffer.h" +#if USE_LIBAVUTIL_SO +#include "ffmpeg/md5.h" +#else +#include "libavutil/md5.h" +#endif + +/* +#define LOG +*/ + +static const unsigned char xor_table[] = { + 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53, + 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70, + 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09, + 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02, + 0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 }; + + +#define BE_32C(x,y) (*((uint32_t*)(x))=be2me_32(y)) + +#define BE_16(x) be2me_16(*(uint16_t*)(x)) + +#define BE_32(x) be2me_32(*(uint32_t*)(x)) + +#ifndef MAX +#define MAX(x,y) ((x>y) ? x : y) +#endif + +#define BUF_SIZE 4096 + +#ifdef LOG +static void hexdump (const char *buf, int length) { + + int i; + + printf (" hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\n "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} +#endif + + +static void calc_response_string (char *result, char *challenge) { + + char zres[16]; + int i; + + av_md5_sum(zres, challenge, 64); + + /* convert zres to ascii string */ + for (i=0; i<16; i++ ) { + char a, b; + + a = (zres[i] >> 4) & 15; + b = zres[i] & 15; + + result[i*2] = ((a<10) ? (a+48) : (a+87)) & 255; + result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255; + } +} + +static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) { + + int ch_len, table_len, resp_len; + int i; + char *ptr; + char buf[128]; + + /* initialize return values */ + memset(response, 0, 64); + memset(chksum, 0, 34); + + /* initialize buffer */ + memset(buf, 0, 128); + ptr=buf; + BE_32C(ptr, 0xa1e9149d); + ptr+=4; + BE_32C(ptr, 0x0e6b3b59); + ptr+=4; + + /* some (length) checks */ + if (challenge != NULL) + { + ch_len = strlen (challenge); + + if (ch_len == 40) /* what a hack... */ + { + challenge[32]=0; + ch_len=32; + } + if ( ch_len > 56 ) ch_len=56; + + /* copy challenge to buf */ + memcpy(ptr, challenge, ch_len); + } + + table_len = strlen(xor_table); + + if (table_len > 56) table_len=56; + + /* xor challenge bytewise with xor_table */ + for (i=0; i<table_len; i++) + ptr[i] = ptr[i] ^ xor_table[i]; + + calc_response_string (response, buf); + + /* add tail */ + resp_len = strlen (response); + strcpy (&response[resp_len], "01d0a8e3"); + + /* calculate checksum */ + for (i=0; i<resp_len/4; i++) + chksum[i] = response[i*4]; +} + + +/* + * takes a MLTI-Chunk and a rule number got from match_asm_rule, + * returns a pointer to selected data and number of bytes in that. + */ + +static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) { + + int numrules, codec, size; + int i; + + /* MLTI chunk should begin with MLTI */ + + if ((mlti_chunk[0] != 'M') + ||(mlti_chunk[1] != 'L') + ||(mlti_chunk[2] != 'T') + ||(mlti_chunk[3] != 'I')) + { +#ifdef LOG + printf("libreal: MLTI tag not detected, copying data\n"); +#endif + *out = xbuffer_copyin(*out, 0, mlti_chunk, mlti_size); + return mlti_size; + } + + mlti_chunk+=4; + + /* next 16 bits are the number of rules */ + numrules=BE_16(mlti_chunk); + if (selection >= numrules) return 0; + + /* now <numrules> indices of codecs follows */ + /* we skip to selection */ + mlti_chunk+=(selection+1)*2; + + /* get our index */ + codec=BE_16(mlti_chunk); + + /* skip to number of codecs */ + mlti_chunk+=(numrules-selection)*2; + + /* get number of codecs */ + numrules=BE_16(mlti_chunk); + + if (codec >= numrules) { + printf("codec index >= number of codecs. %i %i\n", codec, numrules); + return 0; + } + + mlti_chunk+=2; + + /* now seek to selected codec */ + for (i=0; i<codec; i++) { + size=BE_32(mlti_chunk); + mlti_chunk+=size+4; + } + + size=BE_32(mlti_chunk); + +#ifdef LOG + hexdump(mlti_chunk+4, size); +#endif + *out = xbuffer_copyin(*out, 0, mlti_chunk+4, size); + return size; +} + +/* + * looking at stream description. + */ + +static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) { + + sdpplin_t *desc; + rmff_header_t *header; + char *buf; + int len, i; + int max_bit_rate=0; + int avg_bit_rate=0; + int max_packet_size=0; + int avg_packet_size=0; + int duration=0; + + + if (!data) return NULL; + + desc=sdpplin_parse(data); + + if (!desc) return NULL; + + buf = xbuffer_init(2048); + header=calloc(1,sizeof(rmff_header_t)); + + header->fileheader=rmff_new_fileheader(4+desc->stream_count); + header->cont=rmff_new_cont( + desc->title, + desc->author, + desc->copyright, + desc->abstract); + header->data=rmff_new_dataheader(0,0); + header->streams=calloc(1,sizeof(rmff_mdpr_t*)*(desc->stream_count+1)); +#ifdef LOG + printf("number of streams: %u\n", desc->stream_count); +#endif + + for (i=0; i<desc->stream_count; i++) { + + int j=0; + int n; + char b[64]; + int rulematches[16]; + +#ifdef LOG + printf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth); +#endif + n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches); + for (j=0; j<n; j++) { +#ifdef LOG + printf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id); +#endif + sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]); + *stream_rules = xbuffer_strcat(*stream_rules, b); + } + + if (!desc->stream[i]->mlti_data) { + len = 0; + buf = NULL; + } else + len=select_mlti_data(desc->stream[i]->mlti_data, desc->stream[i]->mlti_data_size, rulematches[0], &buf); + + header->streams[i]=rmff_new_mdpr( + desc->stream[i]->stream_id, + desc->stream[i]->max_bit_rate, + desc->stream[i]->avg_bit_rate, + desc->stream[i]->max_packet_size, + desc->stream[i]->avg_packet_size, + desc->stream[i]->start_time, + desc->stream[i]->preroll, + desc->stream[i]->duration, + desc->stream[i]->stream_name, + desc->stream[i]->mime_type, + len, + buf); + + duration=MAX(duration,desc->stream[i]->duration); + max_bit_rate+=desc->stream[i]->max_bit_rate; + avg_bit_rate+=desc->stream[i]->avg_bit_rate; + max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size); + if (avg_packet_size) + avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2; + else + avg_packet_size=desc->stream[i]->avg_packet_size; + } + + if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',') + (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */ + + header->prop=rmff_new_prop( + max_bit_rate, + avg_bit_rate, + max_packet_size, + avg_packet_size, + 0, + duration, + 0, + 0, + 0, + desc->stream_count, + desc->flags); + + rmff_fix_header(header); + buf = xbuffer_free(buf); + + return header; +} + +int real_get_rdt_chunk(rtsp_t *rtsp_session, char **buffer) { + + int n=1; + uint8_t header[8]; + rmff_pheader_t ph; + int size; + int flags1, flags2; + int unknown1; + uint32_t ts; + static uint32_t prev_ts = -1; + static int prev_stream_number = -1; + + n=rtsp_read_data(rtsp_session, header, 8); + if (n<8) return 0; + if (header[0] != 0x24) + { + printf("rdt chunk not recognized: got 0x%02x\n", header[0]); + return 0; + } + size=(header[1]<<16)+(header[2]<<8)+(header[3]); + flags1=header[4]; + if ((flags1!=0x40)&&(flags1!=0x42)) + { +#ifdef LOG + printf("got flags1: 0x%02x\n",flags1); +#endif + if(header[6] == 0x06) { + printf("Stream EOF detected\n"); + return -1; + } + header[0]=header[5]; + header[1]=header[6]; + header[2]=header[7]; + n=rtsp_read_data(rtsp_session, header+3, 5); + if (n<5) return 0; +#ifdef LOG + printf("ignoring bytes:\n"); + hexdump(header, 8); +#endif + n=rtsp_read_data(rtsp_session, header+4, 4); + if (n<4) return 0; + flags1=header[4]; + size-=9; + } + flags2=header[7]; + // header[5..6] == frame number in stream + unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]); + n=rtsp_read_data(rtsp_session, header, 6); + if (n<6) return 0; + ts=BE_32(header); + +#ifdef LOG + printf("ts: %u, size: %u, flags: 0x%02x, unknown values: 0x%06x 0x%02x 0x%02x\n", + ts, size, flags1, unknown1, header[4], header[5]); +#endif + size+=2; + + ph.object_version=0; + ph.length=size; + ph.stream_number=(flags1>>1)&1; + ph.timestamp=ts; + ph.reserved=0; + if ((flags2&1) == 0 && (prev_ts != ts || prev_stream_number != ph.stream_number)) + { + prev_ts = ts; + prev_stream_number = ph.stream_number; + ph.flags=2; + } + else + ph.flags=0; + *buffer = xbuffer_ensure_size(*buffer, 12+size); + rmff_dump_pheader(&ph, *buffer); + size-=12; + n=rtsp_read_data(rtsp_session, (*buffer)+12, size); + + return (n <= 0) ? 0 : n+12; +} + +static int convert_timestamp(char *str, int *sec, int *msec) { + int hh, mm, ss, ms = 0; + if (sscanf(str, "%d:%d:%d.%d", &hh, &mm, &ss, &ms) < 3) { + hh = 0; + if (sscanf(str, "%d:%d.%d", &mm, &ss, &ms) < 2) { + mm = 0; + if (sscanf(str, "%d.%d", &ss, &ms) < 1) { + ss = 0; + ms = 0; + } + } + } + if (sec) + *sec = hh * 3600 + mm * 60 + ss; + if (msec) + *msec = ms; + return 1; +} + +//! maximum size of the rtsp description, must be < INT_MAX +#define MAX_DESC_BUF (20 * 1024 * 1024) +rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth) { + + char *description=NULL; + char *session_id=NULL; + rmff_header_t *h; + char *challenge1; + char challenge2[64]; + char checksum[34]; + char *subscribe; + char *buf = xbuffer_init(256); + char *mrl=rtsp_get_mrl(rtsp_session); + unsigned int size; + int status; + uint32_t maxbandwidth = bandwidth; + + /* get challenge */ + challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1")); +#ifdef LOG + printf("real: Challenge1: %s\n", challenge1); +#endif + + /* set a reasonable default to get the best stream, unless bandwidth given */ + if (!bandwidth) + bandwidth = 10485800; + + /* request stream description */ + rtsp_schedule_field(rtsp_session, "Accept: application/sdp"); + sprintf(buf, "Bandwidth: %u", bandwidth); + rtsp_schedule_field(rtsp_session, buf); + rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000"); + rtsp_schedule_field(rtsp_session, "RegionData: 0"); + rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586"); + rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1"); + rtsp_schedule_field(rtsp_session, "Language: en-US"); + rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup"); + status=rtsp_request_describe(rtsp_session,NULL); + + if ( status<200 || status>299 ) + { + char *alert=rtsp_search_answers(rtsp_session,"Alert"); + if (alert) { + printf("real: got message from server:\n%s\n", alert); + } + rtsp_send_ok(rtsp_session); + buf = xbuffer_free(buf); + return NULL; + } + + /* receive description */ + size=0; + if (!rtsp_search_answers(rtsp_session,"Content-length")) + printf("real: got no Content-length!\n"); + else + size=atoi(rtsp_search_answers(rtsp_session,"Content-length")); + + // as size is unsigned this also catches the case (size < 0) + if (size > MAX_DESC_BUF) { + printf("real: Content-length for description too big (> %uMB)!\n", + MAX_DESC_BUF/(1024*1024) ); + xbuffer_free(buf); + return NULL; + } + + if (!rtsp_search_answers(rtsp_session,"ETag")) + printf("real: got no ETag!\n"); + else + session_id=strdup(rtsp_search_answers(rtsp_session,"ETag")); + +#ifdef LOG + printf("real: Stream description size: %u\n", size); +#endif + + description=malloc(size+1); + + if( rtsp_read_data(rtsp_session, description, size) <= 0) { + buf = xbuffer_free(buf); + return NULL; + } + description[size]=0; + + /* parse sdp (sdpplin) and create a header and a subscribe string */ + subscribe = xbuffer_init(256); + strcpy(subscribe, "Subscribe: "); + h=real_parse_sdp(description, &subscribe, bandwidth); + if (!h) { + subscribe = xbuffer_free(subscribe); + buf = xbuffer_free(buf); + return NULL; + } + rmff_fix_header(h); + +#ifdef LOG + printf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n", + h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams); +#endif + + /* setup our streams */ + real_calc_response_and_checksum (challenge2, checksum, challenge1); + buf = xbuffer_ensure_size(buf, strlen(challenge2) + strlen(checksum) + 32); + sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum); + rtsp_schedule_field(rtsp_session, buf); + buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); + sprintf(buf, "If-Match: %s", session_id); + rtsp_schedule_field(rtsp_session, buf); + rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); + buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); + sprintf(buf, "%s/streamid=0", mrl); + rtsp_request_setup(rtsp_session,buf,NULL); + + if (h->prop->num_streams > 1) { + rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play"); + buf = xbuffer_ensure_size(buf, strlen(session_id) + 32); + sprintf(buf, "If-Match: %s", session_id); + rtsp_schedule_field(rtsp_session, buf); + + buf = xbuffer_ensure_size(buf, strlen(mrl) + 32); + sprintf(buf, "%s/streamid=1", mrl); + rtsp_request_setup(rtsp_session,buf,NULL); + } + /* set stream parameter (bandwidth) with our subscribe string */ + rtsp_schedule_field(rtsp_session, subscribe); + rtsp_request_setparameter(rtsp_session,NULL); + + /* set delivery bandwidth */ + if (maxbandwidth) { + sprintf(buf, "SetDeliveryBandwidth: Bandwidth=%u;BackOff=0", maxbandwidth); + rtsp_schedule_field(rtsp_session, buf); + rtsp_request_setparameter(rtsp_session,NULL); + } + + { + int s_ss = 0, s_ms = 0, e_ss = 0, e_ms = 0; + char *str; + if ((str = rtsp_get_param(rtsp_session, "start"))) { + convert_timestamp(str, &s_ss, &s_ms); + free(str); + } + if ((str = rtsp_get_param(rtsp_session, "end"))) { + convert_timestamp(str, &e_ss, &e_ms); + free(str); + } + str = buf + sprintf(buf, s_ms ? "%s%d.%d-" : "%s%d-", "Range: npt=", s_ss, s_ms); + if (e_ss || e_ms) + sprintf(str, e_ms ? "%d.%d" : "%d", e_ss, e_ms); + } + rtsp_schedule_field(rtsp_session, buf); + /* and finally send a play request */ + rtsp_request_play(rtsp_session,NULL); + + subscribe = xbuffer_free(subscribe); + buf = xbuffer_free(buf); + return h; +} + +struct real_rtsp_session_t * +init_real_rtsp_session (void) +{ + struct real_rtsp_session_t *real_rtsp_session = NULL; + + real_rtsp_session = malloc (sizeof (struct real_rtsp_session_t)); + real_rtsp_session->recv = xbuffer_init (BUF_SIZE); + + return real_rtsp_session; +} + +void +free_real_rtsp_session (struct real_rtsp_session_t* real_session) +{ + if (!real_session) + return; + + xbuffer_free (real_session->recv); + free (real_session); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/real.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,56 @@ +/* + * This file was ported to MPlayer from xine CVS real.h,v 1.2 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * special functions for real streams. + * adopted from joschkas real tools. + * + */ + +#ifndef HAVE_REAL_H +#define HAVE_REAL_H + +#include "rmff.h" +#include "../librtsp/rtsp.h" + +#define HEADER_SIZE 4096 + +struct real_rtsp_session_t { + /* receive buffer */ + uint8_t *recv; + int recv_size; + int recv_read; + + /* header buffer */ + uint8_t header[HEADER_SIZE]; + int header_len; + int header_read; +}; + +int real_get_rdt_chunk(rtsp_t *rtsp_session, char **buffer); +rmff_header_t *real_setup_and_get_header(rtsp_t *rtsp_session, uint32_t bandwidth); +struct real_rtsp_session_t *init_real_rtsp_session (void); +void free_real_rtsp_session (struct real_rtsp_session_t* real_session); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/rmff.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,907 @@ +/* + * This file was ported to MPlayer from xine CVS rmff.c,v 1.3 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * functions for real media file format + * adopted from joschkas real tools + */ + +#include "rmff.h" +#include "xbuffer.h" + +/* +#define LOG +*/ + +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) +#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ + (((uint8_t*)(x))[1] << 16) | \ + (((uint8_t*)(x))[2] << 8) | \ + ((uint8_t*)(x))[3]) + +static void hexdump (const char *buf, int length) { + + int i; + + printf ("rmff: ascii>"); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + if ((c >= 32) && (c <= 128)) + printf ("%c", c); + else + printf ("."); + } + printf ("\n"); + + printf ("rmff: hexdump> "); + for (i = 0; i < length; i++) { + unsigned char c = buf[i]; + + printf ("%02x", c); + + if ((i % 16) == 15) + printf ("\nrmff: "); + + if ((i % 2) == 1) + printf (" "); + + } + printf ("\n"); +} + +/* + * writes header data to a buffer + */ + +static void rmff_dump_fileheader(rmff_fileheader_t *fileheader, char *buffer) { + + if (!fileheader) return; + fileheader->object_id=BE_32(&fileheader->object_id); + fileheader->size=BE_32(&fileheader->size); + fileheader->object_version=BE_16(&fileheader->object_version); + fileheader->file_version=BE_32(&fileheader->file_version); + fileheader->num_headers=BE_32(&fileheader->num_headers); + + memcpy(buffer, fileheader, 8); + memcpy(&buffer[8], &fileheader->object_version, 2); + memcpy(&buffer[10], &fileheader->file_version, 8); + + fileheader->size=BE_32(&fileheader->size); + fileheader->object_version=BE_16(&fileheader->object_version); + fileheader->file_version=BE_32(&fileheader->file_version); + fileheader->num_headers=BE_32(&fileheader->num_headers); + fileheader->object_id=BE_32(&fileheader->object_id); +} + +static void rmff_dump_prop(rmff_prop_t *prop, char *buffer) { + + if (!prop) return; + prop->object_id=BE_32(&prop->object_id); + prop->size=BE_32(&prop->size); + prop->object_version=BE_16(&prop->object_version); + prop->max_bit_rate=BE_32(&prop->max_bit_rate); + prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); + prop->max_packet_size=BE_32(&prop->max_packet_size); + prop->avg_packet_size=BE_32(&prop->avg_packet_size); + prop->num_packets=BE_32(&prop->num_packets); + prop->duration=BE_32(&prop->duration); + prop->preroll=BE_32(&prop->preroll); + prop->index_offset=BE_32(&prop->index_offset); + prop->data_offset=BE_32(&prop->data_offset); + prop->num_streams=BE_16(&prop->num_streams); + prop->flags=BE_16(&prop->flags); + + memcpy(buffer, prop, 8); + memcpy(&buffer[8], &prop->object_version, 2); + memcpy(&buffer[10], &prop->max_bit_rate, 36); + memcpy(&buffer[46], &prop->num_streams, 2); + memcpy(&buffer[48], &prop->flags, 2); + + prop->size=BE_32(&prop->size); + prop->object_version=BE_16(&prop->object_version); + prop->max_bit_rate=BE_32(&prop->max_bit_rate); + prop->avg_bit_rate=BE_32(&prop->avg_bit_rate); + prop->max_packet_size=BE_32(&prop->max_packet_size); + prop->avg_packet_size=BE_32(&prop->avg_packet_size); + prop->num_packets=BE_32(&prop->num_packets); + prop->duration=BE_32(&prop->duration); + prop->preroll=BE_32(&prop->preroll); + prop->index_offset=BE_32(&prop->index_offset); + prop->data_offset=BE_32(&prop->data_offset); + prop->num_streams=BE_16(&prop->num_streams); + prop->flags=BE_16(&prop->flags); + prop->object_id=BE_32(&prop->object_id); +} + +static void rmff_dump_mdpr(rmff_mdpr_t *mdpr, char *buffer) { + + int s1, s2, s3; + + if (!mdpr) return; + mdpr->object_id=BE_32(&mdpr->object_id); + mdpr->size=BE_32(&mdpr->size); + mdpr->object_version=BE_16(&mdpr->object_version); + mdpr->stream_number=BE_16(&mdpr->stream_number); + mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); + mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); + mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); + mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); + mdpr->start_time=BE_32(&mdpr->start_time); + mdpr->preroll=BE_32(&mdpr->preroll); + mdpr->duration=BE_32(&mdpr->duration); + + memcpy(buffer, mdpr, 8); + memcpy(&buffer[8], &mdpr->object_version, 2); + memcpy(&buffer[10], &mdpr->stream_number, 2); + memcpy(&buffer[12], &mdpr->max_bit_rate, 28); + memcpy(&buffer[40], &mdpr->stream_name_size, 1); + s1=mdpr->stream_name_size; + memcpy(&buffer[41], mdpr->stream_name, s1); + + memcpy(&buffer[41+s1], &mdpr->mime_type_size, 1); + s2=mdpr->mime_type_size; + memcpy(&buffer[42+s1], mdpr->mime_type, s2); + + mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); + memcpy(&buffer[42+s1+s2], &mdpr->type_specific_len, 4); + mdpr->type_specific_len=BE_32(&mdpr->type_specific_len); + s3=mdpr->type_specific_len; + memcpy(&buffer[46+s1+s2], mdpr->type_specific_data, s3); + + mdpr->size=BE_32(&mdpr->size); + mdpr->stream_number=BE_16(&mdpr->stream_number); + mdpr->max_bit_rate=BE_32(&mdpr->max_bit_rate); + mdpr->avg_bit_rate=BE_32(&mdpr->avg_bit_rate); + mdpr->max_packet_size=BE_32(&mdpr->max_packet_size); + mdpr->avg_packet_size=BE_32(&mdpr->avg_packet_size); + mdpr->start_time=BE_32(&mdpr->start_time); + mdpr->preroll=BE_32(&mdpr->preroll); + mdpr->duration=BE_32(&mdpr->duration); + mdpr->object_id=BE_32(&mdpr->object_id); + +} + +static void rmff_dump_cont(rmff_cont_t *cont, char *buffer) { + + int p; + + if (!cont) return; + cont->object_id=BE_32(&cont->object_id); + cont->size=BE_32(&cont->size); + cont->object_version=BE_16(&cont->object_version); + + memcpy(buffer, cont, 8); + memcpy(&buffer[8], &cont->object_version, 2); + + cont->title_len=BE_16(&cont->title_len); + memcpy(&buffer[10], &cont->title_len, 2); + cont->title_len=BE_16(&cont->title_len); + memcpy(&buffer[12], cont->title, cont->title_len); + p=12+cont->title_len; + + cont->author_len=BE_16(&cont->author_len); + memcpy(&buffer[p], &cont->author_len, 2); + cont->author_len=BE_16(&cont->author_len); + memcpy(&buffer[p+2], cont->author, cont->author_len); + p+=2+cont->author_len; + + cont->copyright_len=BE_16(&cont->copyright_len); + memcpy(&buffer[p], &cont->copyright_len, 2); + cont->copyright_len=BE_16(&cont->copyright_len); + memcpy(&buffer[p+2], cont->copyright, cont->copyright_len); + p+=2+cont->copyright_len; + + cont->comment_len=BE_16(&cont->comment_len); + memcpy(&buffer[p], &cont->comment_len, 2); + cont->comment_len=BE_16(&cont->comment_len); + memcpy(&buffer[p+2], cont->comment, cont->comment_len); + + cont->size=BE_32(&cont->size); + cont->object_version=BE_16(&cont->object_version); + cont->object_id=BE_32(&cont->object_id); +} + +static void rmff_dump_dataheader(rmff_data_t *data, char *buffer) { + + if (!data) return; + data->object_id=BE_32(&data->object_id); + data->size=BE_32(&data->size); + data->object_version=BE_16(&data->object_version); + data->num_packets=BE_32(&data->num_packets); + data->next_data_header=BE_32(&data->next_data_header); + + memcpy(buffer, data, 8); + memcpy(&buffer[8], &data->object_version, 2); + memcpy(&buffer[10], &data->num_packets, 8); + + data->num_packets=BE_32(&data->num_packets); + data->next_data_header=BE_32(&data->next_data_header); + data->size=BE_32(&data->size); + data->object_version=BE_16(&data->object_version); + data->object_id=BE_32(&data->object_id); +} + +int rmff_dump_header(rmff_header_t *h, char *buffer, int max) { + + int written=0; + rmff_mdpr_t **stream=h->streams; + + rmff_dump_fileheader(h->fileheader, &buffer[written]); + written+=h->fileheader->size; + rmff_dump_prop(h->prop, &buffer[written]); + written+=h->prop->size; + rmff_dump_cont(h->cont, &buffer[written]); + written+=h->cont->size; + if (stream) + { + while(*stream) + { + rmff_dump_mdpr(*stream, &buffer[written]); + written+=(*stream)->size; + stream++; + } + } + + rmff_dump_dataheader(h->data, &buffer[written]); + written+=18; + + return written; +} + +void rmff_dump_pheader(rmff_pheader_t *h, char *data) { + + data[0]=(h->object_version>>8) & 0xff; + data[1]=h->object_version & 0xff; + data[2]=(h->length>>8) & 0xff; + data[3]=h->length & 0xff; + data[4]=(h->stream_number>>8) & 0xff; + data[5]=h->stream_number & 0xff; + data[6]=(h->timestamp>>24) & 0xff; + data[7]=(h->timestamp>>16) & 0xff; + data[8]=(h->timestamp>>8) & 0xff; + data[9]=h->timestamp & 0xff; + data[10]=h->reserved; + data[11]=h->flags; +} + +static rmff_fileheader_t *rmff_scan_fileheader(const char *data) { + + rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); + + fileheader->object_id=BE_32(data); + fileheader->size=BE_32(&data[4]); + fileheader->object_version=BE_16(&data[8]); + if (fileheader->object_version != 0) + { + printf("warning: unknown object version in .RMF: 0x%04x\n", + fileheader->object_version); + } + fileheader->file_version=BE_32(&data[10]); + fileheader->num_headers=BE_32(&data[14]); + + return fileheader; +} + +static rmff_prop_t *rmff_scan_prop(const char *data) { + + rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); + + prop->object_id=BE_32(data); + prop->size=BE_32(&data[4]); + prop->object_version=BE_16(&data[8]); + if (prop->object_version != 0) + { + printf("warning: unknown object version in PROP: 0x%04x\n", + prop->object_version); + } + prop->max_bit_rate=BE_32(&data[10]); + prop->avg_bit_rate=BE_32(&data[14]); + prop->max_packet_size=BE_32(&data[18]); + prop->avg_packet_size=BE_32(&data[22]); + prop->num_packets=BE_32(&data[26]); + prop->duration=BE_32(&data[30]); + prop->preroll=BE_32(&data[34]); + prop->index_offset=BE_32(&data[38]); + prop->data_offset=BE_32(&data[42]); + prop->num_streams=BE_16(&data[46]); + prop->flags=BE_16(&data[48]); + + return prop; +} + +static rmff_mdpr_t *rmff_scan_mdpr(const char *data) { + + rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); + + mdpr->object_id=BE_32(data); + mdpr->size=BE_32(&data[4]); + mdpr->object_version=BE_16(&data[8]); + if (mdpr->object_version != 0) + { + printf("warning: unknown object version in MDPR: 0x%04x\n", + mdpr->object_version); + } + mdpr->stream_number=BE_16(&data[10]); + mdpr->max_bit_rate=BE_32(&data[12]); + mdpr->avg_bit_rate=BE_32(&data[16]); + mdpr->max_packet_size=BE_32(&data[20]); + mdpr->avg_packet_size=BE_32(&data[24]); + mdpr->start_time=BE_32(&data[28]); + mdpr->preroll=BE_32(&data[32]); + mdpr->duration=BE_32(&data[36]); + + mdpr->stream_name_size=data[40]; + mdpr->stream_name=malloc(mdpr->stream_name_size+1); + memcpy(mdpr->stream_name, &data[41], mdpr->stream_name_size); + mdpr->stream_name[mdpr->stream_name_size]=0; + + mdpr->mime_type_size=data[41+mdpr->stream_name_size]; + mdpr->mime_type=malloc(mdpr->mime_type_size+1); + memcpy(mdpr->mime_type, &data[42+mdpr->stream_name_size], mdpr->mime_type_size); + mdpr->mime_type[mdpr->mime_type_size]=0; + + mdpr->type_specific_len=BE_32(&data[42+mdpr->stream_name_size+mdpr->mime_type_size]); + mdpr->type_specific_data=malloc(mdpr->type_specific_len); + memcpy(mdpr->type_specific_data, + &data[46+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len); + + return mdpr; +} + +static rmff_cont_t *rmff_scan_cont(const char *data) { + + rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); + int pos; + + cont->object_id=BE_32(data); + cont->size=BE_32(&data[4]); + cont->object_version=BE_16(&data[8]); + if (cont->object_version != 0) + { + printf("warning: unknown object version in CONT: 0x%04x\n", + cont->object_version); + } + cont->title_len=BE_16(&data[10]); + cont->title=malloc(cont->title_len+1); + memcpy(cont->title, &data[12], cont->title_len); + cont->title[cont->title_len]=0; + pos=cont->title_len+12; + cont->author_len=BE_16(&data[pos]); + cont->author=malloc(cont->author_len+1); + memcpy(cont->author, &data[pos+2], cont->author_len); + cont->author[cont->author_len]=0; + pos=pos+2+cont->author_len; + cont->copyright_len=BE_16(&data[pos]); + cont->copyright=malloc(cont->copyright_len+1); + memcpy(cont->copyright, &data[pos+2], cont->copyright_len); + cont->copyright[cont->copyright_len]=0; + pos=pos+2+cont->copyright_len; + cont->comment_len=BE_16(&data[pos]); + cont->comment=malloc(cont->comment_len+1); + memcpy(cont->comment, &data[pos+2], cont->comment_len); + cont->comment[cont->comment_len]=0; + + return cont; +} + +static rmff_data_t *rmff_scan_dataheader(const char *data) { + + rmff_data_t *dh=malloc(sizeof(rmff_data_t)); + + dh->object_id=BE_32(data); + dh->size=BE_32(&data[4]); + dh->object_version=BE_16(&data[8]); + if (dh->object_version != 0) + { + printf("warning: unknown object version in DATA: 0x%04x\n", + dh->object_version); + } + dh->num_packets=BE_32(&data[10]); + dh->next_data_header=BE_32(&data[14]); + + return dh; +} + +rmff_header_t *rmff_scan_header(const char *data) { + + rmff_header_t *header=malloc(sizeof(rmff_header_t)); + rmff_mdpr_t *mdpr=NULL; + int chunk_size; + uint32_t chunk_type; + const char *ptr=data; + int i; + + header->fileheader=NULL; + header->prop=NULL; + header->cont=NULL; + header->data=NULL; + + chunk_type = BE_32(ptr); + if (chunk_type != RMF_TAG) + { + printf("rmff: not an real media file header (.RMF tag not found).\n"); + free(header); + return NULL; + } + header->fileheader=rmff_scan_fileheader(ptr); + ptr += header->fileheader->size; + + header->streams=malloc(sizeof(rmff_mdpr_t*)*(header->fileheader->num_headers)); + for (i=0; i<header->fileheader->num_headers; i++) { + header->streams[i]=NULL; + } + + for (i=1; i<header->fileheader->num_headers; i++) { + chunk_type = BE_32(ptr); + + if (ptr[0] == 0) + { + printf("rmff: warning: only %d of %d header found.\n", i, header->fileheader->num_headers); + break; + } + + chunk_size=1; + switch (chunk_type) { + case PROP_TAG: + header->prop=rmff_scan_prop(ptr); + chunk_size=header->prop->size; + break; + case MDPR_TAG: + mdpr=rmff_scan_mdpr(ptr); + chunk_size=mdpr->size; + header->streams[mdpr->stream_number]=mdpr; + break; + case CONT_TAG: + header->cont=rmff_scan_cont(ptr); + chunk_size=header->cont->size; + break; + case DATA_TAG: + header->data=rmff_scan_dataheader(ptr); + chunk_size=34; /* hard coded header size */ + break; + default: + printf("unknown chunk\n"); + hexdump(ptr,10); + chunk_size=1; + break; + } + ptr+=chunk_size; + } + + return header; +} + +rmff_header_t *rmff_scan_header_stream(int fd) { + + rmff_header_t *header; + char *buf=xbuffer_init(1024); + int index=0; + uint32_t chunk_type; + uint32_t chunk_size; + + do { + buf = xbuffer_ensure_size(buf, index+8); + recv(fd, buf+index, 8, 0); + chunk_type=BE_32(buf+index); index+=4; + chunk_size=BE_32(buf+index); index+=4; + + switch (chunk_type) { + case DATA_TAG: + chunk_size=18; + case MDPR_TAG: + case CONT_TAG: + case RMF_TAG: + case PROP_TAG: + buf = xbuffer_ensure_size(buf, index+chunk_size-8); + recv(fd, buf+index, (chunk_size-8), 0); + index+=(chunk_size-8); + break; + default: + printf("rmff_scan_header_stream: unknown chunk"); + hexdump(buf+index-8, 8); + chunk_type=DATA_TAG; + } + } while (chunk_type != DATA_TAG); + + header = rmff_scan_header(buf); + + xbuffer_free(buf); + + return header; +} + +void rmff_scan_pheader(rmff_pheader_t *h, char *data) { + + h->object_version=BE_16(data); + h->length=BE_16(data+2); + h->stream_number=BE_16(data+4); + h->timestamp=BE_32(data+6); + h->reserved=(uint8_t)data[10]; + h->flags=(uint8_t)data[11]; +} + +rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers) { + + rmff_fileheader_t *fileheader=malloc(sizeof(rmff_fileheader_t)); + + fileheader->object_id=RMF_TAG; + fileheader->size=18; + fileheader->object_version=0; + fileheader->file_version=0; + fileheader->num_headers=num_headers; + + return fileheader; +} + +rmff_prop_t *rmff_new_prop ( + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t num_packets, + uint32_t duration, + uint32_t preroll, + uint32_t index_offset, + uint32_t data_offset, + uint16_t num_streams, + uint16_t flags ) { + + rmff_prop_t *prop=malloc(sizeof(rmff_prop_t)); + + prop->object_id=PROP_TAG; + prop->size=50; + prop->object_version=0; + + prop->max_bit_rate=max_bit_rate; + prop->avg_bit_rate=avg_bit_rate; + prop->max_packet_size=max_packet_size; + prop->avg_packet_size=avg_packet_size; + prop->num_packets=num_packets; + prop->duration=duration; + prop->preroll=preroll; + prop->index_offset=index_offset; + prop->data_offset=data_offset; + prop->num_streams=num_streams; + prop->flags=flags; + + return prop; +} + +rmff_mdpr_t *rmff_new_mdpr( + uint16_t stream_number, + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t start_time, + uint32_t preroll, + uint32_t duration, + const char *stream_name, + const char *mime_type, + uint32_t type_specific_len, + const char *type_specific_data ) { + + rmff_mdpr_t *mdpr=malloc(sizeof(rmff_mdpr_t)); + + mdpr->object_id=MDPR_TAG; + mdpr->object_version=0; + + mdpr->stream_number=stream_number; + mdpr->max_bit_rate=max_bit_rate; + mdpr->avg_bit_rate=avg_bit_rate; + mdpr->max_packet_size=max_packet_size; + mdpr->avg_packet_size=avg_packet_size; + mdpr->start_time=start_time; + mdpr->preroll=preroll; + mdpr->duration=duration; + mdpr->stream_name_size=0; + if (stream_name) { + mdpr->stream_name=strdup(stream_name); + mdpr->stream_name_size=strlen(stream_name); + } + mdpr->mime_type_size=0; + if (mime_type) { + mdpr->mime_type=strdup(mime_type); + mdpr->mime_type_size=strlen(mime_type); + } + mdpr->type_specific_len=type_specific_len; + mdpr->type_specific_data=malloc(type_specific_len); + memcpy(mdpr->type_specific_data,type_specific_data,type_specific_len); + mdpr->mlti_data=NULL; + + mdpr->size=mdpr->stream_name_size+mdpr->mime_type_size+mdpr->type_specific_len+46; + + return mdpr; +} + +rmff_cont_t *rmff_new_cont(const char *title, const char *author, const char *copyright, const char *comment) { + + rmff_cont_t *cont=malloc(sizeof(rmff_cont_t)); + + cont->object_id=CONT_TAG; + cont->object_version=0; + + cont->title=NULL; + cont->author=NULL; + cont->copyright=NULL; + cont->comment=NULL; + + cont->title_len=0; + cont->author_len=0; + cont->copyright_len=0; + cont->comment_len=0; + + if (title) { + cont->title_len=strlen(title); + cont->title=strdup(title); + } + if (author) { + cont->author_len=strlen(author); + cont->author=strdup(author); + } + if (copyright) { + cont->copyright_len=strlen(copyright); + cont->copyright=strdup(copyright); + } + if (comment) { + cont->comment_len=strlen(comment); + cont->comment=strdup(comment); + } + cont->size=cont->title_len+cont->author_len+cont->copyright_len+cont->comment_len+18; + + return cont; +} + +rmff_data_t *rmff_new_dataheader(uint32_t num_packets, uint32_t next_data_header) { + + rmff_data_t *data=malloc(sizeof(rmff_data_t)); + + data->object_id=DATA_TAG; + data->size=18; + data->object_version=0; + data->num_packets=num_packets; + data->next_data_header=next_data_header; + + return data; +} + +void rmff_print_header(rmff_header_t *h) { + + rmff_mdpr_t **stream; + + if(!h) { + printf("rmff_print_header: NULL given\n"); + return; + } + if(h->fileheader) + { + printf("\nFILE:\n"); + printf("file version : %d\n", h->fileheader->file_version); + printf("number of headers : %d\n", h->fileheader->num_headers); + } + if(h->cont) + { + printf("\nCONTENT:\n"); + printf("title : %s\n", h->cont->title); + printf("author : %s\n", h->cont->author); + printf("copyright : %s\n", h->cont->copyright); + printf("comment : %s\n", h->cont->comment); + } + if(h->prop) + { + printf("\nSTREAM PROPERTIES:\n"); + printf("bit rate (max/avg) : %i/%i\n", h->prop->max_bit_rate, h->prop->avg_bit_rate); + printf("packet size (max/avg) : %i/%i bytes\n", h->prop->max_packet_size, h->prop->avg_packet_size); + printf("packets : %i\n", h->prop->num_packets); + printf("duration : %i ms\n", h->prop->duration); + printf("pre-buffer : %i ms\n", h->prop->preroll); + printf("index offset : %i bytes\n", h->prop->index_offset); + printf("data offset : %i bytes\n", h->prop->data_offset); + printf("media streams : %i\n", h->prop->num_streams); + printf("flags : "); + if (h->prop->flags & PN_SAVE_ENABLED) printf("save_enabled "); + if (h->prop->flags & PN_PERFECT_PLAY_ENABLED) printf("perfect_play_enabled "); + if (h->prop->flags & PN_LIVE_BROADCAST) printf("live_broadcast "); + printf("\n"); + } + stream=h->streams; + if(stream) + { + while (*stream) + { + printf("\nSTREAM %i:\n", (*stream)->stream_number); + printf("stream name [mime type] : %s [%s]\n", (*stream)->stream_name, (*stream)->mime_type); + printf("bit rate (max/avg) : %i/%i\n", (*stream)->max_bit_rate, (*stream)->avg_bit_rate); + printf("packet size (max/avg) : %i/%i bytes\n", (*stream)->max_packet_size, (*stream)->avg_packet_size); + printf("start time : %i\n", (*stream)->start_time); + printf("pre-buffer : %i ms\n", (*stream)->preroll); + printf("duration : %i ms\n", (*stream)->duration); + printf("type specific data:\n"); + hexdump((*stream)->type_specific_data, (*stream)->type_specific_len); + stream++; + } + } + if(h->data) + { + printf("\nDATA:\n"); + printf("size : %i\n", h->data->size); + printf("packets : %i\n", h->data->num_packets); + printf("next DATA : 0x%08x\n", h->data->next_data_header); + } +} + +void rmff_fix_header(rmff_header_t *h) { + + int num_headers=0; + int header_size=0; + rmff_mdpr_t **streams; + int num_streams=0; + + if (!h) { + printf("rmff_fix_header: fatal: no header given.\n"); + return; + } + + if (!h->streams) { + printf("rmff_fix_header: warning: no MDPR chunks\n"); + } else + { + streams=h->streams; + while (*streams) + { + num_streams++; + num_headers++; + header_size+=(*streams)->size; + streams++; + } + } + + if (h->prop) { + if (h->prop->size != 50) + { +#ifdef LOG + printf("rmff_fix_header: correcting prop.size from %i to %i\n", h->prop->size, 50); +#endif + h->prop->size=50; + } + if (h->prop->num_streams != num_streams) + { +#ifdef LOG + printf("rmff_fix_header: correcting prop.num_streams from %i to %i\n", h->prop->num_streams, num_streams); +#endif + h->prop->num_streams=num_streams; + } + num_headers++; + header_size+=50; + } else + printf("rmff_fix_header: warning: no PROP chunk.\n"); + + if (h->cont) { + num_headers++; + header_size+=h->cont->size; + } else + printf("rmff_fix_header: warning: no CONT chunk.\n"); + + if (!h->data) { +#ifdef LOG + printf("rmff_fix_header: no DATA chunk, creating one\n"); +#endif + h->data=malloc(sizeof(rmff_data_t)); + h->data->object_id=DATA_TAG; + h->data->object_version=0; + h->data->size=34; + h->data->num_packets=0; + h->data->next_data_header=0; + } + num_headers++; + + + if (!h->fileheader) { +#ifdef LOG + printf("rmff_fix_header: no fileheader, creating one"); +#endif + h->fileheader=malloc(sizeof(rmff_fileheader_t)); + h->fileheader->object_id=RMF_TAG; + h->fileheader->size=34; + h->fileheader->object_version=0; + h->fileheader->file_version=0; + h->fileheader->num_headers=num_headers+1; + } + header_size+=h->fileheader->size; + num_headers++; + + if(h->fileheader->num_headers != num_headers) { +#ifdef LOG + printf("rmff_fix_header: setting num_headers from %i to %i\n", h->fileheader->num_headers, num_headers); +#endif + h->fileheader->num_headers=num_headers; + } + + if(h->prop) { + if (h->prop->data_offset != header_size) { +#ifdef LOG + printf("rmff_fix_header: setting prop.data_offset from %i to %i\n", h->prop->data_offset, header_size); +#endif + h->prop->data_offset=header_size; + } + if (h->prop->num_packets == 0) { + int p=(int)(h->prop->avg_bit_rate/8.0*(h->prop->duration/1000.0)/h->prop->avg_packet_size); +#ifdef LOG + printf("rmff_fix_header: assuming prop.num_packets=%i\n", p); +#endif + h->prop->num_packets=p; + } + if (h->data->num_packets == 0) { +#ifdef LOG + printf("rmff_fix_header: assuming data.num_packets=%i\n", h->prop->num_packets); +#endif + h->data->num_packets=h->prop->num_packets; + } + +#ifdef LOG + printf("rmff_fix_header: assuming data.size=%i\n", h->prop->num_packets*h->prop->avg_packet_size); +#endif + h->data->size=h->prop->num_packets*h->prop->avg_packet_size; + } +} + +int rmff_get_header_size(rmff_header_t *h) { + + if (!h) return 0; + if (!h->prop) return -1; + + return h->prop->data_offset+18; + +} + +void rmff_free_header(rmff_header_t *h) { + + if (!h) return; + + if (h->fileheader) free(h->fileheader); + if (h->prop) free(h->prop); + if (h->data) free(h->data); + if (h->cont) + { + free(h->cont->title); + free(h->cont->author); + free(h->cont->copyright); + free(h->cont->comment); + free(h->cont); + } + if (h->streams) + { + rmff_mdpr_t **s=h->streams; + + while(*s) { + free((*s)->stream_name); + free((*s)->mime_type); + free((*s)->type_specific_data); + free(*s); + s++; + } + free(h->streams); + } + free(h); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/rmff.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,270 @@ +/* + * This file was ported to MPlayer from xine CVS rmff.h,v 1.3 2003/02/10 22:11:10 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * some functions for real media file headers + * adopted from joschkas real tools + */ + +#include <sys/types.h> +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#else +#include <winsock2.h> +#endif +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + + +#ifndef HAVE_RMFF_H +#define HAVE_RMFF_H + + +#define RMFF_HEADER_SIZE 0x12 + +#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ + (((long)(unsigned char)(ch3) ) | \ + ( (long)(unsigned char)(ch2) << 8 ) | \ + ( (long)(unsigned char)(ch1) << 16 ) | \ + ( (long)(unsigned char)(ch0) << 24 ) ) + + +#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') +#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') +#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') +#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') +#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') +#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') +#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) + +#define MLTI_TAG FOURCC_TAG('M', 'L', 'T', 'I') + +/* prop flags */ +#define PN_SAVE_ENABLED 0x01 +#define PN_PERFECT_PLAY_ENABLED 0x02 +#define PN_LIVE_BROADCAST 0x04 + +/* + * rm header data structs + */ + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t file_version; + uint32_t num_headers; +} rmff_fileheader_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t max_bit_rate; + uint32_t avg_bit_rate; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t num_packets; + uint32_t duration; + uint32_t preroll; + uint32_t index_offset; + uint32_t data_offset; + uint16_t num_streams; + uint16_t flags; + +} rmff_prop_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint16_t stream_number; + uint32_t max_bit_rate; + uint32_t avg_bit_rate; + uint32_t max_packet_size; + uint32_t avg_packet_size; + uint32_t start_time; + uint32_t preroll; + uint32_t duration; + uint8_t stream_name_size; + char *stream_name; + uint8_t mime_type_size; + char *mime_type; + uint32_t type_specific_len; + char *type_specific_data; + + int mlti_data_size; + char *mlti_data; + +} rmff_mdpr_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint16_t title_len; + char *title; + uint16_t author_len; + char *author; + uint16_t copyright_len; + char *copyright; + uint16_t comment_len; + char *comment; + +} rmff_cont_t; + +typedef struct { + + uint32_t object_id; + uint32_t size; + uint16_t object_version; + + uint32_t num_packets; + uint32_t next_data_header; /* rarely used */ +} rmff_data_t; + +typedef struct { + + rmff_fileheader_t *fileheader; + rmff_prop_t *prop; + rmff_mdpr_t **streams; + rmff_cont_t *cont; + rmff_data_t *data; +} rmff_header_t; + +typedef struct { + + uint16_t object_version; + + uint16_t length; + uint16_t stream_number; + uint32_t timestamp; + uint8_t reserved; + uint8_t flags; + +} rmff_pheader_t; + +/* + * constructors for header structs + */ + +rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers); + +rmff_prop_t *rmff_new_prop ( + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t num_packets, + uint32_t duration, + uint32_t preroll, + uint32_t index_offset, + uint32_t data_offset, + uint16_t num_streams, + uint16_t flags ); + +rmff_mdpr_t *rmff_new_mdpr( + uint16_t stream_number, + uint32_t max_bit_rate, + uint32_t avg_bit_rate, + uint32_t max_packet_size, + uint32_t avg_packet_size, + uint32_t start_time, + uint32_t preroll, + uint32_t duration, + const char *stream_name, + const char *mime_type, + uint32_t type_specific_len, + const char *type_specific_data ); + +rmff_cont_t *rmff_new_cont( + const char *title, + const char *author, + const char *copyright, + const char *comment); + +rmff_data_t *rmff_new_dataheader( + uint32_t num_packets, uint32_t next_data_header); + +/* + * reads header infos from data and returns a newly allocated header struct + */ +rmff_header_t *rmff_scan_header(const char *data); + +/* + * scans a data packet header. Notice, that this function does not allocate + * the header struct itself. + */ +void rmff_scan_pheader(rmff_pheader_t *h, char *data); + +/* + * reads header infos from stream and returns a newly allocated header struct + */ +rmff_header_t *rmff_scan_header_stream(int fd); + +/* + * prints header information in human readible form to stdout + */ +void rmff_print_header(rmff_header_t *h); + +/* + * does some checks and fixes header if possible + */ +void rmff_fix_header(rmff_header_t *h); + +/* + * returns the size of the header (incl. first data-header) + */ +int rmff_get_header_size(rmff_header_t *h); + +/* + * dumps the header <h> to <buffer>. <max> is the size of <buffer> + */ +int rmff_dump_header(rmff_header_t *h, char *buffer, int max); + +/* + * dumps a packet header + */ +void rmff_dump_pheader(rmff_pheader_t *h, char *data); + +/* + * frees a header struct + */ +void rmff_free_header(rmff_header_t *h); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/sdpplin.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,366 @@ +/* + * This file was ported to MPlayer from xine CVS sdpplin.c,v 1.1 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * sdp/sdpplin parser. + * + */ + +#include "config.h" +#include "../librtsp/rtsp.h" +#include "sdpplin.h" +#include "xbuffer.h" +#include "mp_msg.h" + +/* +#define LOG +*/ + +/* + * Decodes base64 strings (based upon b64 package) + */ + +static char *b64_decode(const char *in, char *out, int *size) +{ + char dtable[256]; /* Encode / decode table */ + int i,j,k; + + for (i = 0; i < 255; i++) { + dtable[i] = 0x80; + } + for (i = 'A'; i <= 'Z'; i++) { + dtable[i] = 0 + (i - 'A'); + } + for (i = 'a'; i <= 'z'; i++) { + dtable[i] = 26 + (i - 'a'); + } + for (i = '0'; i <= '9'; i++) { + dtable[i] = 52 + (i - '0'); + } + dtable['+'] = 62; + dtable['/'] = 63; + dtable['='] = 0; + + k=0; + + /*CONSTANTCONDITION*/ + for (j=0; j<strlen(in); j+=4) + { + char a[4], b[4]; + + for (i = 0; i < 4; i++) { + int c = in[i+j]; + + if (dtable[c] & 0x80) { + printf("Illegal character '%c' in input.\n", c); +// exit(1); + return NULL; + } + a[i] = (char) c; + b[i] = (char) dtable[c]; + } + out = xbuffer_ensure_size(out, k+4); + out[k++] = (b[0] << 2) | (b[1] >> 4); + out[k++] = (b[1] << 4) | (b[2] >> 2); + out[k++] = (b[2] << 6) | b[3]; + i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); + if (i < 3) { + out[k]=0; + *size=k; + return out; + } + } + out[k]=0; + *size=k; + return out; +} + +static char *nl(char *data) { + + char *nlptr = (data) ? strchr(data,'\n') : NULL; + return (nlptr) ? nlptr + 1 : NULL; +} + +static int filter(const char *in, const char *filter, char **out) { + + int flen=strlen(filter); + int len; + + if (!in) + return 0; + + len = (strchr(in,'\n')) ? strchr(in,'\n')-in : strlen(in); + + if (!strncmp(in,filter,flen)) + { + if(in[flen]=='"') flen++; + if(in[len-1]==13) len--; + if(in[len-1]=='"') len--; + *out = xbuffer_copyin(*out, 0, in+flen, len-flen+1); + (*out)[len-flen]=0; + + return len-flen; + } + + return 0; +} +static sdpplin_stream_t *sdpplin_parse_stream(char **data) { + + sdpplin_stream_t *desc=calloc(1,sizeof(sdpplin_stream_t)); + char *buf=xbuffer_init(32); + char *decoded=xbuffer_init(32); + int handled; + int got_mimetype; + + if (filter(*data, "m=", &buf)) { + desc->id = strdup(buf); + } else + { + printf("sdpplin: no m= found.\n"); + free(desc); + xbuffer_free(buf); + return NULL; + } + *data=nl(*data); + + got_mimetype = 0; + + while (*data && **data && *data[0]!='m') { +#ifdef LOG + { + int len=strchr(*data,'\n')-(*data); + buf = xbuffer_copyin(buf, 0, *data, len+1); + buf[len]=0; + printf("libreal: sdpplin_stream: '%s'\n", buf); + } +#endif + + handled=0; + + if(filter(*data,"a=control:streamid=",&buf)) { + desc->stream_id=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=MaxBitRate:integer;",&buf)) { + desc->max_bit_rate=atoi(buf); + if (!desc->avg_bit_rate) + desc->avg_bit_rate=desc->max_bit_rate; + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=MaxPacketSize:integer;",&buf)) { + desc->max_packet_size=atoi(buf); + if (!desc->avg_packet_size) + desc->avg_packet_size=desc->max_packet_size; + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=StartTime:integer;",&buf)) { + desc->start_time=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=Preroll:integer;",&buf)) { + desc->preroll=atoi(buf); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=length:npt=",&buf)) { + desc->duration=(uint32_t)(atof(buf)*1000); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=StreamName:string;",&buf)) { + desc->stream_name=strdup(buf); + desc->stream_name_size=strlen(desc->stream_name); + handled=1; + *data=nl(*data); + } + + if(filter(*data,"a=mimetype:string;",&buf)) { + desc->mime_type=strdup(buf); + desc->mime_type_size=strlen(desc->mime_type); + handled=1; + got_mimetype = 1; + *data=nl(*data); + } + + if(filter(*data,"a=OpaqueData:buffer;",&buf)) { + decoded = b64_decode(buf, decoded, &(desc->mlti_data_size)); + desc->mlti_data=malloc(desc->mlti_data_size); + memcpy(desc->mlti_data, decoded, desc->mlti_data_size); + handled=1; + *data=nl(*data); +#ifdef LOG + printf("mlti_data_size: %i\n", desc->mlti_data_size); +#endif + } + + if(filter(*data,"a=ASMRuleBook:string;",&buf)) { + desc->asm_rule_book=strdup(buf); + handled=1; + *data=nl(*data); + } + + if(!handled) { +#ifdef LOG + int len=strchr(*data,'\n')-(*data); + buf = xbuffer_copyin(buf, 0, *data, len+1); + buf[len]=0; + printf("libreal: sdpplin_stream: not handled: '%s'\n", buf); +#endif + *data=nl(*data); + } + } + + if (!got_mimetype) { + mp_msg(MSGT_OPEN, MSGL_V, "libreal: sdpplin_stream: no mimetype\n"); + desc->mime_type = strdup("audio/x-pn-realaudio"); + desc->mime_type_size = strlen(desc->mime_type); + if (desc->stream_id) + mp_msg(MSGT_OPEN, MSGL_WARN, "libreal: sdpplin_stream: implicit mimetype for stream_id != 0, weird.\n"); + } + + xbuffer_free(buf); + xbuffer_free(decoded); + + return desc; +} + +sdpplin_t *sdpplin_parse(char *data) { + + sdpplin_t *desc=calloc(1,sizeof(sdpplin_t)); + char *buf=xbuffer_init(32); + char *decoded=xbuffer_init(32); + int handled; + int len; + + while (data && *data) { +#ifdef LOG + { + int len=strchr(data,'\n')-(data); + buf = xbuffer_copyin(buf, 0, data, len+1); + buf[len]=0; + printf("libreal: sdpplin: '%s'\n", buf); + } +#endif + + handled=0; + + if (filter(data, "m=", &buf)) { + sdpplin_stream_t *stream=sdpplin_parse_stream(&data); +#ifdef LOG + printf("got data for stream id %u\n", stream->stream_id); +#endif + if (desc->stream && (stream->stream_id >= 0) && (stream->stream_id < desc->stream_count)) + desc->stream[stream->stream_id]=stream; + else if (desc->stream) + { + mp_msg(MSGT_OPEN, MSGL_ERR, "sdpplin: bad stream_id %d (must be >= 0, < %d). Broken sdp?\n", + stream->stream_id, desc->stream_count); + free(stream); + } else { + mp_msg(MSGT_OPEN, MSGL_V, "sdpplin: got 'm=', but 'a=StreamCount' is still unknown.\n"); + if (stream->stream_id == 0) { + desc->stream_count=1; + desc->stream=malloc(sizeof(sdpplin_stream_t*)); + desc->stream[0]=stream; + } else { + mp_msg(MSGT_OPEN, MSGL_ERR, "sdpplin: got 'm=', but 'a=StreamCount' is still unknown and stream_id != 0. Broken sdp?\n"); + free(stream); + } + } + continue; + } + + if(filter(data,"a=Title:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->title=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Author:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->author=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Copyright:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->copyright=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Abstract:buffer;",&buf)) { + decoded=b64_decode(buf, decoded, &len); + desc->abstract=strdup(decoded); + handled=1; + data=nl(data); + } + + if(filter(data,"a=StreamCount:integer;",&buf)) { + desc->stream_count=(unsigned int)atoi(buf); + desc->stream=malloc(sizeof(sdpplin_stream_t*)*desc->stream_count); + handled=1; + data=nl(data); + } + + if(filter(data,"a=Flags:integer;",&buf)) { + desc->flags=atoi(buf); + handled=1; + data=nl(data); + } + + if(!handled) { +#ifdef LOG + int len=strchr(data,'\n')-data; + buf = xbuffer_copyin(buf, 0, data, len+1); + buf[len]=0; + printf("libreal: sdpplin: not handled: '%s'\n", buf); +#endif + data=nl(data); + } + } + + xbuffer_free(buf); + xbuffer_free(decoded); + + return desc; +} + +void sdpplin_free(sdpplin_t *description) { + + /* TODO: free strings */ + free(description); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/sdpplin.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,109 @@ +/* + * This file was ported to MPlayer from xine CVS sdpplin.h,v 1.1 2002/12/24 01:30:22 + */ + +/* + * Copyright (C) 2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU 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 + * + * + * sdp/sdpplin parser. + * + */ + +#ifndef HAVE_SDPPLIN_H +#define HAVE_SDPPLIN_H + +#include "rmff.h" +#include "../librtsp/rtsp.h" + +typedef struct { + + char *id; + char *bandwidth; + + int stream_id; + char *range; + char *length; + char *rtpmap; + char *mimetype; + int min_switch_overlap; + int start_time; + int end_one_rule_end_all; + int avg_bit_rate; + int max_bit_rate; + int avg_packet_size; + int max_packet_size; + int end_time; + int seek_greater_on_switch; + int preroll; + + int duration; + char *stream_name; + int stream_name_size; + char *mime_type; + int mime_type_size; + char *mlti_data; + int mlti_data_size; + int rmff_flags_length; + char *rmff_flags; + int asm_rule_book_length; + char *asm_rule_book; + +} sdpplin_stream_t; + +typedef struct { + + int sdp_version, sdpplin_version; + char *owner; + char *session_name; + char *session_info; + char *uri; + char *email; + char *phone; + char *connection; + char *bandwidth; + + int flags; + int is_real_data_type; + int stream_count; + char *title; + char *author; + char *copyright; + char *keywords; + int asm_rule_book_length; + char *asm_rule_book; + char *abstract; + char *range; + int avg_bit_rate; + int max_bit_rate; + int avg_packet_size; + int max_packet_size; + int preroll; + int duration; + + sdpplin_stream_t **stream; + +} sdpplin_t; + +sdpplin_t *sdpplin_parse(char *data); + +void sdpplin_free(sdpplin_t *description); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/xbuffer.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,102 @@ +/* + * xbuffer code + * + * Includes a minimalistic replacement for xine_buffer functions used in + * Real streaming code. Only function needed by this code are implemented. + * + * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project + * + * WARNING: do not mix original xine_buffer functions with this code! + * xbuffers behave like xine_buffers, but are not byte-compatible with them. + * You must take care of pointers returned by xbuffers functions (no macro to + * do it automatically) + * + */ + +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include "xbuffer.h" + + +typedef struct { + uint32_t size; + uint32_t chunk_size; +} xbuffer_header_t; + +#define XBUFFER_HEADER_SIZE sizeof (xbuffer_header_t) + + + +void *xbuffer_init(int chunk_size) { + uint8_t *data=calloc(1,chunk_size+XBUFFER_HEADER_SIZE); + + xbuffer_header_t *header=(xbuffer_header_t*)data; + + header->size=chunk_size; + header->chunk_size=chunk_size; + + return data+XBUFFER_HEADER_SIZE; +} + + + +void *xbuffer_free(void *buf) { + if (!buf) { + return NULL; + } + + free(((uint8_t*)buf)-XBUFFER_HEADER_SIZE); + + return NULL; +} + + + +void *xbuffer_copyin(void *buf, int index, const void *data, int len) { + if (!buf || !data) { + return NULL; + } + + buf = xbuffer_ensure_size(buf, index+len); + memcpy(((uint8_t*)buf)+index, data, len); + + return buf; +} + + + +void *xbuffer_ensure_size(void *buf, int size) { + xbuffer_header_t *xbuf; + int new_size; + + if (!buf) { + return 0; + } + + xbuf = ((xbuffer_header_t*)(((uint8_t*)buf)-XBUFFER_HEADER_SIZE)); + + if (xbuf->size < size) { + new_size = size + xbuf->chunk_size - (size % xbuf->chunk_size); + xbuf->size = new_size; + buf = ((uint8_t*)realloc(((uint8_t*)buf)-XBUFFER_HEADER_SIZE, + new_size+XBUFFER_HEADER_SIZE)) + XBUFFER_HEADER_SIZE; + } + + return buf; +} + + + +void *xbuffer_strcat(void *buf, char *data) { + + if (!buf || !data) { + return NULL; + } + + buf = xbuffer_ensure_size(buf, strlen(buf)+strlen(data)+1); + + strcat(buf, data); + + return buf; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/realrtsp/xbuffer.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,26 @@ +/* + * xbuffer code + * + * Includes a minimalistic replacement for xine_buffer functions used in + * Real streaming code. Only function needed by this code are implemented. + * + * Most code comes from xine_buffer.c Copyright (C) 2002 the xine project + * + * WARNING: do not mix original xine_buffer functions with this code! + * xbuffers behave like xine_buffers, but are not byte-compatible with them. + * You must take care of pointers returned by xbuffers functions (no macro to + * do it automatically) + * + */ + + +#ifndef _XCL_H_ +#define _XCL_H_ + +void *xbuffer_init(int chunk_size); +void *xbuffer_free(void *buf); +void *xbuffer_copyin(void *buf, int index, const void *data, int len); +void *xbuffer_ensure_size(void *buf, int size); +void *xbuffer_strcat(void *buf, char *data); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/rtp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,434 @@ +/* Imported from the dvbstream-0.2 project + * + * Modified for use with MPlayer, for details see the changelog at + * http://svn.mplayerhq.hu/mplayer/trunk/ + * $Id$ + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <ctype.h> +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#define closesocket close +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#endif +#include <errno.h> +#include "stream.h" + +/* MPEG-2 TS RTP stack */ + +#define DEBUG 1 +#include "rtp.h" + +extern int network_bandwidth; + + +#define DEBUG 1 +#include "../mp_msg.h" +#include "rtp.h" + +// RTP reorder routines +// Also handling of repeated UDP packets (a bug of ExtremeNetworks switches firmware) +// rtpreord procedures +// write rtp packets in cache +// get rtp packets reordered + +#define MAXRTPPACKETSIN 32 // The number of max packets being reordered + +struct rtpbuffer +{ + unsigned char data[MAXRTPPACKETSIN][STREAM_BUFFER_SIZE]; + unsigned short seq[MAXRTPPACKETSIN]; + unsigned short len[MAXRTPPACKETSIN]; + unsigned short first; +}; +static struct rtpbuffer rtpbuf; + +// RTP Reordering functions +// Algorithm works as follows: +// If next packet is in sequence just copy it to buffer +// Otherwise copy it in cache according to its sequence number +// Cache is a circular array where "rtpbuf.first" points to next sequence slot +// and keeps track of expected sequence + +// Initialize rtp cache +static void rtp_cache_reset(unsigned short seq) +{ + int i; + + rtpbuf.first = 0; + rtpbuf.seq[0] = ++seq; + + for (i=0; i<MAXRTPPACKETSIN; i++) { + rtpbuf.len[i] = 0; + } +} + +// Write in a cache the rtp packet in right rtp sequence order +static int rtp_cache(int fd, char *buffer, int length) +{ + struct rtpheader rh; + int newseq; + char *data; + unsigned short seq; + static int is_first = 1; + + getrtp2(fd, &rh, &data, &length); + if(!length) + return 0; + seq = rh.b.sequence; + + newseq = seq - rtpbuf.seq[rtpbuf.first]; + + if ((newseq == 0) || is_first) + { + is_first = 0; + + //mp_msg(MSGT_NETWORK, MSGL_DBG4, "RTP (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); + rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN; + rtpbuf.seq[rtpbuf.first] = ++seq; + goto feed; + } + + if (newseq > MAXRTPPACKETSIN) + { + mp_msg(MSGT_NETWORK, MSGL_DBG2, "Overrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); + rtp_cache_reset(seq); + goto feed; + } + + if (newseq < 0) + { + int i; + + // Is it a stray packet re-sent to network? + for (i=0; i<MAXRTPPACKETSIN; i++) { + if (rtpbuf.seq[i] == seq) { + mp_msg(MSGT_NETWORK, MSGL_ERR, "Stray packet (seq[%d]=%d seq=%d, newseq=%d found at %d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq, i); + return 0; // Yes, it is! + } + } + // Some heuristic to decide when to drop packet or to restart everything + if (newseq > -(3 * MAXRTPPACKETSIN)) { + mp_msg(MSGT_NETWORK, MSGL_ERR, "Too Old packet (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); + return 0; // Yes, it is! + } + + mp_msg(MSGT_NETWORK, MSGL_ERR, "Underrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); + + rtp_cache_reset(seq); + goto feed; + } + + mp_msg(MSGT_NETWORK, MSGL_DBG4, "Out of Seq (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq); + newseq = ( newseq + rtpbuf.first ) % MAXRTPPACKETSIN; + memcpy (rtpbuf.data[newseq], data, length); + rtpbuf.len[newseq] = length; + rtpbuf.seq[newseq] = seq; + + return 0; + +feed: + memcpy (buffer, data, length); + return length; +} + +// Get next packet in cache +// Look in cache to get first packet in sequence +static int rtp_get_next(int fd, char *buffer, int length) +{ + int i; + unsigned short nextseq; + + // If we have empty buffer we loop to fill it + for (i=0; i < MAXRTPPACKETSIN -3; i++) { + if (rtpbuf.len[rtpbuf.first] != 0) break; + + length = rtp_cache(fd, buffer, length) ; + + // returns on first packet in sequence + if (length > 0) { + //mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp [%d] %hu\n", i, rtpbuf.first); + return length; + } else if (length < 0) break; + + // Only if length == 0 loop continues! + } + + i = rtpbuf.first; + while (rtpbuf.len[i] == 0) { + mp_msg(MSGT_NETWORK, MSGL_ERR, "Lost packet %hu\n", rtpbuf.seq[i]); + i = ( 1 + i ) % MAXRTPPACKETSIN; + if (rtpbuf.first == i) break; + } + rtpbuf.first = i; + + // Copy next non empty packet from cache + mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp from cache [%d] %hu\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first]); + memcpy (buffer, rtpbuf.data[rtpbuf.first], rtpbuf.len[rtpbuf.first]); + length = rtpbuf.len[rtpbuf.first]; // can be zero? + + // Reset fisrt slot and go next in cache + rtpbuf.len[rtpbuf.first] = 0; + nextseq = rtpbuf.seq[rtpbuf.first]; + rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN; + rtpbuf.seq[rtpbuf.first] = nextseq + 1; + + return length; +} + + +// Read next rtp packet using cache +int read_rtp_from_server(int fd, char *buffer, int length) { + // Following test is ASSERT (i.e. uneuseful if code is correct) + if(buffer==NULL || length<STREAM_BUFFER_SIZE) { + mp_msg(MSGT_NETWORK, MSGL_ERR, "RTP buffer invalid; no data return from network\n"); + return 0; + } + + // loop just to skip empty packets + while ((length = rtp_get_next(fd, buffer, length)) == 0) { + mp_msg(MSGT_NETWORK, MSGL_ERR, "Got empty packet from RTP cache!?\n"); + } + + return(length); +} + +// Start listening on a UDP port. If multicast, join the group. +static int rtp_open_socket( URL_t *url ) { + int socket_server_fd, rxsockbufsz; + int err, err_len; + fd_set set; + struct sockaddr_in server_address; + struct ip_mreq mcast; + struct timeval tv; + struct hostent *hp; + + mp_msg(MSGT_NETWORK,MSGL_V,"Listening for traffic on %s:%d ...\n", url->hostname, url->port ); + + socket_server_fd = socket(AF_INET, SOCK_DGRAM, 0); +// fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK ); + if( socket_server_fd==-1 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create socket\n"); + return -1; + } + + if( isalpha(url->hostname[0]) ) { +#ifndef HAVE_WINSOCK2 + hp =(struct hostent*)gethostbyname( url->hostname ); + if( hp==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); + goto err_out; + } + memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr_list[0], hp->h_length ); +#else + server_address.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + } else { +#ifndef HAVE_WINSOCK2 +#ifdef USE_ATON + inet_aton(url->hostname, &server_address.sin_addr); +#else + inet_pton(AF_INET, url->hostname, &server_address.sin_addr); +#endif +#else + server_address.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + } + server_address.sin_family=AF_INET; + server_address.sin_port=htons(url->port); + + if( bind( socket_server_fd, (struct sockaddr*)&server_address, sizeof(server_address) )==-1 ) { +#ifndef HAVE_WINSOCK2 + if( errno!=EINPROGRESS ) { +#else + if( WSAGetLastError() != WSAEINPROGRESS ) { +#endif + mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server\n"); + goto err_out; + } + } + +#ifdef HAVE_WINSOCK2 + if (isalpha(url->hostname[0])) { + hp =(struct hostent*)gethostbyname( url->hostname ); + if( hp==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Counldn't resolve name: %s\n", url->hostname); + goto err_out; + } + memcpy( (void*)&server_address.sin_addr.s_addr, (void*)hp->h_addr, hp->h_length ); + } else { + unsigned int addr = inet_addr(url->hostname); + memcpy( (void*)&server_address.sin_addr, (void*)&addr, sizeof(addr) ); + } +#endif + + // Increase the socket rx buffer size to maximum -- this is UDP + rxsockbufsz = 240 * 1024; + if( setsockopt( socket_server_fd, SOL_SOCKET, SO_RCVBUF, &rxsockbufsz, sizeof(rxsockbufsz))) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't set receive socket buffer size\n"); + } + + if((ntohl(server_address.sin_addr.s_addr) >> 28) == 0xe) { + mcast.imr_multiaddr.s_addr = server_address.sin_addr.s_addr; + //mcast.imr_interface.s_addr = inet_addr("10.1.1.2"); + mcast.imr_interface.s_addr = 0; + if( setsockopt( socket_server_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mcast, sizeof(mcast))) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?)\n"); + goto err_out; + } + } + + tv.tv_sec = 0; + tv.tv_usec = (1 * 1000000); // 1 second timeout + FD_ZERO( &set ); + FD_SET( socket_server_fd, &set ); + err = select(socket_server_fd+1, &set, NULL, NULL, &tv); + if (err < 0) { + mp_msg(MSGT_NETWORK, MSGL_FATAL, "Select failed: %s\n", strerror(errno)); + goto err_out; + } + if (err == 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"Timeout! No data from host %s\n", url->hostname ); + goto err_out; + } + err_len = sizeof( err ); + getsockopt( socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len ); + if( err ) { + mp_msg(MSGT_NETWORK,MSGL_DBG2,"Socket error: %d\n", err ); + goto err_out; + } + return socket_server_fd; + +err_out: + closesocket(socket_server_fd); + return -1; +} + +static int rtp_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *streaming_ctrl ) { + return read_rtp_from_server( fd, buffer, size ); +} + +static int rtp_streaming_start( stream_t *stream, int raw_udp ) { + streaming_ctrl_t *streaming_ctrl; + int fd; + + if( stream==NULL ) return -1; + streaming_ctrl = stream->streaming_ctrl; + fd = stream->fd; + + if( fd<0 ) { + fd = rtp_open_socket( (streaming_ctrl->url) ); + if( fd<0 ) return -1; + stream->fd = fd; + } + + if(raw_udp) + streaming_ctrl->streaming_read = nop_streaming_read; + else + streaming_ctrl->streaming_read = rtp_streaming_read; + streaming_ctrl->streaming_seek = nop_streaming_seek; + streaming_ctrl->prebuffer_size = 64*1024; // 64 KBytes + streaming_ctrl->buffering = 0; + streaming_ctrl->status = streaming_playing_e; + return 0; +} + + +static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) { + static char buf[1600]; + unsigned int intP; + char* charP = (char*) &intP; + int headerSize; + int lengthPacket; + lengthPacket=recv(fd,buf,1590,0); + if (lengthPacket<0) + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: socket read error\n"); + else if (lengthPacket<12) + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: packet too small (%d) to be an rtp frame (>12bytes)\n", lengthPacket); + if(lengthPacket<12) { + *lengthData = 0; + return 0; + } + rh->b.v = (unsigned int) ((buf[0]>>6)&0x03); + rh->b.p = (unsigned int) ((buf[0]>>5)&0x01); + rh->b.x = (unsigned int) ((buf[0]>>4)&0x01); + rh->b.cc = (unsigned int) ((buf[0]>>0)&0x0f); + rh->b.m = (unsigned int) ((buf[1]>>7)&0x01); + rh->b.pt = (unsigned int) ((buf[1]>>0)&0x7f); + intP = 0; + memcpy(charP+2,&buf[2],2); + rh->b.sequence = ntohl(intP); + intP = 0; + memcpy(charP,&buf[4],4); + rh->timestamp = ntohl(intP); + + headerSize = 12 + 4*rh->b.cc; /* in bytes */ + + *lengthData = lengthPacket - headerSize; + *data = (char*) buf + headerSize; + + // mp_msg(MSGT_NETWORK,MSGL_DBG2,"Reading rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",rh->b.v,rh->b.p,rh->b.x,rh->b.cc,rh->b.m,rh->b.pt,rh->b.sequence,rh->timestamp,lengthPacket); + + return(0); +} + + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + URL_t *url; + int udp = 0; + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_RTP, URL: %s\n", stream->url); + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + + if( url->port==0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"You must enter a port number for RTP and UDP streams!\n"); + goto fail; + } + if(!strncmp(stream->url, "udp", 3)) + udp = 1; + + if(rtp_streaming_start(stream, udp) < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp_streaming_start(rtp) failed\n"); + goto fail; + } + + stream->type = STREAMTYPE_STREAM; + fixup_network_stream_cache(stream); + return STREAM_OK; + +fail: + streaming_ctrl_free( stream->streaming_ctrl ); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; +} + + +stream_info_t stream_info_rtp_udp = { + "mpeg rtp and upd streaming", + "rtp and udp", + "Dave Chapman", + "native rtp support", + open_s, + {"rtp", "udp", NULL}, + NULL, + 0 // Urls are an option string +}; + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/rtp.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,38 @@ +/* Imported from the dvbstream project + * + * Modified for use with MPlayer, for details see the changelog at + * http://svn.mplayerhq.hu/mplayer/trunk/ + * $Id$ + */ + +#ifndef _RTP_H +#define _RTP_H + +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <sys/socket.h> +#else +#include <winsock2.h> +#endif + +struct rtpbits { + unsigned int v:2; /* version: 2 */ + unsigned int p:1; /* is there padding appended: 0 */ + unsigned int x:1; /* number of extension headers: 0 */ + unsigned int cc:4; /* number of CSRC identifiers: 0 */ + unsigned int m:1; /* marker: 0 */ + unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */ + unsigned int sequence:16; /* sequence number: random */ +}; + +struct rtpheader { /* in network byte order */ + struct rtpbits b; + int timestamp; /* start: random */ + int ssrc; /* random */ +}; + + +static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData); +int read_rtp_from_server(int fd, char *buffer, int length); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,434 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> +#ifndef __MINGW32__ +#include <sys/ioctl.h> +#include <sys/wait.h> +#endif +#include <fcntl.h> +#include <signal.h> +#include <strings.h> + +#include "config.h" + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#else +#include <winsock2.h> +#endif + +#include "mp_msg.h" +#include "help_mp.h" +#include "osdep/shmem.h" + +#include "stream.h" +#include "demuxer.h" + +#include "m_option.h" +#include "m_struct.h" + + +void cache_uninit(stream_t *s); // defined in cache2.c + +//#include "vcd_read_bincue.h" + +#ifdef HAVE_VCD +extern stream_info_t stream_info_vcd; +#endif +#ifdef HAVE_CDDA +extern stream_info_t stream_info_cdda; +#endif +#ifdef MPLAYER_NETWORK +extern stream_info_t stream_info_netstream; +extern stream_info_t stream_info_pnm; +extern stream_info_t stream_info_asf; +extern stream_info_t stream_info_rtsp; +extern stream_info_t stream_info_rtp_udp; +extern stream_info_t stream_info_http1; +extern stream_info_t stream_info_http2; +#endif +#ifdef HAS_DVBIN_SUPPORT +extern stream_info_t stream_info_dvb; +#endif +#ifdef HAVE_PVR +extern stream_info_t stream_info_pvr; +#endif +#ifdef HAVE_FTP +extern stream_info_t stream_info_ftp; +#endif +#ifdef HAVE_VSTREAM +extern stream_info_t stream_info_vstream; +#endif +#ifdef USE_DVDNAV +extern stream_info_t stream_info_dvdnav; +#endif +#ifdef LIBSMBCLIENT +extern stream_info_t stream_info_smb; +#endif +#ifdef STREAMING_LIVE555 +extern stream_info_t stream_info_sdp; +extern stream_info_t stream_info_rtsp_sip; +#endif + +extern stream_info_t stream_info_cue; +extern stream_info_t stream_info_null; +extern stream_info_t stream_info_file; +#ifdef HAVE_DVD +extern stream_info_t stream_info_dvd; +#endif + +stream_info_t* auto_open_streams[] = { +#ifdef HAVE_VCD + &stream_info_vcd, +#endif +#ifdef HAVE_CDDA + &stream_info_cdda, +#endif +#ifdef MPLAYER_NETWORK + &stream_info_netstream, + &stream_info_http1, + &stream_info_asf, + &stream_info_pnm, + &stream_info_rtsp, +#ifdef STREAMING_LIVE555 + &stream_info_sdp, + &stream_info_rtsp_sip, +#endif + &stream_info_rtp_udp, + &stream_info_http2, +#endif +#ifdef HAS_DVBIN_SUPPORT + &stream_info_dvb, +#endif +#ifdef HAVE_PVR + &stream_info_pvr, +#endif +#ifdef HAVE_FTP + &stream_info_ftp, +#endif +#ifdef HAVE_VSTREAM + &stream_info_vstream, +#endif +#ifdef LIBSMBCLIENT + &stream_info_smb, +#endif + &stream_info_cue, +#ifdef HAVE_DVD + &stream_info_dvd, +#endif +#ifdef USE_DVDNAV + &stream_info_dvdnav, +#endif + + &stream_info_null, + &stream_info_file, + NULL +}; + +stream_t* open_stream_plugin(stream_info_t* sinfo,char* filename,int mode, + char** options, int* file_format, int* ret) { + void* arg = NULL; + stream_t* s; + m_struct_t* desc = (m_struct_t*)sinfo->opts; + + // Parse options + if(desc) { + arg = m_struct_alloc(desc); + if(sinfo->opts_url) { + m_option_t url_opt = + { "stream url", arg , CONF_TYPE_CUSTOM_URL, 0, 0 ,0, sinfo->opts }; + if(m_option_parse(&url_opt,"stream url",filename,arg,M_CONFIG_FILE) < 0) { + mp_msg(MSGT_OPEN,MSGL_ERR, "URL parsing failed on url %s\n",filename); + m_struct_free(desc,arg); + return NULL; + } + } + if(options) { + int i; + for(i = 0 ; options[i] != NULL ; i += 2) { + mp_msg(MSGT_OPEN,MSGL_DBG2, "Set stream arg %s=%s\n", + options[i],options[i+1]); + if(!m_struct_set(desc,arg,options[i],options[i+1])) + mp_msg(MSGT_OPEN,MSGL_WARN, "Failed to set stream option %s=%s\n", + options[i],options[i+1]); + } + } + } + s = new_stream(-2,-2); + s->url=strdup(filename); + s->flags |= mode; + *ret = sinfo->open(s,mode,arg,file_format); + if((*ret) != STREAM_OK) { + free(s->url); + free(s); + return NULL; + } + if(s->type <= -2) + mp_msg(MSGT_OPEN,MSGL_WARN, "Warning streams need a type !!!!\n"); + if(s->flags & STREAM_SEEK && !s->seek) + s->flags &= ~STREAM_SEEK; + if(s->seek && !(s->flags & STREAM_SEEK)) + s->flags |= STREAM_SEEK; + + + mp_msg(MSGT_OPEN,MSGL_V, "STREAM: [%s] %s\n",sinfo->name,filename); + mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Description: %s\n",sinfo->info); + mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Author: %s\n", sinfo->author); + mp_msg(MSGT_OPEN,MSGL_V, "STREAM: Comment: %s\n", sinfo->comment); + + return s; +} + + +stream_t* open_stream_full(char* filename,int mode, char** options, int* file_format) { + int i,j,l,r; + stream_info_t* sinfo; + stream_t* s; + + for(i = 0 ; auto_open_streams[i] ; i++) { + sinfo = auto_open_streams[i]; + if(!sinfo->protocols) { + mp_msg(MSGT_OPEN,MSGL_WARN, "Stream type %s has protocols == NULL, it's a bug\n", sinfo->name); + continue; + } + for(j = 0 ; sinfo->protocols[j] ; j++) { + l = strlen(sinfo->protocols[j]); + // l == 0 => Don't do protocol matching (ie network and filenames) + if((l == 0) || ((strncmp(sinfo->protocols[j],filename,l) == 0) && + (strncmp("://",filename+l,3) == 0))) { + *file_format = DEMUXER_TYPE_UNKNOWN; + s = open_stream_plugin(sinfo,filename,mode,options,file_format,&r); + if(s) return s; + if(r != STREAM_UNSUPORTED) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_FailedToOpen,filename); + return NULL; + } + break; + } + } + } + + mp_msg(MSGT_OPEN,MSGL_ERR, "No stream found to handle url %s\n",filename); + return NULL; +} + +//=================== STREAMER ========================= + +int stream_fill_buffer(stream_t *s){ + int len; + if (/*s->fd == NULL ||*/ s->eof) { s->buf_pos = s->buf_len = 0; return 0; } + switch(s->type){ + case STREAMTYPE_STREAM: +#ifdef MPLAYER_NETWORK + if( s->streaming_ctrl!=NULL ) { + len=s->streaming_ctrl->streaming_read(s->fd,s->buffer,STREAM_BUFFER_SIZE, s->streaming_ctrl);break; + } else { + len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break; + } +#else + len=read(s->fd,s->buffer,STREAM_BUFFER_SIZE);break; +#endif + case STREAMTYPE_DS: + len = demux_read_data((demux_stream_t*)s->priv,s->buffer,STREAM_BUFFER_SIZE); + break; + + + default: + len= s->fill_buffer ? s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE) : 0; + } + if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; } + s->buf_pos=0; + s->buf_len=len; + s->pos+=len; +// printf("[%d]",len);fflush(stdout); + return len; +} + +int stream_seek_long(stream_t *s,off_t pos){ +off_t newpos=0; + +// if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ) printf("seek_long to 0x%X\n",(unsigned int)pos); + + s->buf_pos=s->buf_len=0; + + switch(s->type){ + case STREAMTYPE_STREAM: +#ifdef _LARGEFILE_SOURCE + newpos=pos&(~((long long)STREAM_BUFFER_SIZE-1));break; +#else + newpos=pos&(~(STREAM_BUFFER_SIZE-1));break; +#endif + default: + // Round on sector size + if(s->sector_size) + newpos=(pos/s->sector_size)*s->sector_size; + else { // Otherwise on the buffer size +#ifdef _LARGEFILE_SOURCE + newpos=pos&(~((long long)STREAM_BUFFER_SIZE-1));break; +#else + newpos=pos&(~(STREAM_BUFFER_SIZE-1));break; +#endif + } + break; + } + +if( mp_msg_test(MSGT_STREAM,MSGL_DBG3) ){ + mp_msg(MSGT_STREAM,MSGL_DBG3, "s->pos=%"PRIX64" newpos=%"PRIX64" new_bufpos=%"PRIX64" buflen=%X \n", + (int64_t)s->pos,(int64_t)newpos,(int64_t)pos,s->buf_len); +} + pos-=newpos; + +if(newpos==0 || newpos!=s->pos){ + switch(s->type){ + case STREAMTYPE_STREAM: + //s->pos=newpos; // real seek + // Some streaming protocol allow to seek backward and forward + // A function call that return -1 can tell that the protocol + // doesn't support seeking. +#ifdef MPLAYER_NETWORK + if(s->seek) { // new stream seek is much cleaner than streaming_ctrl one + if(!s->seek(s,newpos)) { + mp_msg(MSGT_STREAM,MSGL_ERR, "Seek failed\n"); + return 0; + } + break; + } + + if( s->streaming_ctrl!=NULL && s->streaming_ctrl->streaming_seek ) { + if( s->streaming_ctrl->streaming_seek( s->fd, pos, s->streaming_ctrl )<0 ) { + mp_msg(MSGT_STREAM,MSGL_INFO,"Stream not seekable!\n"); + return 1; + } + } +#else + if(newpos<s->pos){ + mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n"); + return 1; + } + while(s->pos<newpos){ + if(stream_fill_buffer(s)<=0) break; // EOF + } +#endif + break; + default: + // This should at the beginning as soon as all streams are converted + if(!s->seek) + return 0; + // Now seek + if(!s->seek(s,newpos)) { + mp_msg(MSGT_STREAM,MSGL_ERR, "Seek failed\n"); + return 0; + } + } +// putchar('.');fflush(stdout); +//} else { +// putchar('%');fflush(stdout); +} + +while(stream_fill_buffer(s) > 0 && pos >= 0) { + if(pos<=s->buf_len){ + s->buf_pos=pos; // byte position in sector + return 1; + } + pos -= s->buf_len; +} + +// if(pos==s->buf_len) printf("XXX Seek to last byte of file -> EOF\n"); + + mp_msg(MSGT_STREAM,MSGL_V,"stream_seek: WARNING! Can't seek to 0x%"PRIX64" !\n",(int64_t)(pos+newpos)); + return 0; +} + + +void stream_reset(stream_t *s){ + if(s->eof){ + s->pos=0; //ftell(f); +// s->buf_pos=s->buf_len=0; + s->eof=0; + } + if(s->control) s->control(s,STREAM_CTRL_RESET,NULL); + //stream_seek(s,0); +} + +int stream_control(stream_t *s, int cmd, void *arg){ + if(!s->control) return STREAM_UNSUPORTED; + return s->control(s, cmd, arg); +} + +stream_t* new_memory_stream(unsigned char* data,int len){ + stream_t *s; + + if(len < 0) + return NULL; + s=malloc(sizeof(stream_t)+len); + memset(s,0,sizeof(stream_t)); + s->fd=-1; + s->type=STREAMTYPE_MEMORY; + s->buf_pos=0; s->buf_len=len; + s->start_pos=0; s->end_pos=len; + stream_reset(s); + s->pos=len; + memcpy(s->buffer,data,len); + return s; +} + +stream_t* new_stream(int fd,int type){ + stream_t *s=malloc(sizeof(stream_t)); + if(s==NULL) return NULL; + memset(s,0,sizeof(stream_t)); + +#ifdef HAVE_WINSOCK2 + { + WSADATA wsdata; + int temp = WSAStartup(0x0202, &wsdata); // there might be a better place for this (-> later) + mp_msg(MSGT_STREAM,MSGL_V,"WINSOCK2 init: %i\n", temp); + } +#endif + + s->fd=fd; + s->type=type; + s->buf_pos=s->buf_len=0; + s->start_pos=s->end_pos=0; + s->priv=NULL; + s->url=NULL; + s->cache_pid=0; + stream_reset(s); + return s; +} + +void free_stream(stream_t *s){ +// printf("\n*** free_stream() called ***\n"); +#ifdef USE_STREAM_CACHE + if(s->cache_pid) { + cache_uninit(s); + } +#endif + if(s->close) s->close(s); + if(s->fd>0){ + /* on unix we define closesocket to close + on windows however we have to distinguish between + network socket and file */ + if(s->url && strstr(s->url,"://")) + closesocket(s->fd); + else close(s->fd); + } +#ifdef HAVE_WINSOCK2 + mp_msg(MSGT_STREAM,MSGL_V,"WINSOCK2 uninit\n"); + WSACleanup(); // there might be a better place for this (-> later) +#endif + // Disabled atm, i don't like that. s->priv can be anything after all + // streams should destroy their priv on close + //if(s->priv) free(s->priv); + if(s->url) free(s->url); + free(s); +} + +stream_t* new_ds_stream(demux_stream_t *ds) { + stream_t* s = new_stream(-1,STREAMTYPE_DS); + s->priv = ds; + return s; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,301 @@ +#ifndef __STREAM_H +#define __STREAM_H + +#include "mp_msg.h" +#include <string.h> +#include <inttypes.h> +#include <sys/types.h> + +#define STREAMTYPE_DUMMY -1 // for placeholders, when the actual reading is handled in the demuxer +#define STREAMTYPE_FILE 0 // read from seekable file +#define STREAMTYPE_VCD 1 // raw mode-2 CDROM reading, 2324 bytes/sector +#define STREAMTYPE_STREAM 2 // same as FILE but no seeking (for net/stdin) +#define STREAMTYPE_DVD 3 // libdvdread +#define STREAMTYPE_MEMORY 4 // read data from memory area +#define STREAMTYPE_PLAYLIST 6 // FIXME!!! same as STREAMTYPE_FILE now +#define STREAMTYPE_DS 8 // read from a demuxer stream +#define STREAMTYPE_DVDNAV 9 // we cannot safely "seek" in this... +#define STREAMTYPE_CDDA 10 // raw audio CD reader +#define STREAMTYPE_SMB 11 // smb:// url, using libsmbclient (samba) +#define STREAMTYPE_VCDBINCUE 12 // vcd directly from bin/cue files +#define STREAMTYPE_DVB 13 +#define STREAMTYPE_VSTREAM 14 +#define STREAMTYPE_SDP 15 +#define STREAMTYPE_PVR 16 + +#define STREAM_BUFFER_SIZE 2048 + +#define VCD_SECTOR_SIZE 2352 +#define VCD_SECTOR_OFFS 24 +#define VCD_SECTOR_DATA 2324 + +/// atm it will always use mode == STREAM_READ +/// streams that use the new api should check the mode at open +#define STREAM_READ 0 +#define STREAM_WRITE 1 +/// Seek flags, if not mannualy set and s->seek isn't NULL +/// STREAM_SEEK is automaticly set +#define STREAM_SEEK_BW 2 +#define STREAM_SEEK_FW 4 +#define STREAM_SEEK (STREAM_SEEK_BW|STREAM_SEEK_FW) + +//////////// Open return code +/// This can't open the requested protocol (used by stream wich have a +/// * protocol when they don't know the requested protocol) +#define STREAM_UNSUPORTED -1 +#define STREAM_ERROR 0 +#define STREAM_OK 1 + +#define MAX_STREAM_PROTOCOLS 10 + +#define STREAM_CTRL_RESET 0 +#define STREAM_CTRL_GET_TIME_LENGTH 1 + +#ifdef MPLAYER_NETWORK +#include "network.h" +#endif + +struct stream_st; +typedef struct stream_info_st { + const char *info; + const char *name; + const char *author; + const char *comment; + /// mode isn't used atm (ie always READ) but it shouldn't be ignored + /// opts is at least in it's defaults settings and may have been + /// altered by url parsing if enabled and the options string parsing. + int (*open)(struct stream_st* st, int mode, void* opts, int* file_format); + char* protocols[MAX_STREAM_PROTOCOLS]; + void* opts; + int opts_url; /* If this is 1 we will parse the url as an option string + * too. Otherwise options are only parsed from the + * options string given to open_stream_plugin */ +} stream_info_t; + +typedef struct stream_st { + // Read + int (*fill_buffer)(struct stream_st *s, char* buffer, int max_len); + // Write + int (*write_buffer)(struct stream_st *s, char* buffer, int len); + // Seek + int (*seek)(struct stream_st *s,off_t pos); + // Control + // Will be later used to let streams like dvd and cdda report + // their structure (ie tracks, chapters, etc) + int (*control)(struct stream_st *s,int cmd,void* arg); + // Close + void (*close)(struct stream_st *s); + + int fd; // file descriptor, see man open(2) + int type; // see STREAMTYPE_* + int flags; + int sector_size; // sector size (seek will be aligned on this size if non 0) + unsigned int buf_pos,buf_len; + off_t pos,start_pos,end_pos; + int eof; + unsigned int cache_pid; + void* cache_data; + void* priv; // used for DVD, TV, RTSP etc + char* url; // strdup() of filename/url +#ifdef MPLAYER_NETWORK + streaming_ctrl_t *streaming_ctrl; +#endif + unsigned char buffer[STREAM_BUFFER_SIZE>VCD_SECTOR_SIZE?STREAM_BUFFER_SIZE:VCD_SECTOR_SIZE]; +} stream_t; + +#ifdef USE_STREAM_CACHE +int stream_enable_cache(stream_t *stream,int size,int min,int prefill); +int cache_stream_fill_buffer(stream_t *s); +int cache_stream_seek_long(stream_t *s,off_t pos); +#else +// no cache, define wrappers: +#define cache_stream_fill_buffer(x) stream_fill_buffer(x) +#define cache_stream_seek_long(x,y) stream_seek_long(x,y) +#define stream_enable_cache(x,y,z,w) 1 +#endif +void fixup_network_stream_cache(stream_t *stream); + +inline static int stream_read_char(stream_t *s){ + return (s->buf_pos<s->buf_len)?s->buffer[s->buf_pos++]: + (cache_stream_fill_buffer(s)?s->buffer[s->buf_pos++]:-256); +// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++]; +// stream_fill_buffer(s); +// if(s->buf_pos<s->buf_len) return s->buffer[s->buf_pos++]; +// return 0; // EOF +} + +inline static unsigned int stream_read_word(stream_t *s){ + int x,y; + x=stream_read_char(s); + y=stream_read_char(s); + return (x<<8)|y; +} + +inline static unsigned int stream_read_dword(stream_t *s){ + unsigned int y; + y=stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + return y; +} + +#define stream_read_fourcc stream_read_dword_le + +inline static unsigned int stream_read_word_le(stream_t *s){ + int x,y; + x=stream_read_char(s); + y=stream_read_char(s); + return (y<<8)|x; +} + +inline static unsigned int stream_read_dword_le(stream_t *s){ + unsigned int y; + y=stream_read_char(s); + y|=stream_read_char(s)<<8; + y|=stream_read_char(s)<<16; + y|=stream_read_char(s)<<24; + return y; +} + +inline static uint64_t stream_read_qword(stream_t *s){ + uint64_t y; + y = stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + return y; +} + +inline static uint64_t stream_read_qword_le(stream_t *s){ + uint64_t y; + y = stream_read_char(s); + y|=stream_read_char(s)<<8; + y|=stream_read_char(s)<<16; + y|=stream_read_char(s)<<24; + y|=(uint64_t)stream_read_char(s)<<32; + y|=(uint64_t)stream_read_char(s)<<40; + y|=(uint64_t)stream_read_char(s)<<48; + y|=(uint64_t)stream_read_char(s)<<56; + return y; +} + +inline static unsigned int stream_read_int24(stream_t *s){ + unsigned int y; + y = stream_read_char(s); + y=(y<<8)|stream_read_char(s); + y=(y<<8)|stream_read_char(s); + return y; +} + +inline static int stream_read(stream_t *s,char* mem,int total){ + int len=total; + while(len>0){ + int x; + x=s->buf_len-s->buf_pos; + if(x==0){ + if(!cache_stream_fill_buffer(s)) return total-len; // EOF + x=s->buf_len-s->buf_pos; + } + if(s->buf_pos>s->buf_len) mp_msg(MSGT_DEMUX, MSGL_WARN, "stream_read: WARNING! s->buf_pos>s->buf_len\n"); + if(x>len) x=len; + memcpy(mem,&s->buffer[s->buf_pos],x); + s->buf_pos+=x; mem+=x; len-=x; + } + return total; +} + +inline static unsigned char* stream_read_line(stream_t *s,unsigned char* mem, int max) { + int len; + unsigned char* end,*ptr = mem;; + do { + len = s->buf_len-s->buf_pos; + // try to fill the buffer + if(len <= 0 && + (!cache_stream_fill_buffer(s) || + (len = s->buf_len-s->buf_pos) <= 0)) break; + end = (unsigned char*) memchr((void*)(s->buffer+s->buf_pos),'\n',len); + if(end) len = end - (s->buffer+s->buf_pos) + 1; + if(len > 0 && max > 1) { + int l = len > max-1 ? max-1 : len; + memcpy(ptr,s->buffer+s->buf_pos,l); + max -= l; + ptr += l; + } + s->buf_pos += len; + } while(!end); + if(s->eof && ptr == mem) return NULL; + if(max > 0) ptr[0] = 0; + return mem; +} + + +inline static int stream_eof(stream_t *s){ + return s->eof; +} + +inline static off_t stream_tell(stream_t *s){ + return s->pos+s->buf_pos-s->buf_len; +} + +inline static int stream_seek(stream_t *s,off_t pos){ + + mp_dbg(MSGT_DEMUX, MSGL_DBG3, "seek to 0x%qX\n",(long long)pos); + + if(pos<s->pos){ + off_t x=pos-(s->pos-s->buf_len); + if(x>=0){ + s->buf_pos=x; +// putchar('*');fflush(stdout); + return 1; + } + } + + return cache_stream_seek_long(s,pos); +} + +inline static int stream_skip(stream_t *s,off_t len){ + if( (len<0 && (s->flags & STREAM_SEEK_BW)) || (len>2*STREAM_BUFFER_SIZE && (s->flags & STREAM_SEEK_FW)) ) { + // negative or big skip! + return stream_seek(s,stream_tell(s)+len); + } + while(len>0){ + int x=s->buf_len-s->buf_pos; + if(x==0){ + if(!cache_stream_fill_buffer(s)) return 0; // EOF + x=s->buf_len-s->buf_pos; + } + if(x>len) x=len; + //memcpy(mem,&s->buf[s->buf_pos],x); + s->buf_pos+=x; len-=x; + } + return 1; +} + +void stream_reset(stream_t *s); +int stream_control(stream_t *s, int cmd, void *arg); +stream_t* new_stream(int fd,int type); +void free_stream(stream_t *s); +stream_t* new_memory_stream(unsigned char* data,int len); +stream_t* open_stream(char* filename,char** options,int* file_format); +stream_t* open_stream_full(char* filename,int mode, char** options, int* file_format); + +extern int dvd_title; +extern int dvd_chapter; +extern int dvd_last_chapter; +extern int dvd_angle; + +extern char * audio_stream; + +typedef struct { + int id; // 0 - 31 mpeg; 128 - 159 ac3; 160 - 191 pcm + int language; + int type; + int channels; +} stream_language_t; + +#endif // __STREAM_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_dvd.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,851 @@ + + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifdef __FreeBSD__ +#include <sys/cdrio.h> +#endif + +#define FIRST_AC3_AID 128 +#define FIRST_DTS_AID 136 +#define FIRST_MPG_AID 0 +#define FIRST_PCM_AID 160 + +#include "stream.h" +#include "m_option.h" +#include "m_struct.h" + +#include "stream_dvd.h" + +/// We keep these 2 for the gui atm, but they will be removed. +extern int dvd_title; +extern int dvd_chapter; +extern int dvd_last_chapter; +extern char* dvd_device; +int dvd_angle=1; + +#ifdef USE_DVDREAD +#define LIBDVDREAD_VERSION(maj,min,micro) ((maj)*10000 + (min)*100 + (micro)) +/* + * Try to autodetect the libdvd-0.9.0 library + * (0.9.0 removed the <dvdread/dvd_udf.h> header, and moved the two defines + * DVD_VIDEO_LB_LEN and MAX_UDF_FILE_NAME_LEN from it to + * <dvdread/dvd_reader.h>) + */ +#ifndef DVDREAD_VERSION +#if defined(DVD_VIDEO_LB_LEN) && defined(MAX_UDF_FILE_NAME_LEN) +#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,9,0) +#else +#define DVDREAD_VERSION LIBDVDREAD_VERSION(0,8,0) +#endif +#endif + +char * dvd_audio_stream_types[8] = { "ac3","unknown","mpeg1","mpeg2ext","lpcm","unknown","dts" }; +char * dvd_audio_stream_channels[6] = { "mono", "stereo", "unknown", "unknown", "5.1/6.1", "5.1" }; +#endif /* #ifdef USE_DVDREAD */ + + +static struct stream_priv_s { + int title; +} stream_priv_dflts = { + 1 +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + { "hostname", ST_OFF(title), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "dvd", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +int dvd_parse_chapter_range(m_option_t *conf, const char *range) { + const char *s; + char *t; + if (!range) + return M_OPT_MISSING_PARAM; + s = range; + dvd_chapter = 1; + dvd_last_chapter = 0; + if(*range && isdigit(*range)) { + dvd_chapter = strtol(range, &s, 10); + if(range == s) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); + return M_OPT_INVALID; + } + } + if(*s == 0) + return 0; + else if(*s != '-') { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); + return M_OPT_INVALID; + } + ++s; + if(*s == 0) + return 0; + if(! isdigit(*s)) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); + return M_OPT_INVALID; + } + dvd_last_chapter = strtol(s, &t, 10); + if (s == t || *t) { + mp_msg(MSGT_OPEN, MSGL_ERR, MSGTR_DVDinvalidChapterRange, range); + return M_OPT_INVALID; + } + return 0; +} + +#ifdef USE_DVDREAD +int dvd_chapter_from_cell(dvd_priv_t* dvd,int title,int cell) +{ + pgc_t * cur_pgc; + ptt_info_t* ptt; + int chapter = cell; + int pgc_id,pgn; + if(title < 0 || cell < 0){ + return 0; + } + /* for most DVD's chapter == cell */ + /* but there are more complecated cases... */ + if(chapter >= dvd->vmg_file->tt_srpt->title[title].nr_of_ptts) { + chapter = dvd->vmg_file->tt_srpt->title[title].nr_of_ptts-1; + } + title = dvd->tt_srpt->title[title].vts_ttn-1; + ptt = dvd->vts_file->vts_ptt_srpt->title[title].ptt; + while(chapter >= 0) { + pgc_id = ptt[chapter].pgcn; + pgn = ptt[chapter].pgn; + cur_pgc = dvd->vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; + if(cell >= cur_pgc->program_map[pgn-1]-1) { + return chapter; + } + --chapter; + } + /* didn't find a chapter ??? */ + return chapter; +} + +int dvd_aid_from_lang(stream_t *stream, unsigned char* lang) { + dvd_priv_t *d=stream->priv; + int code,i; + if(lang) { + while(strlen(lang)>=2) { + code=lang[1]|(lang[0]<<8); + for(i=0;i<d->nr_of_channels;i++) { + if(d->audio_streams[i].language==code) { + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDaudioChannel, + d->audio_streams[i].id, lang[0],lang[1]); + return d->audio_streams[i].id; + } + //printf("%X != %X (%c%c)\n",code,d->audio_streams[i].language,lang[0],lang[1]); + } + lang+=2; while (lang[0]==',' || lang[0]==' ') ++lang; + } + mp_msg(MSGT_OPEN,MSGL_WARN,MSGTR_DVDnoMatchingAudio); + } + return -1; +} + +int dvd_number_of_subs(stream_t *stream) { + dvd_priv_t *d; + if (!stream) return -1; + d = stream->priv; + if (!d) return -1; + return d->nr_of_subtitles; +} + +int dvd_lang_from_sid(stream_t *stream, int id) { + dvd_priv_t *d; + if (!stream) return 0; + d = stream->priv; + if (!d) return 0; + if (id >= d->nr_of_subtitles) return 0; + return d->subtitles[id].language; +} + +int dvd_sid_from_lang(stream_t *stream, unsigned char* lang) { + dvd_priv_t *d=stream->priv; + int code,i; + while(lang && strlen(lang)>=2) { + code=lang[1]|(lang[0]<<8); + for(i=0;i<d->nr_of_subtitles;i++) { + if(d->subtitles[i].language==code) { + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDsubtitleChannel, i, lang[0],lang[1]); + return i; + } + } + lang+=2; + while (lang[0]==',' || lang[0]==' ') ++lang; + } + mp_msg(MSGT_OPEN,MSGL_WARN,MSGTR_DVDnoMatchingSubtitle); + return -1; +} + +static int dvd_next_cell(dvd_priv_t *d) { + int next_cell=d->cur_cell; + + mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next1=0x%X \n",next_cell); + if( d->cur_pgc->cell_playback[ next_cell ].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { + while(next_cell<d->last_cell) { + if( d->cur_pgc->cell_playback[next_cell].block_mode == BLOCK_MODE_LAST_CELL ) + break; + ++next_cell; + } + } + mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next2=0x%X \n",next_cell); + + ++next_cell; + if(next_cell>=d->last_cell) + return -1; // EOF + if(d->cur_pgc->cell_playback[next_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) { + next_cell+=dvd_angle; + if(next_cell>=d->last_cell) + return -1; // EOF + } + mp_msg(MSGT_DVD,MSGL_DBG2, "dvd_next_cell: next3=0x%X \n",next_cell); + return next_cell; +} + +int dvd_read_sector(dvd_priv_t *d,unsigned char* data) { + int len; + + if(d->packs_left==0) { + /** + * 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. + * + * Otherwise, we set our next address past the end of this cell to + * force the code above to go to the next cell in the program. + */ + if(d->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL) { + d->cur_pack= d->dsi_pack.dsi_gi.nv_pck_lbn + ( d->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + mp_msg(MSGT_DVD,MSGL_DBG2, "Navi new pos=0x%X \n",d->cur_pack); + } else { + // end of cell! find next cell! + mp_msg(MSGT_DVD,MSGL_V, "--- END OF CELL !!! ---\n"); + d->cur_pack=d->cell_last_pack+1; + } + } + +read_next: + if(d->cur_pack>d->cell_last_pack) { + // end of cell! + int next=dvd_next_cell(d); + if(next>=0) { + d->cur_cell=next; + // if( d->cur_pgc->cell_playback[d->cur_cell].block_type + // == BLOCK_TYPE_ANGLE_BLOCK ) d->cur_cell+=dvd_angle; + d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + mp_msg(MSGT_DVD,MSGL_V, "DVD next cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); + } else + return -1; // EOF + } + + len = DVDReadBlocks(d->title, d->cur_pack, 1, data); + if(!len) return -1; //error + + if(data[38]==0 && data[39]==0 && data[40]==1 && data[41]==0xBF && + data[1024]==0 && data[1025]==0 && data[1026]==1 && data[1027]==0xBF) { + // found a Navi packet!!! +#if DVDREAD_VERSION >= LIBDVDREAD_VERSION(0,9,0) + navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ])); +#else + navRead_DSI(&d->dsi_pack, &(data[ DSI_START_BYTE ]), sizeof(dsi_t)); +#endif + if(d->cur_pack != d->dsi_pack.dsi_gi.nv_pck_lbn ) { + mp_msg(MSGT_DVD,MSGL_V, "Invalid NAVI packet! lba=0x%X navi=0x%X \n", + d->cur_pack,d->dsi_pack.dsi_gi.nv_pck_lbn); + } else { + // process! + d->packs_left = d->dsi_pack.dsi_gi.vobu_ea; + mp_msg(MSGT_DVD,MSGL_DBG2, "Found NAVI packet! lba=0x%X len=%d \n",d->cur_pack,d->packs_left); + //navPrint_DSI(&d->dsi_pack); + mp_msg(MSGT_DVD,MSGL_DBG3,"\r### CELL %d: Navi: %d/%d IFO: %d/%d \n",d->cur_cell, + d->dsi_pack.dsi_gi.vobu_c_idn,d->dsi_pack.dsi_gi.vobu_vob_idn, + d->cur_pgc->cell_position[d->cur_cell].cell_nr, + d->cur_pgc->cell_position[d->cur_cell].vob_id_nr); + + if(d->angle_seek) { + int i,skip=0; +#if defined(__GNUC__) && ( defined(__sparc__) || defined(hpux) ) + // workaround for a bug in the sparc/hpux version of gcc 2.95.X ... 3.2, + // it generates incorrect code for unaligned access to a packed + // structure member, resulting in an mplayer crash with a SIGBUS + // signal. + // + // See also gcc problem report PR c/7847: + // http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=view+audit-trail&pr=7847 + for(i=0;i<9;i++) { // check if all values zero: + typeof(d->dsi_pack.sml_agli.data[i].address) tmp_addr; + memcpy(&tmp_addr,&d->dsi_pack.sml_agli.data[i].address,sizeof(tmp_addr)); + if((skip=tmp_addr)!=0) break; + } +#else + for(i=0;i<9;i++) // check if all values zero: + if((skip=d->dsi_pack.sml_agli.data[i].address)!=0) break; +#endif + if(skip) { + // sml_agli table has valid data (at least one non-zero): + d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ + d->dsi_pack.sml_agli.data[dvd_angle].address; + d->angle_seek=0; + mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced using sml_agli map! new_lba=0x%X \n",d->cur_pack); + } else { + // check if we're in the right cell, jump otherwise: + if( (d->dsi_pack.dsi_gi.vobu_c_idn==d->cur_pgc->cell_position[d->cur_cell].cell_nr) && + (d->dsi_pack.dsi_gi.vobu_vob_idn==d->cur_pgc->cell_position[d->cur_cell].vob_id_nr) ){ + d->angle_seek=0; + mp_msg(MSGT_DVD,MSGL_V, "Angle-seek synced by cell/vob IDN search! \n"); + } else { + // wrong angle, skip this vobu: + d->cur_pack=d->dsi_pack.dsi_gi.nv_pck_lbn+ + d->dsi_pack.dsi_gi.vobu_ea; + d->angle_seek=2; // DEBUG + } + } + } + } + ++d->cur_pack; + goto read_next; + } + + ++d->cur_pack; + if(d->packs_left>=0) --d->packs_left; + + if(d->angle_seek) { + if(d->angle_seek==2) mp_msg(MSGT_DVD,MSGL_V, "!!! warning! reading packet while angle_seek !!!\n"); + goto read_next; // searching for Navi packet + } + + return d->cur_pack-1; +} + +void dvd_seek(dvd_priv_t *d,int pos) { + d->packs_left=-1; + d->cur_pack=pos; + + // check if we stay in current cell (speedup things, and avoid angle skip) + if(d->cur_pack>d->cell_last_pack || + d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector) { + + // ok, cell change, find the right cell! + d->cur_cell=0; + if(d->cur_pgc->cell_playback[d->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) + d->cur_cell+=dvd_angle; + + while(1) { + int next; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + if(d->cur_pack<d->cur_pgc->cell_playback[ d->cur_cell ].first_sector) { + d->cur_pack=d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + break; + } + if(d->cur_pack<=d->cell_last_pack) break; // ok, we find it! :) + next=dvd_next_cell(d); + if(next<0) { + //d->cur_pack=d->cell_last_pack+1; + break; // we're after the last cell + } + d->cur_cell=next; + } + } + + mp_msg(MSGT_DVD,MSGL_V, "DVD Seek! lba=0x%X cell=%d packs: 0x%X-0x%X \n", + d->cur_pack,d->cur_cell,d->cur_pgc->cell_playback[ d->cur_cell ].first_sector,d->cell_last_pack); + + // if we're in interleaved multi-angle cell, find the right angle chain! + // (read Navi block, and use the seamless angle jump table) + d->angle_seek=1; +} + +void dvd_close(dvd_priv_t *d) { + ifoClose(d->vts_file); + ifoClose(d->vmg_file); + DVDCloseFile(d->title); + DVDClose(d->dvd); + dvd_chapter = 1; + dvd_last_chapter = 0; +} + +#endif /* #ifdef USE_DVDREAD */ + +static int fill_buffer(stream_t *s, char *but, int len) +{ +#ifdef USE_DVDREAD + if(s->type == STREAMTYPE_DVD) { + off_t pos=dvd_read_sector(s->priv,s->buffer); + if(pos>=0) { + len=2048; // full sector + s->pos=2048*pos-len; + } else len=-1; // error + } +#endif + return len; +} + +static int seek(stream_t *s, off_t newpos) { +#ifdef USE_DVDREAD + s->pos=newpos; // real seek + dvd_seek(s->priv,s->pos/2048); +#endif + return 1; +} + +static void stream_dvd_close(stream_t *s) { +#ifdef USE_DVDREAD + dvd_close(s->priv); +#endif +} + +/** +\brief Converts DVD time structure to milliseconds. +\param *dev the DVD time structure to convert +\return returns the time in milliseconds +*/ +static int dvdtimetomsec(dvd_time_t *dt) +{ + static int framerates[4] = {0, 2500, 0, 2997}; + int framerate = framerates[(dt->frame_u & 0xc0) >> 6]; + int msec = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000; + msec += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000; + msec += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000; + if(framerate > 0) + msec += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 100000 / framerate; + return msec; +} + +static int mp_get_titleset_length(ifo_handle_t *vts_file, tt_srpt_t *tt_srpt, int title_no) +{ + int vts_ttn; ///< title number within video title set + int pgc_no; ///< program chain number + int msec; ///< time length in milliseconds + + msec=0; + if(!vts_file || !tt_srpt) + return 0; + + if(vts_file->vtsi_mat && vts_file->vts_pgcit) + { + vts_ttn = tt_srpt->title[title_no].vts_ttn - 1; + pgc_no = vts_file->vts_ptt_srpt->title[vts_ttn].ptt[0].pgcn - 1; + msec = dvdtimetomsec(&vts_file->vts_pgcit->pgci_srp[pgc_no].pgc->playback_time); + } + return msec; +} + + +static int mp_describe_titleset(dvd_reader_t *dvd, tt_srpt_t *tt_srpt, int vts_no) +{ + ifo_handle_t *vts_file; + int title_no, msec=0; + + vts_file = ifoOpen(dvd, vts_no); + if(!vts_file) + return 0; + + if(!vts_file->vtsi_mat || !vts_file->vts_pgcit) + { + ifoClose(vts_file); + return 0; + } + + for(title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) + { + if (tt_srpt->title[title_no].title_set_nr != vts_no) + continue; + msec = mp_get_titleset_length(vts_file, tt_srpt, title_no); + mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_TITLE_%d_LENGTH=%d.%03d\n", title_no + 1, msec / 1000, msec % 1000); + } + ifoClose(vts_file); + return 1; +} + +static int control(stream_t *stream,int cmd,void* arg) +{ + switch(cmd) + { + case STREAM_CTRL_GET_TIME_LENGTH: + { + dvd_priv_t *d = stream->priv; + *((unsigned int *)arg) = mp_get_titleset_length(d->vts_file, d->tt_srpt, d->cur_title-1); + return 1; + } + } + return STREAM_UNSUPORTED; +} + + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + struct stream_priv_s* p = (struct stream_priv_s*)opts; + char *filename; + + filename = strdup(stream->url); + mp_msg(MSGT_OPEN,MSGL_V,"URL: %s\n", filename); + dvd_title = p->title; +#ifdef USE_DVDREAD + if(1){ + //int ret,ret2; + dvd_priv_t *d; + int ttn,pgc_id,pgn; + dvd_reader_t *dvd; + dvd_file_t *title; + ifo_handle_t *vmg_file; + tt_srpt_t *tt_srpt; + ifo_handle_t *vts_file; + /** + * Open the disc. + */ + if(!dvd_device) dvd_device=strdup(DEFAULT_DVD_DEVICE); +#ifdef SYS_DARWIN + /* Dynamic DVD drive selection on Darwin */ + if(!strcmp(dvd_device, "/dev/rdiskN")) { + int i; + char *temp_device = malloc(strlen(dvd_device)+1); + + for (i = 1; i < 10; i++) { + sprintf(temp_device, "/dev/rdisk%d", i); + dvd = DVDOpen(temp_device); + if(!dvd) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device); + } else { +#if DVDREAD_VERSION <= LIBDVDREAD_VERSION(0,9,4) + int len; + if(!UDFFindFile(dvd,"/",&len)) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,temp_device); + DVDClose(dvd); + } else +#endif + { + free(temp_device); + break; + } + } + } + + if(!dvd) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + } else +#endif /* SYS_DARWIN */ + { + dvd = DVDOpen(dvd_device); + if(!dvd) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CantOpenDVD,dvd_device); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + } + + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_DVDwait); + + /** + * Load the video manager to find out the information about the titles on + * this disc. + */ + vmg_file = ifoOpen(dvd, 0); + if(!vmg_file) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVMG); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + tt_srpt = vmg_file->tt_srpt; + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + int title_no; ///< title number + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLES=%d\n", tt_srpt->nr_of_srpts); + for (title_no = 0; title_no < tt_srpt->nr_of_srpts; title_no++) + { + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_CHAPTERS=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_ptts); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_ANGLES=%d\n", title_no + 1, tt_srpt->title[title_no].nr_of_angles); + } + } + if (mp_msg_test(MSGT_IDENTIFY, MSGL_V)) + { + unsigned char discid [16]; ///< disk ID, a 128 bit MD5 sum + int vts_no; ///< video title set number + for (vts_no = 1; vts_no <= vmg_file->vts_atrt->nr_of_vtss; vts_no++) + mp_describe_titleset(dvd, tt_srpt, vts_no); + if (DVDDiscID(dvd, discid) >= 0) + { + int i; + char buf[33]; + for (i = 0; i < 16; i ++) + sprintf(buf+2*i, "%02X", discid[i]); + mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_DISC_ID=%s\n", buf); + } + } + /** + * Make sure our title number is valid. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumTitles, tt_srpt->nr_of_srpts ); + if(dvd_title < 1 || dvd_title > tt_srpt->nr_of_srpts) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidTitle, dvd_title); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + --dvd_title; // remap 1.. -> 0.. + /** + * Make sure the chapter number is valid for this title. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumChapters, tt_srpt->title[dvd_title].nr_of_ptts); + if(dvd_chapter<1 || dvd_chapter>tt_srpt->title[dvd_title].nr_of_ptts) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidChapter, dvd_chapter); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + if(dvd_last_chapter>0) { + if(dvd_last_chapter<dvd_chapter || dvd_last_chapter>tt_srpt->title[dvd_title].nr_of_ptts) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidLastChapter, dvd_last_chapter); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + } + --dvd_chapter; // remap 1.. -> 0.. + /* XXX No need to remap dvd_last_chapter */ + /** + * Make sure the angle number is valid for this title. + */ + mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDnumAngles, tt_srpt->title[dvd_title].nr_of_angles); + if(dvd_angle<1 || dvd_angle>tt_srpt->title[dvd_title].nr_of_angles) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDinvalidAngle, dvd_angle); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + --dvd_angle; // remap 1.. -> 0.. + + ttn = tt_srpt->title[dvd_title].vts_ttn - 1; + /** + * Load the VTS information for the title set our title is in. + */ + vts_file = ifoOpen( dvd, tt_srpt->title[dvd_title].title_set_nr ); + if(!vts_file) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoIFO, tt_srpt->title[dvd_title].title_set_nr ); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + /** + * We've got enough info, time to open the title set data. + */ + title = DVDOpenFile(dvd, tt_srpt->title[dvd_title].title_set_nr, DVD_READ_TITLE_VOBS); + if(!title) { + mp_msg(MSGT_OPEN,MSGL_ERR, MSGTR_DVDnoVOBs, tt_srpt->title[dvd_title].title_set_nr); + ifoClose( vts_file ); + ifoClose( vmg_file ); + DVDClose( dvd ); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + + mp_msg(MSGT_OPEN,MSGL_INFO, MSGTR_DVDopenOk); + // store data + d=malloc(sizeof(dvd_priv_t)); memset(d,0,sizeof(dvd_priv_t)); + d->dvd=dvd; + d->title=title; + d->vmg_file=vmg_file; + d->tt_srpt=tt_srpt; + d->vts_file=vts_file; + d->cur_title = dvd_title+1; + + /** + * Check number of audio channels and types + */ + { + d->nr_of_channels=0; + if(vts_file->vts_pgcit) { + int i; + for(i=0;i<8;i++) +#ifdef USE_MPDVDKIT + if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i].present) { +#else + if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i] & 0x8000) { +#endif + audio_attr_t * audio = &vts_file->vtsi_mat->vts_audio_attr[i]; + int language = 0; + char tmp[] = "unknown"; + + if(audio->lang_type == 1) { + language=audio->lang_code; + tmp[0]=language>>8; + tmp[1]=language&0xff; + tmp[2]=0; + } + + d->audio_streams[d->nr_of_channels].language=language; +#ifdef USE_MPDVDKIT + d->audio_streams[d->nr_of_channels].id=vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i].s_audio; +#else + d->audio_streams[d->nr_of_channels].id=vts_file->vts_pgcit->pgci_srp[ttn].pgc->audio_control[i] >> 8 & 7; +#endif + switch(audio->audio_format) { + case 0: // ac3 + d->audio_streams[d->nr_of_channels].id+=FIRST_AC3_AID; + break; + case 6: // dts + d->audio_streams[d->nr_of_channels].id+=FIRST_DTS_AID; + break; + case 2: // mpeg layer 1/2/3 + case 3: // mpeg2 ext + d->audio_streams[d->nr_of_channels].id+=FIRST_MPG_AID; + break; + case 4: // lpcm + d->audio_streams[d->nr_of_channels].id+=FIRST_PCM_AID; + break; + } + + d->audio_streams[d->nr_of_channels].type=audio->audio_format; + // Pontscho: to my mind, tha channels: + // 1 - stereo + // 5 - 5.1 + d->audio_streams[d->nr_of_channels].channels=audio->channels; + mp_msg(MSGT_OPEN,MSGL_V,"[open] audio stream: %d audio format: %s (%s) language: %s aid: %d\n", + d->nr_of_channels, + dvd_audio_stream_types[ audio->audio_format ], + dvd_audio_stream_channels[ audio->channels ], + tmp, + d->audio_streams[d->nr_of_channels].id + ); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_ID=%d\n", d->audio_streams[d->nr_of_channels].id); + if(language && tmp[0]) + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", d->audio_streams[d->nr_of_channels].id, tmp); + + d->nr_of_channels++; + } + } + mp_msg(MSGT_OPEN,MSGL_V,"[open] number of audio channels on disk: %d.\n",d->nr_of_channels ); + } + + /** + * Check number of subtitles and language + */ + { + int i; + + d->nr_of_subtitles=0; + for(i=0;i<32;i++) +#ifdef USE_MPDVDKIT + if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].present) { +#else + if(vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] & 0x80000000) { +#endif + subp_attr_t * subtitle = &vts_file->vtsi_mat->vts_subp_attr[i]; + video_attr_t *video = &vts_file->vtsi_mat->vts_video_attr; + int language = 0; + char tmp[] = "unknown"; + + if(subtitle->type == 1) { + language=subtitle->lang_code; + tmp[0]=language>>8; + tmp[1]=language&0xff; + tmp[2]=0; + } + + d->subtitles[ d->nr_of_subtitles ].language=language; + d->subtitles[ d->nr_of_subtitles ].id=d->nr_of_subtitles; + if(video->display_aspect_ratio == 0) /* 4:3 */ +#ifdef USE_MPDVDKIT + d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].s_4p3; +#else + d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] >> 24 & 31; +#endif + else if(video->display_aspect_ratio == 3) /* 16:9 */ +#ifdef USE_MPDVDKIT + d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i].s_lbox; +#else + d->subtitles[d->nr_of_subtitles].id = vts_file->vts_pgcit->pgci_srp[ttn].pgc->subp_control[i] >> 8 & 31; +#endif + + mp_msg(MSGT_OPEN,MSGL_V,"[open] subtitle ( sid ): %d language: %s\n", d->nr_of_subtitles, tmp); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SUBTITLE_ID=%d\n", d->subtitles[d->nr_of_subtitles].id); + if(language && tmp[0]) + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", d->nr_of_subtitles, tmp); + d->nr_of_subtitles++; + } + mp_msg(MSGT_OPEN,MSGL_V,"[open] number of subtitles on disk: %d\n",d->nr_of_subtitles ); + } + + /** + * Determine which program chain we want to watch. This is based on the + * chapter number. + */ + pgc_id = vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_chapter].pgcn; // local + pgn = vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_chapter].pgn; // local + d->cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; + d->cur_cell = d->cur_pgc->program_map[pgn-1] - 1; // start playback here + d->packs_left=-1; // for Navi stuff + d->angle_seek=0; + /* XXX dvd_last_chapter is in the range 1..nr_of_ptts */ + if(dvd_last_chapter > 0 && dvd_last_chapter < tt_srpt->title[dvd_title].nr_of_ptts) { + pgn=vts_file->vts_ptt_srpt->title[ttn].ptt[dvd_last_chapter].pgn; + d->last_cell=d->cur_pgc->program_map[pgn-1] - 1; + } else + d->last_cell=d->cur_pgc->nr_of_cells; + + if(d->cur_pgc->cell_playback[d->cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) + d->cur_cell+=dvd_angle; + d->cur_pack = d->cur_pgc->cell_playback[ d->cur_cell ].first_sector; + d->cell_last_pack=d->cur_pgc->cell_playback[ d->cur_cell ].last_sector; + mp_msg(MSGT_DVD,MSGL_V, "DVD start cell: %d pack: 0x%X-0x%X \n",d->cur_cell,d->cur_pack,d->cell_last_pack); + + // ... (unimplemented) + // return NULL; + stream->type = STREAMTYPE_DVD; + stream->sector_size = 2048; + stream->flags = STREAM_READ | STREAM_SEEK; + stream->fill_buffer = fill_buffer; + stream->seek = seek; + stream->control = control; + stream->close = stream_dvd_close; + stream->start_pos = (off_t)d->cur_pack*2048; + stream->end_pos = (off_t)(d->cur_pgc->cell_playback[d->last_cell-1].last_sector)*2048; + mp_msg(MSGT_DVD,MSGL_V,"DVD start=%d end=%d \n",d->cur_pack,d->cur_pgc->cell_playback[d->last_cell-1].last_sector); + stream->priv = (void*)d; + return STREAM_OK; + } +#endif /* #ifdef USE_DVDREAD */ + mp_msg(MSGT_DVD,MSGL_ERR,MSGTR_NoDVDSupport); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; +} + + +stream_info_t stream_info_dvd = { + "DVD stream", + "null", + "", + "", + open_s, + { "dvd", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_dvd.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,48 @@ + +#ifdef USE_DVDREAD + +#ifdef USE_MPDVDKIT +#include "libmpdvdkit2/dvd_reader.h" +#include "libmpdvdkit2/ifo_types.h" +#include "libmpdvdkit2/ifo_read.h" +#include "libmpdvdkit2/nav_read.h" +#else +#include <dvdread/dvd_reader.h> +#include <dvdread/ifo_types.h> +#include <dvdread/ifo_read.h> +#include <dvdread/nav_read.h> +#endif + +typedef struct { + dvd_reader_t *dvd; + dvd_file_t *title; + ifo_handle_t *vmg_file; + tt_srpt_t *tt_srpt; + ifo_handle_t *vts_file; + vts_ptt_srpt_t *vts_ptt_srpt; + pgc_t *cur_pgc; +// + int cur_title; + int cur_cell; + int last_cell; + int cur_pack; + int cell_last_pack; +// Navi: + int packs_left; + dsi_t dsi_pack; + int angle_seek; +// audio datas + int nr_of_channels; + stream_language_t audio_streams[32]; +// subtitles + int nr_of_subtitles; + stream_language_t subtitles[32]; +} dvd_priv_t; + +int dvd_number_of_subs(stream_t *stream); +int dvd_lang_from_sid(stream_t *stream, int id); +int dvd_aid_from_lang(stream_t *stream, unsigned char* lang); +int dvd_sid_from_lang(stream_t *stream, unsigned char* lang); +int dvd_chapter_from_cell(dvd_priv_t *dvd,int title,int cell); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_file.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,162 @@ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +static struct stream_priv_s { + char* filename; + char *filename2; +} stream_priv_dflts = { + NULL, NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + {"string", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"filename", ST_OFF(filename2), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "file", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + int r = read(s->fd,buffer,max_len); + return (r <= 0) ? -1 : r; +} + +static int write_buffer(stream_t *s, char* buffer, int len) { + int r = write(s->fd,buffer,len); + return (r <= 0) ? -1 : r; +} + +static int seek(stream_t *s,off_t newpos) { + s->pos = newpos; + if(lseek(s->fd,s->pos,SEEK_SET)<0) { + s->eof=1; + return 0; + } + return 1; +} + +static int seek_forward(stream_t *s,off_t newpos) { + if(newpos<s->pos){ + mp_msg(MSGT_STREAM,MSGL_INFO,"Cannot seek backward in linear streams!\n"); + return 0; + } + while(s->pos<newpos){ + int len=s->fill_buffer(s,s->buffer,STREAM_BUFFER_SIZE); + if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; break; } // EOF + s->buf_pos=0; + s->buf_len=len; + s->pos+=len; + } + return 1; +} + +static int open_f(stream_t *stream,int mode, void* opts, int* file_format) { + int f; + mode_t m = 0; + off_t len; + unsigned char *filename; + struct stream_priv_s* p = (struct stream_priv_s*)opts; + + if(mode == STREAM_READ) + m = O_RDONLY; + else if(mode == STREAM_WRITE) + m = O_WRONLY; + else { + mp_msg(MSGT_OPEN,MSGL_ERR, "[file] Unknown open mode %d\n",mode); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + + if(p->filename) + filename = p->filename; + else if(p->filename2) + filename = p->filename2; + else + filename = NULL; + if(!filename) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[file] No filename\n"); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + +#if defined(__CYGWIN__)|| defined(__MINGW32__) + m |= O_BINARY; +#endif + + if(!strcmp(filename,"-")){ + if(mode == STREAM_READ) { + // read from stdin + mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_ReadSTDIN); + f=0; // 0=stdin +#ifdef __MINGW32__ + setmode(fileno(stdin),O_BINARY); +#endif + } else { + mp_msg(MSGT_OPEN,MSGL_INFO,"Writing to stdout\n"); + f=1; +#ifdef __MINGW32__ + setmode(fileno(stdout),O_BINARY); +#endif + } + } else { + f=open(filename,m); + if(f<0) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + } + + len=lseek(f,0,SEEK_END); lseek(f,0,SEEK_SET); +#ifdef __MINGW32__ + if(f==0 || len == -1) { +#else + if(len == -1) { +#endif + stream->seek = seek_forward; + stream->type = STREAMTYPE_STREAM; // Must be move to STREAMTYPE_FILE + stream->flags |= STREAM_SEEK_FW; + } else if(len >= 0) { + stream->seek = seek; + stream->end_pos = len; + stream->type = STREAMTYPE_FILE; + } + + mp_msg(MSGT_OPEN,MSGL_V,"[file] File size is %"PRId64" bytes\n", (int64_t)len); + + stream->fd = f; + stream->fill_buffer = fill_buffer; + stream->write_buffer = write_buffer; + + m_struct_free(&stream_opts,opts); + return STREAM_OK; +} + +stream_info_t stream_info_file = { + "File", + "file", + "Albeu", + "based on the code from ??? (probably Arpi)", + open_f, + { "file", "", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_ftp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,469 @@ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#ifndef HAVE_WINSOCK2 +#include <sys/socket.h> +#define closesocket close +#else +#include <winsock2.h> +#endif + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +static struct stream_priv_s { + char* user; + char* pass; + char* host; + int port; + char* filename; + + char *cput,*cget; + int handle; + int cavail,cleft; + char *buf; +} stream_priv_dflts = { + "anonymous","no@spam", + NULL, + 21, + NULL, + NULL, + NULL, + + 0, + 0,0, + NULL +}; + +#define BUFSIZE 2048 + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + {"username", ST_OFF(user), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"password", ST_OFF(pass), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"port", ST_OFF(port), CONF_TYPE_INT, 0, 0 ,65635, NULL}, + {"filename", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "ftp", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +#define TELNET_IAC 255 /* interpret as command: */ +#define TELNET_IP 244 /* interrupt process--permanently */ +#define TELNET_SYNCH 242 /* for telfunc calls */ + +// Check if there is something to read on a fd. This avoid hanging +// forever if the network stop responding. +static int fd_can_read(int fd,int timeout) { + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(fd,&fds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + return (select(fd+1, &fds, NULL, NULL, &tv) > 0); +} + +/* + * read a line of text + * + * return -1 on error or bytecount + */ +static int readline(char *buf,int max,struct stream_priv_s *ctl) +{ + int x,retval = 0; + char *end,*bp=buf; + int eof = 0; + + do { + if (ctl->cavail > 0) { + x = (max >= ctl->cavail) ? ctl->cavail : max-1; + end = memccpy(bp,ctl->cget,'\n',x); + if (end != NULL) + x = end - bp; + retval += x; + bp += x; + *bp = '\0'; + max -= x; + ctl->cget += x; + ctl->cavail -= x; + if (end != NULL) { + bp -= 2; + if (strcmp(bp,"\r\n") == 0) { + *bp++ = '\n'; + *bp++ = '\0'; + --retval; + } + break; + } + } + if (max == 1) { + *buf = '\0'; + break; + } + if (ctl->cput == ctl->cget) { + ctl->cput = ctl->cget = ctl->buf; + ctl->cavail = 0; + ctl->cleft = BUFSIZE; + } + if(eof) { + if (retval == 0) + retval = -1; + break; + } + + if(!fd_can_read(ctl->handle, 15)) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); + retval = -1; + break; + } + + if ((x = recv(ctl->handle,ctl->cput,ctl->cleft,0)) == -1) { + mp_msg(MSGT_STREAM,MSGL_ERR, "[ftp] read error: %s\n",strerror(errno)); + retval = -1; + break; + } + if (x == 0) + eof = 1; + ctl->cleft -= x; + ctl->cavail += x; + ctl->cput += x; + } while (1); + + return retval; +} + +/* + * read a response from the server + * + * return 0 if first char doesn't match + * return 1 if first char matches + */ +static int readresp(struct stream_priv_s* ctl,char* rsp) +{ + static char response[256]; + char match[5]; + int r; + + if (readline(response,256,ctl) == -1) + return 0; + + r = atoi(response)/100; + if(rsp) strcpy(rsp,response); + + mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response); + + if (response[3] == '-') { + strncpy(match,response,3); + match[3] = ' '; + match[4] = '\0'; + do { + if (readline(response,256,ctl) == -1) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Control socket read failed\n"); + return 0; + } + mp_msg(MSGT_OPEN,MSGL_V, "[ftp] < %s",response); + } while (strncmp(response,match,4)); + } + return r; +} + + +static int FtpSendCmd(const char *cmd, struct stream_priv_s *nControl,char* rsp) +{ + int l = strlen(cmd); + int hascrlf = cmd[l - 2] == '\r' && cmd[l - 1] == '\n'; + + if(hascrlf && l == 2) mp_msg(MSGT_STREAM,MSGL_V, "\n"); + else mp_msg(MSGT_STREAM,MSGL_V, "[ftp] > %s",cmd); + while(l > 0) { + int s = send(nControl->handle,cmd,l,0); + + if(s <= 0) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] write error: %s\n",strerror(errno)); + return 0; + } + + cmd += s; + l -= s; + } + + if (hascrlf) + return readresp(nControl,rsp); + else + return FtpSendCmd("\r\n", nControl, rsp); +} + +static int FtpOpenPort(struct stream_priv_s* p) { + int resp,fd; + char rsp_txt[256]; + char* par,str[128]; + int num[6]; + + resp = FtpSendCmd("PASV",p,rsp_txt); + if(resp != 2) { + mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'PASV' failed: %s\n",rsp_txt); + return 0; + } + + par = strchr(rsp_txt,'('); + + if(!par || !par[0] || !par[1]) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] invalid server response: %s ??\n",rsp_txt); + return 0; + } + + sscanf(par+1,"%u,%u,%u,%u,%u,%u",&num[0],&num[1],&num[2], + &num[3],&num[4],&num[5]); + snprintf(str,127,"%d.%d.%d.%d",num[0],num[1],num[2],num[3]); + fd = connect2Server(str,(num[4]<<8)+num[5],0); + + if(fd < 0) + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] failed to create data connection\n"); + + return fd; +} + +static int FtpOpenData(stream_t* s,size_t newpos) { + struct stream_priv_s* p = s->priv; + int resp; + char str[256],rsp_txt[256]; + + // Open a new connection + s->fd = FtpOpenPort(p); + + if(s->fd < 0) return 0; + + if(newpos > 0) { + snprintf(str,255,"REST %"PRId64, (int64_t)newpos); + + resp = FtpSendCmd(str,p,rsp_txt); + if(resp != 3) { + mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt); + newpos = 0; + } + } + + // Get the file + snprintf(str,255,"RETR %s",p->filename); + resp = FtpSendCmd(str,p,rsp_txt); + + if(resp != 1) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); + return 0; + } + + s->pos = newpos; + return 1; +} + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + int r; + + if(s->fd < 0 && !FtpOpenData(s,s->pos)) + return -1; + + if(!fd_can_read(s->fd, 15)) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); + return -1; + } + + r = recv(s->fd,buffer,max_len,0); + return (r <= 0) ? -1 : r; +} + +static int seek(stream_t *s,off_t newpos) { + struct stream_priv_s* p = s->priv; + int resp; + char rsp_txt[256]; + + if(s->pos > s->end_pos) { + s->eof=1; + return 0; + } + + // Check to see if the server doesn't alredy terminated the transfert + if(fd_can_read(p->handle, 0)) { + if(readresp(p,rsp_txt) != 2) + mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] Warning the server didn't finished the transfert correctly: %s\n",rsp_txt); + closesocket(s->fd); + s->fd = -1; + } + + // Close current download + if(s->fd >= 0) { + static const char pre_cmd[]={TELNET_IAC,TELNET_IP,TELNET_IAC,TELNET_SYNCH}; + //int fl; + + // First close the fd + closesocket(s->fd); + s->fd = 0; + + // Send send the telnet sequence needed to make the server react + + // Dunno if this is really needed, lftp have it. I let + // it here in case it turn out to be needed on some other OS + //fl=fcntl(p->handle,F_GETFL); + //fcntl(p->handle,F_SETFL,fl&~O_NONBLOCK); + + // send only first byte as OOB due to OOB braindamage in many unices + send(p->handle,pre_cmd,1,MSG_OOB); + send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,0); + + //fcntl(p->handle,F_SETFL,fl); + + // Get the 426 Transfer aborted + // Or the 226 Transfer complete + resp = readresp(p,rsp_txt); + if(resp != 4 && resp != 2) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Server didn't abort correctly: %s\n",rsp_txt); + s->eof = 1; + return 0; + } + // Send the ABOR command + // Ignore the return code as sometimes it fail with "nothing to abort" + FtpSendCmd("ABOR",p,rsp_txt); + } + return FtpOpenData(s,newpos); +} + + +static void close_f(stream_t *s) { + struct stream_priv_s* p = s->priv; + + if(!p) return; + + if(s->fd > 0) { + closesocket(s->fd); + s->fd = 0; + } + + FtpSendCmd("QUIT",p,NULL); + + if(p->handle) closesocket(p->handle); + if(p->buf) free(p->buf); + + m_struct_free(&stream_opts,p); +} + + + +static int open_f(stream_t *stream,int mode, void* opts, int* file_format) { + int len = 0,resp; + struct stream_priv_s* p = (struct stream_priv_s*)opts; + char str[256],rsp_txt[256]; + + if(mode != STREAM_READ) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode); + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + + if(!p->filename || !p->host) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Bad url\n"); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + + // Open the control connection + p->handle = connect2Server(p->host,p->port,1); + + if(p->handle < 0) { + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + + // We got a connection, let's start serious things + stream->fd = -1; + stream->priv = p; + p->buf = malloc(BUFSIZE); + + if (readresp(p, NULL) == 0) { + close_f(stream); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + + // Login + snprintf(str,255,"USER %s",p->user); + resp = FtpSendCmd(str,p,rsp_txt); + + // password needed + if(resp == 3) { + snprintf(str,255,"PASS %s",p->pass); + resp = FtpSendCmd(str,p,rsp_txt); + if(resp != 2) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); + close_f(stream); + return STREAM_ERROR; + } + } else if(resp != 2) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt); + close_f(stream); + return STREAM_ERROR; + } + + // Set the transfert type + resp = FtpSendCmd("TYPE I",p,rsp_txt); + if(resp != 2) { + mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'TYPE I' failed: %s\n",rsp_txt); + close_f(stream); + return STREAM_ERROR; + } + + // Get the filesize + snprintf(str,255,"SIZE %s",p->filename); + resp = FtpSendCmd(str,p,rsp_txt); + if(resp != 2) { + mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt); + } else { + int dummy; + sscanf(rsp_txt,"%d %d",&dummy,&len); + } + + if(len > 0) { + stream->seek = seek; + stream->end_pos = len; + } + + // The data connection is really opened only at the first + // read/seek. This must be done when the cache is used + // because the connection would stay open in the main process, + // preventing correct abort with many servers. + stream->fd = -1; + stream->priv = p; + stream->fill_buffer = fill_buffer; + stream->close = close_f; + + return STREAM_OK; +} + +stream_info_t stream_info_ftp = { + "File Transfer Protocol", + "ftp", + "Albeu", + "reuse a bit of code from ftplib written by Thomas Pfau", + open_f, + { "ftp", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_livedotcom.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,119 @@ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "stream.h" +#include "network.h" +#include "demuxer.h" +#include "help_mp.h" + +extern int network_bandwidth; + +static int _rtsp_streaming_seek(int fd, off_t pos, streaming_ctrl_t* streaming_ctrl) { + return -1; // For now, we don't handle RTSP stream seeking +} + +static int rtsp_streaming_start(stream_t* stream) { + stream->streaming_ctrl->streaming_seek = _rtsp_streaming_seek; + return 0; +} + + +static int open_live_rtsp_sip(stream_t *stream,int mode, void* opts, int* file_format) { + URL_t *url; + + stream->streaming_ctrl = streaming_ctrl_new(); + if( stream->streaming_ctrl==NULL ) { + return STREAM_ERROR; + } + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new(stream->url); + stream->streaming_ctrl->url = check4proxies(url); + //url_free(url); + + mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_LIVE555, URL: %s\n", stream->url); + + if(rtsp_streaming_start(stream) < 0) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtsp_streaming_start failed\n"); + goto fail; + } + + *file_format = DEMUXER_TYPE_RTP; + stream->type = STREAMTYPE_STREAM; + return STREAM_OK; + +fail: + streaming_ctrl_free( stream->streaming_ctrl ); + stream->streaming_ctrl = NULL; + return STREAM_ERROR; +} + +static int open_live_sdp(stream_t *stream,int mode, void* opts, int* file_format) { + int f; + char *filename = stream->url; + off_t len; + char* sdpDescription; + ssize_t numBytesRead; + + if(strncmp("sdp://",filename,6) == 0) { + filename += 6; +#if defined(__CYGWIN__) || defined(__MINGW32__) + f = open(filename,O_RDONLY|O_BINARY); +#else + f = open(filename,O_RDONLY); +#endif + if(f < 0) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename); + return STREAM_ERROR; + } + + len=lseek(f,0,SEEK_END); + lseek(f,0,SEEK_SET); + if(len == -1) + return STREAM_ERROR; + if(len > SIZE_MAX - 1) + return STREAM_ERROR; + + sdpDescription = malloc(len+1); + if(sdpDescription == NULL) return STREAM_ERROR; + numBytesRead = read(f, sdpDescription, len); + if(numBytesRead != len) { + free(sdpDescription); + return STREAM_ERROR; + } + sdpDescription[len] = '\0'; // to be safe + stream->priv = sdpDescription; + + stream->type = STREAMTYPE_SDP; + *file_format = DEMUXER_TYPE_RTP; + return STREAM_OK; + } + return STREAM_UNSUPORTED; +} + + +stream_info_t stream_info_rtsp_sip = { + "standard RTSP and SIP", + "RTSP and SIP", + "Ross Finlayson", + "Uses LIVE555 Streaming Media library.", + open_live_rtsp_sip, + {"rtsp", "sip", NULL }, + NULL, + 0 // Urls are an option string +}; + +stream_info_t stream_info_sdp = { + "SDP stream descriptor", + "SDP", + "Ross Finlayson", + "Uses LIVE555 Streaming Media library.", + open_live_sdp, + {"sdp", NULL }, + NULL, + 0 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_netstream.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,308 @@ +/* + * stream_netstream.c + * + * Copyright (C) Alban Bedel - 04/2003 + * + * This file is part of MPlayer, a free movie player. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/* + * Net stream allow you to access MPlayer stream accross a tcp + * connection. + * Note that at least mf and tv use a dummy stream (they are + * implemented at the demuxer level) so you won't be able to + * access those :(( but dvd, vcd and so on should work perfectly + * (if you have the bandwidth ;) + * A simple server is in TOOLS/netstream. + * + */ + + +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <errno.h> + +#ifndef HAVE_WINSOCK2 +#define closesocket close +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#else +#include <winsock2.h> +#endif + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" +#include "bswap.h" + +#include "netstream.h" + +static struct stream_priv_s { + char* host; + int port; + char* url; +} stream_priv_dflts = { + NULL, + 10000, + NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"port", ST_OFF(port), CONF_TYPE_INT, M_OPT_MIN, 1 ,0, NULL}, + {"filename", ST_OFF(url), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "netstream", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +//// When the cache is running we need a lock as +//// fill_buffer is called from another proccess +static int lock_fd(int fd) { +#ifndef HAVE_WINSOCK2 + struct flock lock; + + memset(&lock,0,sizeof(struct flock)); + lock.l_type = F_WRLCK; + + mp_msg(MSGT_STREAM,MSGL_DBG2, "Lock (%d)\n",getpid()); + do { + if(fcntl(fd,F_SETLKW,&lock)) { + if(errno == EAGAIN) continue; + mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to get the lock: %s\n", + strerror(errno)); + return 0; + } + } while(0); + mp_msg(MSGT_STREAM,MSGL_DBG2, "Locked (%d)\n",getpid()); +#else +printf("FIXME? should lock here\n"); +#endif + return 1; +} + +static int unlock_fd(int fd) { +#ifndef HAVE_WINSOCK2 + struct flock lock; + + memset(&lock,0,sizeof(struct flock)); + lock.l_type = F_UNLCK; + + mp_msg(MSGT_STREAM,MSGL_DBG2, "Unlock (%d)\n",getpid()); + if(fcntl(fd,F_SETLK,&lock)) { + mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to release the lock: %s\n", + strerror(errno)); + return 0; + } +#else +printf("FIXME? should unlock here\n"); +#endif + return 1; +} + +static mp_net_stream_packet_t* send_net_stream_cmd(stream_t *s,uint16_t cmd,char* data,int len) { + mp_net_stream_packet_t* pack; + + // Cache is enabled : lock + if(s->cache_data && !lock_fd(s->fd)) + return NULL; + // Send a command + if(!write_packet(s->fd,cmd,data,len)) { + if(s->cache_data) unlock_fd(s->fd); + return 0; + } + // Read the response + pack = read_packet(s->fd); + // Now we can unlock + if(s->cache_data) unlock_fd(s->fd); + + if(!pack) + return NULL; + + switch(pack->cmd) { + case NET_STREAM_OK: + return pack; + case NET_STREAM_ERROR: + if(pack->len > sizeof(mp_net_stream_packet_t)) + mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed: %s\n",pack->data); + else + mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed\n"); + free(pack); + return NULL; + } + + mp_msg(MSGT_STREAM,MSGL_ERR, "Unknown response to %d: %d\n",cmd,pack->cmd); + free(pack); + return NULL; +} + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + uint16_t len = le2me_16(max_len); + mp_net_stream_packet_t* pack; + + pack = send_net_stream_cmd(s,NET_STREAM_FILL_BUFFER,(char*)&len,2); + if(!pack) { + return -1; + } + len = pack->len - sizeof(mp_net_stream_packet_t); + if(len > max_len) { + mp_msg(MSGT_STREAM,MSGL_ERR, "Got a too big a packet %d / %d\n",len,max_len); + free(pack); + return 0; + } + if(len > 0) + memcpy(buffer,pack->data,len); + free(pack); + return len; +} + + +static int seek(stream_t *s,off_t newpos) { + uint64_t pos = le2me_64((uint64_t)newpos); + mp_net_stream_packet_t* pack; + + pack = send_net_stream_cmd(s,NET_STREAM_SEEK,(char*)&pos,8); + if(!pack) { + return 0; + } + s->pos = newpos; + free(pack); + return 1; +} + +static int net_stream_reset(struct stream_st *s) { + mp_net_stream_packet_t* pack; + + pack = send_net_stream_cmd(s,NET_STREAM_RESET,NULL,0); + if(!pack) { + return 0; + } + free(pack); + return 1; +} + +static int control(struct stream_st *s,int cmd,void* arg) { + switch(cmd) { + case STREAM_CTRL_RESET: + return net_stream_reset(s); + } + return STREAM_UNSUPORTED; +} + +static void close_s(struct stream_st *s) { + mp_net_stream_packet_t* pack; + + pack = send_net_stream_cmd(s,NET_STREAM_CLOSE,NULL,0); + if(pack) + free(pack); +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + int f; + struct stream_priv_s* p = (struct stream_priv_s*)opts; + mp_net_stream_packet_t* pack; + mp_net_stream_opened_t* opened; + + if(mode != STREAM_READ) + return STREAM_UNSUPORTED; + + if(!p->host) { + mp_msg(MSGT_OPEN,MSGL_ERR, "We need an host name (ex: mpst://server.net/cdda://5)\n"); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + if(!p->url || strlen(p->url) == 0) { + mp_msg(MSGT_OPEN,MSGL_ERR, "We need a remote url (ex: mpst://server.net/cdda://5)\n"); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + + f = connect2Server(p->host,p->port,1); + if(f < 0) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Connection to %s:%d failed\n",p->host,p->port); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + stream->fd = f; + /// Now send an open command + pack = send_net_stream_cmd(stream,NET_STREAM_OPEN,p->url,strlen(p->url) + 1); + if(!pack) { + goto error; + } + + if(pack->len != sizeof(mp_net_stream_packet_t) + + sizeof(mp_net_stream_opened_t)) { + mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid open response packet len (%d bytes)\n",pack->len); + free(pack); + goto error; + } + + opened = (mp_net_stream_opened_t*)pack->data; + net_stream_opened_2_me(opened); + + *file_format = opened->file_format; + stream->flags = opened->flags; + stream->sector_size = opened->sector_size; + stream->start_pos = opened->start_pos; + stream->end_pos = opened->end_pos; + + stream->fill_buffer = fill_buffer; + stream->control = control; + if(stream->flags & STREAM_SEEK) + stream->seek = seek; + stream->close = close_s; + + free(pack); + m_struct_free(&stream_opts,opts); + + return STREAM_OK; + + error: + closesocket(f); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; +} + +stream_info_t stream_info_netstream = { + "Net stream", + "netstream", + "Albeu", + "", + open_s, + { "mpst",NULL }, + &stream_opts, + 1 // Url is an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_null.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,45 @@ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> + +#include "stream.h" +#include "demuxer.h" + +#ifdef USE_TV +extern char* tv_param_channel; +#endif + + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + stream->type = STREAMTYPE_DUMMY; + + if(strncmp("mf://",stream->url,5) == 0) { + *file_format = DEMUXER_TYPE_MF; + } +#ifdef USE_TV + else if (strncmp("tv://",stream->url,5) == 0) { + *file_format = DEMUXER_TYPE_TV; + if(stream->url[5] != '\0') + tv_param_channel = strdup(stream->url + 5); + } +#endif + return 1; +} + + +stream_info_t stream_info_null = { + "Null stream", + "null", + "Albeu", + "", + open_s, + { +#ifdef USE_TV +"tv", +#endif +"mf", "null", NULL }, + NULL, + 0 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_pvr.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,1026 @@ +/* + * Copyright (C) 2006 Benjamin Zores + * Stream layer for WinTV PVR-150/250/350 (a.k.a IVTV) PVR cards. + * See http://ivtvdriver.org/index.php/Main_Page for more details on the + * cards supported by the ivtv driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/time.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <inttypes.h> +#include <sys/poll.h> +#include <linux/videodev2.h> +#include <linux/ivtv.h> + +#include "mp_msg.h" +#include "help_mp.h" + +#include "stream.h" +#include "tv.h" + +#define PVR_DEFAULT_DEVICE "/dev/video0" + +/* logging mechanisms */ +#define LOG_LEVEL_PVR "[pvr]" +#define LOG_LEVEL_V4L2 "[v4l2]" +#define LOG_LEVEL_IVTV "[ivtv]" + +/* IVTV driver settings (see http://ivtvdriver.org/index.php/Ivtvctl ) */ + +/* codec aspect ratio (1:1, 4:3, 16:9, 2.21:1) */ +#define PVR_ASPECT_RATIO_1_1 1 +#define PVR_ASPECT_RATIO_4_3 2 +#define PVR_ASPECT_RATIO_16_9 3 +#define PVR_ASPECT_RATIO_2_21_1 4 + +/* audio codec sample rate (32KHz, CD 44.1 KHz, AC97 48 KHz) */ +#define PVR_AUDIO_SAMPLE_RATE_44_1_KHZ 0x0000 +#define PVR_AUDIO_SAMPLE_RATE_48_KHZ 0x0001 +#define PVR_AUDIO_SAMPLE_RATE_32_KHZ 0x0002 + +/* audio codec layer (1 or 2) */ +#define PVR_AUDIO_LAYER_1 0x0004 +#define PVR_AUDIO_LAYER_2 0x0008 + +/* audio codec bitrate */ +#define PVR_AUDIO_BITRATE_32 0x0010 +#define PVR_AUDIO_BITRATE_L1_64 0x0020 +#define PVR_AUDIO_BITRATE_L1_96 0x0030 +#define PVR_AUDIO_BITRATE_L1_128 0x0040 +#define PVR_AUDIO_BITRATE_L1_160 0x0050 +#define PVR_AUDIO_BITRATE_L1_192 0x0060 +#define PVR_AUDIO_BITRATE_L1_224 0x0070 +#define PVR_AUDIO_BITRATE_L1_256 0x0080 +#define PVR_AUDIO_BITRATE_L1_288 0x0090 +#define PVR_AUDIO_BITRATE_L1_320 0x00A0 +#define PVR_AUDIO_BITRATE_L1_352 0x00B0 +#define PVR_AUDIO_BITRATE_L1_384 0x00C0 +#define PVR_AUDIO_BITRATE_L1_416 0x00D0 +#define PVR_AUDIO_BITRATE_L1_448 0x00E0 +#define PVR_AUDIO_BITRATE_L2_48 0x0020 +#define PVR_AUDIO_BITRATE_L2_56 0x0030 +#define PVR_AUDIO_BITRATE_L2_64 0x0040 +#define PVR_AUDIO_BITRATE_L2_80 0x0050 +#define PVR_AUDIO_BITRATE_L2_96 0x0060 +#define PVR_AUDIO_BITRATE_L2_112 0x0070 +#define PVR_AUDIO_BITRATE_L2_128 0x0080 +#define PVR_AUDIO_BITRATE_L2_160 0x0090 +#define PVR_AUDIO_BITRATE_L2_192 0x00A0 +#define PVR_AUDIO_BITRATE_L2_224 0x00B0 +#define PVR_AUDIO_BITRATE_L2_256 0x00C0 +#define PVR_AUDIO_BITRATE_L2_320 0x00D0 +#define PVR_AUDIO_BITRATE_L2_384 0x00E0 + +/* audio codec mode */ +#define PVR_AUDIO_MODE_ARG_STEREO "stereo" +#define PVR_AUDIO_MODE_ARG_JOINT_STEREO "joint_stereo" +#define PVR_AUDIO_MODE_ARG_DUAL "dual" +#define PVR_AUDIO_MODE_ARG_MONO "mono" +#define PVR_AUDIO_MODE_STEREO 0x0000 +#define PVR_AUDIO_MODE_JOINT_STEREO 0x0100 +#define PVR_AUDIO_MODE_DUAL 0x0200 +#define PVR_AUDIO_MODE_MONO 0x0300 + +/* video codec bitrate mode */ +#define PVR_VIDEO_BITRATE_MODE_ARG_VBR "vbr" +#define PVR_VIDEO_BITRATE_MODE_ARG_CBR "cbr" +#define PVR_VIDEO_BITRATE_MODE_VBR 0 +#define PVR_VIDEO_BITRATE_MODE_CBR 1 + +/* video codec stream type */ +#define PVR_VIDEO_STREAM_TYPE_PS "ps" +#define PVR_VIDEO_STREAM_TYPE_TS "ts" +#define PVR_VIDEO_STREAM_TYPE_MPEG1 "mpeg1" +#define PVR_VIDEO_STREAM_TYPE_DVD "dvd" +#define PVR_VIDEO_STREAM_TYPE_VCD "vcd" +#define PVR_VIDEO_STREAM_TYPE_SVCD "svcd" +#define PVR_VIDEO_STREAM_TYPE_DVD_S1 "dvds1" +#define PVR_VIDEO_STREAM_TYPE_DVD_S2 "dvds2" + +/* command line arguments */ +int pvr_param_aspect_ratio = 0; +int pvr_param_sample_rate = 0; +int pvr_param_audio_layer = 0; +int pvr_param_audio_bitrate = 0; +char *pvr_param_audio_mode = NULL; +int pvr_param_bitrate = 0; +char *pvr_param_bitrate_mode = NULL; +int pvr_param_bitrate_peak = 0; +char *pvr_param_stream_type = NULL; + +struct pvr_t { + int dev_fd; + char *video_dev; + + /* v4l2 params */ + int mute; + int input; + int normid; + int brightness; + int contrast; + int hue; + int saturation; + int width; + int height; + char *freq; + + /* ivtv params */ + int aspect; + int samplerate; + int layer; + int audio_rate; + int audio_mode; + int bitrate; + int bitrate_mode; + int bitrate_peak; + int stream_type; +}; + +static struct pvr_t * +pvr_init (void) +{ + struct pvr_t *pvr = NULL; + + pvr = malloc (sizeof (struct pvr_t)); + pvr->dev_fd = -1; + pvr->video_dev = strdup (PVR_DEFAULT_DEVICE); + + /* v4l2 params */ + pvr->mute = 0; + pvr->input = 0; + pvr->normid = -1; + pvr->brightness = 0; + pvr->contrast = 0; + pvr->hue = 0; + pvr->saturation = 0; + pvr->width = -1; + pvr->height = -1; + pvr->freq = NULL; + + /* ivtv params */ + pvr->aspect = -1; + pvr->samplerate = -1; + pvr->layer = -1; + pvr->audio_rate = -1; + pvr->audio_mode = -1; + pvr->bitrate = -1; + pvr->bitrate_mode = -1; + pvr->bitrate_peak = -1; + pvr->stream_type = -1; + + return pvr; +} + +static void +pvr_uninit (struct pvr_t *pvr) +{ + if (!pvr) + return; + + /* close device */ + if (pvr->dev_fd) + close (pvr->dev_fd); + + if (pvr->video_dev) + free (pvr->video_dev); + if (pvr->freq) + free (pvr->freq); + free (pvr); +} + +/* IVTV layer */ + +static void +parse_ivtv_options (struct pvr_t *pvr) +{ + if (!pvr) + return; + + /* -pvr aspect=digit */ + if (pvr_param_aspect_ratio >= 1 && pvr_param_aspect_ratio <= 4) + pvr->aspect = pvr_param_aspect_ratio; + + /* -pvr arate=x */ + if (pvr_param_sample_rate != 0) + { + switch (pvr_param_sample_rate) + { + case 32000: + pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_32_KHZ; + break; + case 44100: + pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_44_1_KHZ; + break; + case 48000: + pvr->samplerate = PVR_AUDIO_SAMPLE_RATE_48_KHZ; + break; + default: + break; + } + } + + /* -pvr alayer=x */ + if (pvr_param_audio_layer == 1) + pvr->layer = PVR_AUDIO_LAYER_1; + else if (pvr_param_audio_layer == 2) + pvr->layer = PVR_AUDIO_LAYER_2; + + /* -pvr abitrate=x */ + if (pvr_param_audio_bitrate != 0) + { + /* set according to layer or use layer 1 by default if not specified */ + switch (pvr_param_audio_bitrate) + { + case 32: + pvr->audio_rate = PVR_AUDIO_BITRATE_32; + break; + case 48: + pvr->audio_rate = PVR_AUDIO_BITRATE_L2_48; + break; + case 56: + pvr->audio_rate = PVR_AUDIO_BITRATE_L2_56; + break; + case 64: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_64 : PVR_AUDIO_BITRATE_L1_64; + break; + case 80: + pvr->audio_rate = PVR_AUDIO_BITRATE_L2_80; + break; + case 96: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_96 : PVR_AUDIO_BITRATE_L1_96; + break; + case 112: + pvr->audio_rate = PVR_AUDIO_BITRATE_L2_112; + break; + case 128: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_128 : PVR_AUDIO_BITRATE_L1_128; + break; + case 160: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_160 : PVR_AUDIO_BITRATE_L1_160; + break; + case 192: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_192 : PVR_AUDIO_BITRATE_L1_192; + break; + case 224: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_224 : PVR_AUDIO_BITRATE_L1_224; + break; + case 256: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_256 : PVR_AUDIO_BITRATE_L1_256; + break; + case 288: + pvr->audio_rate = PVR_AUDIO_BITRATE_L1_288; + break; + case 320: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_320 : PVR_AUDIO_BITRATE_L1_320; + break; + case 352: + pvr->audio_rate = PVR_AUDIO_BITRATE_L1_352; + break; + case 384: + pvr->audio_rate = (pvr_param_audio_layer == 2) ? + PVR_AUDIO_BITRATE_L2_384 : PVR_AUDIO_BITRATE_L1_384; + break; + case 416: + pvr->audio_rate = PVR_AUDIO_BITRATE_L1_416; + break; + case 448: + pvr->audio_rate = PVR_AUDIO_BITRATE_L1_448; + break; + default: + break; + } + } + + /* -pvr amode=x */ + if (pvr_param_audio_mode) + { + if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_STEREO)) + pvr->audio_mode = PVR_AUDIO_MODE_STEREO; + else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_JOINT_STEREO)) + pvr->audio_mode = PVR_AUDIO_MODE_JOINT_STEREO; + else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_DUAL)) + pvr->audio_mode = PVR_AUDIO_MODE_DUAL; + else if (!strcmp (pvr_param_audio_mode, PVR_AUDIO_MODE_ARG_MONO)) + pvr->audio_mode = PVR_AUDIO_MODE_MONO; + else /* for anything else, set to stereo */ + pvr->audio_mode = PVR_AUDIO_MODE_STEREO; + } + + /* -pvr vbitrate=x */ + if (pvr_param_bitrate) + pvr->bitrate = pvr_param_bitrate; + + /* -pvr vmode=x */ + if (pvr_param_bitrate_mode) + { + if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_VBR)) + pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; + else if (!strcmp (pvr_param_bitrate_mode, PVR_VIDEO_BITRATE_MODE_ARG_CBR)) + pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_CBR; + else /* for anything else, set to VBR */ + pvr->bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; + } + + /* -pvr vpeak=x */ + if (pvr_param_bitrate_peak) + pvr->bitrate_peak = pvr_param_bitrate_peak; + + /* -pvr fmt=x */ + if (pvr_param_stream_type) + { + if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_PS)) + pvr->stream_type = IVTV_STREAM_PS; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_TS)) + pvr->stream_type = IVTV_STREAM_TS; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_MPEG1)) + pvr->stream_type = IVTV_STREAM_MPEG1; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD)) + pvr->stream_type = IVTV_STREAM_DVD; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_VCD)) + pvr->stream_type = IVTV_STREAM_VCD; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_SVCD)) + pvr->stream_type = IVTV_STREAM_SVCD; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S1)) + pvr->stream_type = IVTV_STREAM_DVD_S1; + else if (!strcmp (pvr_param_stream_type, PVR_VIDEO_STREAM_TYPE_DVD_S2)) + pvr->stream_type = IVTV_STREAM_DVD_S2; + else /* for anything else, set to MPEG PS */ + pvr->stream_type = IVTV_STREAM_PS; + } +} + +static int +set_ivtv_settings (struct pvr_t *pvr) +{ + struct ivtv_ioctl_codec codec; + + if (!pvr) + return -1; + + if (pvr->dev_fd < 0) + return -1; + + /* get current settings */ + if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno)); + return -1; + } + + /* set default encoding settings + * may be overlapped by user parameters + * Use VBR MPEG_PS encoding at 6 Mbps (peak at 9.6 Mbps) + * with 48 KHz L2 384 kbps audio. + */ + codec.aspect = PVR_ASPECT_RATIO_4_3; + codec.bitrate_mode = PVR_VIDEO_BITRATE_MODE_VBR; + codec.bitrate = 6000000; + codec.bitrate_peak = 9600000; + codec.stream_type = IVTV_STREAM_PS; + codec.audio_bitmask = PVR_AUDIO_LAYER_2 + | PVR_AUDIO_BITRATE_L2_384 | PVR_AUDIO_SAMPLE_RATE_48_KHZ; + + /* set aspect ratio */ + if (pvr->aspect != -1) + codec.aspect = pvr->aspect; + + /* if user value is given, we need to reset audio bitmask */ + if ((pvr->samplerate != -1) || (pvr->layer != -1) + || (pvr->audio_rate != -1) || (pvr->audio_mode != -1)) + codec.audio_bitmask = 0; + + /* set audio samplerate */ + if (pvr->samplerate != -1) + codec.audio_bitmask |= pvr->samplerate; + + /* set audio layer */ + if (pvr->layer != -1) + codec.audio_bitmask |= pvr->layer; + + /* set audio bitrate */ + if (pvr->audio_rate != -1) + codec.audio_bitmask |= pvr->audio_rate; + + /* set audio mode */ + if (pvr->audio_mode != -1) + codec.audio_bitmask |= pvr->audio_mode; + + /* set video bitrate */ + if (pvr->bitrate != -1) + codec.bitrate = pvr->bitrate; + + /* set video bitrate mode */ + if (pvr->bitrate_mode != -1) + codec.bitrate_mode = pvr->bitrate_mode; + + /* set video bitrate peak */ + if (pvr->bitrate != -1) + codec.bitrate_peak = pvr->bitrate_peak; + + /* set video stream type */ + if (pvr->stream_type != -1) + codec.stream_type = pvr->stream_type; + + /* set new encoding settings */ + if (ioctl (pvr->dev_fd, IVTV_IOC_S_CODEC, &codec) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set codec (%s).\n", LOG_LEVEL_IVTV, strerror (errno)); + return -1; + } + + return 0; +} + +/* V4L2 layer */ + +static void +parse_v4l2_tv_options (struct pvr_t *pvr) +{ + if (!pvr) + return; + + if (tv_param_device) + { + if (pvr->video_dev) + free (pvr->video_dev); + pvr->video_dev = strdup (tv_param_device); + } + + if (tv_param_noaudio) + pvr->mute = tv_param_noaudio; + + if (tv_param_input) + pvr->input = tv_param_input; + + if (tv_param_normid) + pvr->normid = tv_param_normid; + + if (tv_param_brightness) + pvr->brightness = tv_param_brightness; + + if (tv_param_contrast) + pvr->contrast = tv_param_contrast; + + if (tv_param_hue) + pvr->hue = tv_param_hue; + + if (tv_param_saturation) + pvr->saturation = tv_param_saturation; + + if (tv_param_width) + pvr->width = tv_param_width; + + if (tv_param_height) + pvr->height = tv_param_height; + + if (tv_param_freq) + pvr->freq = strdup (tv_param_freq); +} + +static int +set_v4l2_settings (struct pvr_t *pvr) +{ + if (!pvr) + return -1; + + if (pvr->dev_fd < 0) + return -1; + + /* -tv noaudio */ + if (pvr->mute) + { + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't mute (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + } + + /* -tv input=x */ + if (pvr->input != 0) + { + if (ioctl (pvr->dev_fd, VIDIOC_S_INPUT, &pvr->input) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set input (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + } + + /* -tv normid=x */ + if (pvr->normid != -1) + { + struct v4l2_standard std; + std.index = pvr->normid; + + if (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &std) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + + mp_msg (MSGT_OPEN, MSGL_V, + "%s set norm to %s\n", LOG_LEVEL_V4L2, std.name); + + if (ioctl (pvr->dev_fd, VIDIOC_S_STD, &std.id) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + } + + /* -tv brightness=x */ + if (pvr->brightness != 0) + { + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_BRIGHTNESS; + ctrl.value = pvr->brightness; + + if (ctrl.value < 0) + ctrl.value = 0; + if (ctrl.value > 255) + ctrl.value = 255; + + if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set brightness to %d (%s).\n", + LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); + return -1; + } + } + + /* -tv contrast=x */ + if (pvr->contrast != 0) + { + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_CONTRAST; + ctrl.value = pvr->contrast; + + if (ctrl.value < 0) + ctrl.value = 0; + if (ctrl.value > 127) + ctrl.value = 127; + + if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set contrast to %d (%s).\n", + LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); + return -1; + } + } + + /* -tv hue=x */ + if (pvr->hue != 0) + { + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_HUE; + ctrl.value = pvr->hue; + + if (ctrl.value < -128) + ctrl.value = -128; + if (ctrl.value > 127) + ctrl.value = 127; + + if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set hue to %d (%s).\n", + LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); + return -1; + } + } + + /* -tv saturation=x */ + if (pvr->saturation != 0) + { + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_SATURATION; + ctrl.value = pvr->saturation; + + if (ctrl.value < 0) + ctrl.value = 0; + if (ctrl.value > 127) + ctrl.value = 127; + + if (ioctl (pvr->dev_fd, VIDIOC_S_CTRL, &ctrl) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set saturation to %d (%s).\n", + LOG_LEVEL_V4L2, ctrl.value, strerror (errno)); + return -1; + } + } + + /* -tv width=x:height=y */ + if (pvr->width && pvr->height) + { + struct v4l2_format vfmt; + vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vfmt.fmt.pix.width = pvr->width; + vfmt.fmt.pix.height = pvr->height; + + if (ioctl (pvr->dev_fd, VIDIOC_S_FMT, &vfmt) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set resolution to %dx%d (%s).\n", + LOG_LEVEL_V4L2, pvr->width, pvr->height, strerror (errno)); + return -1; + } + } + + /* -tv freq=x */ + if (pvr->freq) + { + struct v4l2_frequency vf; + vf.tuner = 0; + vf.type = 0; + vf.frequency = strtol (pvr->freq, 0L, 0); + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s setting frequency to %d\n", LOG_LEVEL_V4L2, vf.frequency); + + if (ioctl (pvr->dev_fd, VIDIOC_S_FREQUENCY, &vf) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, "%s can't set frequency (%s).\n", + LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + } + + return 0; +} + +static int +v4l2_list_capabilities (struct pvr_t *pvr) +{ + struct v4l2_audio vaudio; + struct v4l2_standard vs; + struct v4l2_input vin; + int err = 0; + + if (!pvr) + return -1; + + if (pvr->dev_fd < 0) + return -1; + + /* list available video inputs */ + vin.index = 0; + err = 1; + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Available video inputs: ", LOG_LEVEL_V4L2); + while (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) >= 0) + { + err = 0; + mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vin.index, vin.name); + vin.index++; + } + if (err) + { + mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); + return -1; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); + + /* list available audio inputs */ + vaudio.index = 0; + err = 1; + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Available audio inputs: ", LOG_LEVEL_V4L2); + while (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) >= 0) + { + err = 0; + mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vaudio.index, vaudio.name); + vaudio.index++; + } + if (err) + { + mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); + return -1; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); + + /* list available norms */ + vs.index = 0; + mp_msg (MSGT_OPEN, MSGL_INFO, "%s Available norms: ", LOG_LEVEL_V4L2); + while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) + { + err = 0; + mp_msg (MSGT_OPEN, MSGL_INFO, "'#%d, %s' ", vs.index, vs.name); + vs.index++; + } + if (err) + { + mp_msg (MSGT_OPEN, MSGL_INFO, "none\n"); + return -1; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, "\n"); + + return 0; +} + +static int +v4l2_display_settings (struct pvr_t *pvr) +{ + struct v4l2_audio vaudio; + struct v4l2_standard vs; + struct v4l2_input vin; + v4l2_std_id std; + int input; + + if (!pvr) + return -1; + + if (pvr->dev_fd < 0) + return -1; + + /* get current video input */ + if (ioctl (pvr->dev_fd, VIDIOC_G_INPUT, &input) == 0) + { + vin.index = input; + if (ioctl (pvr->dev_fd, VIDIOC_ENUMINPUT, &vin) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Video input: %s\n", LOG_LEVEL_V4L2, vin.name); + } + else + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + + /* get current audio input */ + if (ioctl (pvr->dev_fd, VIDIOC_G_AUDIO, &vaudio) == 0) + { + vaudio.index = input; + if (ioctl (pvr->dev_fd, VIDIOC_ENUMAUDIO, &vaudio) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Audio input: %s\n", LOG_LEVEL_V4L2, vaudio.name); + } + else + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get input (%s).\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + + /* get current video format */ + if (ioctl (pvr->dev_fd, VIDIOC_G_STD, &std) == 0) + { + vs.index = 0; + + while (ioctl (pvr->dev_fd, VIDIOC_ENUMSTD, &vs) >= 0) + { + if (vs.id == std) + { + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Norm: %s.\n", LOG_LEVEL_V4L2, vs.name); + break; + } + vs.index++; + } + } + else + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get norm (%s)\n", LOG_LEVEL_V4L2, strerror (errno)); + return -1; + } + + return 0; +} + +/* stream layer */ + +static void +pvr_stream_close (stream_t *stream) +{ + struct pvr_t *pvr; + + if (!stream) + return; + + pvr = (struct pvr_t *) stream->priv; + pvr_uninit (pvr); +} + +static int +pvr_stream_read (stream_t *stream, char *buffer, int size) +{ + struct pollfd pfds[1]; + struct pvr_t *pvr; + int rk, fd, pos; + + if (!stream || !buffer) + return 0; + + pvr = (struct pvr_t *) stream->priv; + fd = pvr->dev_fd; + pos = 0; + + if (fd < 0) + return 0; + + while (pos < size) + { + pfds[0].fd = fd; + pfds[0].events = POLLIN | POLLPRI; + + rk = size - pos; + + if (poll (pfds, 1, 500) <= 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s failed with errno %d when reading %d bytes\n", + LOG_LEVEL_PVR, errno, size-pos); + break; + } + + rk = read (fd, &buffer[pos], rk); + if (rk > 0) + { + pos += rk; + mp_msg (MSGT_OPEN, MSGL_DBG3, + "%s read (%d) bytes\n", LOG_LEVEL_PVR, pos); + } + } + + if (!pos) + mp_msg (MSGT_OPEN, MSGL_ERR, "%s read %d bytes\n", LOG_LEVEL_PVR, pos); + + return pos; +} + +static int +pvr_stream_open (stream_t *stream, int mode, void *opts, int *file_format) +{ + struct ivtv_ioctl_codec codec; + struct ivtv_driver_info info; + struct v4l2_capability vcap; + struct pvr_t *pvr = NULL; + + if (mode != STREAM_READ) + return STREAM_UNSUPORTED; + + pvr = pvr_init (); + + parse_v4l2_tv_options (pvr); + parse_ivtv_options (pvr); + + /* open device */ + pvr->dev_fd = open (pvr->video_dev, O_RDWR); + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Using device %s\n", LOG_LEVEL_PVR, pvr->video_dev); + if (pvr->dev_fd == -1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s error opening device %s\n", LOG_LEVEL_PVR, pvr->video_dev); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + /* query capabilities (i.e test V4L2 support) */ + if (ioctl (pvr->dev_fd, VIDIOC_QUERYCAP, &vcap) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s device is not V4L2 compliant (%s).\n", + LOG_LEVEL_PVR, strerror (errno)); + pvr_uninit (pvr); + return STREAM_ERROR; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Detected %s\n", LOG_LEVEL_PVR, vcap.card); + + /* get codec and initialize card (i.e test IVTV support) */ + if (ioctl (pvr->dev_fd, IVTV_IOC_G_CODEC, &codec) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s device is not IVTV compliant (%s).\n", + LOG_LEVEL_PVR, strerror (errno)); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + /* get ivtv driver info */ + if (ioctl (pvr->dev_fd, IVTV_IOC_G_DRIVER_INFO, &info) < 0) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s device is not IVTV compliant (%s).\n", + LOG_LEVEL_PVR, strerror (errno)); + pvr_uninit (pvr); + return STREAM_ERROR; + } + else + mp_msg (MSGT_OPEN, MSGL_INFO, + "%s Detected ivtv driver: %s\n", LOG_LEVEL_PVR, info.comment); + + /* list V4L2 capabilities */ + if (v4l2_list_capabilities (pvr) == -1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get v4l2 capabilities\n", LOG_LEVEL_PVR); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + /* apply V4L2 settings */ + if (set_v4l2_settings (pvr) == -1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set v4l2 settings\n", LOG_LEVEL_PVR); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + /* apply IVTV settings */ + if (set_ivtv_settings (pvr) == -1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't set ivtv settings\n", LOG_LEVEL_PVR); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + /* display current V4L2 settings */ + if (v4l2_display_settings (pvr) == -1) + { + mp_msg (MSGT_OPEN, MSGL_ERR, + "%s can't get v4l2 settings\n", LOG_LEVEL_PVR); + pvr_uninit (pvr); + return STREAM_ERROR; + } + + stream->priv = pvr; + stream->type = STREAMTYPE_PVR; + stream->fill_buffer = pvr_stream_read; + stream->close = pvr_stream_close; + + return STREAM_OK; +} + +stream_info_t stream_info_pvr = { + "PVR (V4L2/IVTV) Input", + "pvr", + "Benjamin Zores", + "", + pvr_stream_open, + { "pvr", NULL }, + NULL, + 1 +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_rtsp.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2006 Benjamin Zores + * based on previous Real RTSP support from Roberto Togni and xine team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <ctype.h> +#include "config.h" +#ifndef HAVE_WINSOCK2 +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#define closesocket close +#else +#include <winsock2.h> +#include <ws2tcpip.h> +#endif +#include <errno.h> + +#include "stream.h" +#include "librtsp/rtsp.h" +#include "librtsp/rtsp_session.h" + +#define RTSP_DEFAULT_PORT 554 + +extern int network_bandwidth; + +static int +rtsp_streaming_read (int fd, char *buffer, + int size, streaming_ctrl_t *stream_ctrl) +{ + return rtsp_session_read (stream_ctrl->data, buffer, size); +} + +static int +rtsp_streaming_start (stream_t *stream) +{ + int fd; + rtsp_session_t *rtsp; + char *mrl; + char *file; + int port; + int redirected, temp; + + if (!stream) + return -1; + + /* counter so we don't get caught in infinite redirections */ + temp = 5; + + do { + redirected = 0; + + fd = connect2Server (stream->streaming_ctrl->url->hostname, + port = (stream->streaming_ctrl->url->port ? + stream->streaming_ctrl->url->port : + RTSP_DEFAULT_PORT), 1); + + if (fd < 0 && !stream->streaming_ctrl->url->port) + fd = connect2Server (stream->streaming_ctrl->url->hostname, + port = 7070, 1); + + if (fd < 0) + return -1; + + file = stream->streaming_ctrl->url->file; + if (file[0] == '/') + file++; + + mrl = malloc (strlen (stream->streaming_ctrl->url->hostname) + + strlen (file) + 16); + + sprintf (mrl, "rtsp://%s:%i/%s", + stream->streaming_ctrl->url->hostname, port, file); + + rtsp = rtsp_session_start (fd, &mrl, file, + stream->streaming_ctrl->url->hostname, + port, &redirected, + stream->streaming_ctrl->bandwidth); + + if (redirected == 1) + { + url_free (stream->streaming_ctrl->url); + stream->streaming_ctrl->url = url_new (mrl); + closesocket (fd); + } + + free (mrl); + temp--; + } while ((redirected != 0) && (temp > 0)); + + if (!rtsp) + return -1; + + stream->fd = fd; + stream->streaming_ctrl->data = rtsp; + + stream->streaming_ctrl->streaming_read = rtsp_streaming_read; + stream->streaming_ctrl->streaming_seek = NULL; + stream->streaming_ctrl->prebuffer_size = 128*1024; // 640 KBytes + stream->streaming_ctrl->buffering = 1; + stream->streaming_ctrl->status = streaming_playing_e; + + return 0; +} + +static void +rtsp_streaming_close (struct stream_st *s) +{ + rtsp_session_t *rtsp = NULL; + + rtsp = (rtsp_session_t *) s->streaming_ctrl->data; + if (rtsp) + rtsp_session_end (rtsp); +} + +static int +rtsp_streaming_open (stream_t *stream, int mode, void *opts, int *file_format) +{ + URL_t *url; + extern int index_mode; + + mp_msg (MSGT_OPEN, MSGL_INFO, "STREAM_RTSP, URL: %s\n", stream->url); + stream->streaming_ctrl = streaming_ctrl_new (); + if (!stream->streaming_ctrl) + return STREAM_ERROR; + + stream->streaming_ctrl->bandwidth = network_bandwidth; + url = url_new (stream->url); + stream->streaming_ctrl->url = check4proxies (url); + + stream->fd = -1; + index_mode = -1; /* prevent most RTSP streams from locking due to -idx */ + if (rtsp_streaming_start (stream) < 0) + { + streaming_ctrl_free (stream->streaming_ctrl); + stream->streaming_ctrl = NULL; + return STREAM_UNSUPORTED; + } + + fixup_network_stream_cache (stream); + stream->type = STREAMTYPE_STREAM; + stream->close = rtsp_streaming_close; + + return STREAM_OK; +} + +stream_info_t stream_info_rtsp = { + "RTSP streaming", + "rtsp", + "Benjamin Zores, Roberto Togni", + "ported from xine", + rtsp_streaming_open, + {"rtsp", NULL}, + NULL, + 0 /* Urls are an option string */ +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_smb.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,148 @@ + +#include "config.h" + +#include <libsmbclient.h> +#include <unistd.h> + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +static struct stream_priv_s { +} stream_priv_dflts = { +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +// URL definition +static m_option_t stream_opts_fields[] = { + { NULL, NULL, 0, 0, 0, 0, NULL } +}; + +static struct m_struct_st stream_opts = { + "smb", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +static char smb_password[15]; +static char smb_username[15]; + +static void smb_auth_fn(const char *server, const char *share, + char *workgroup, int wgmaxlen, char *username, int unmaxlen, + char *password, int pwmaxlen) +{ + char temp[128]; + + strcpy(temp, "LAN"); + if (temp[strlen(temp) - 1] == 0x0a) + temp[strlen(temp) - 1] = 0x00; + + if (temp[0]) strncpy(workgroup, temp, wgmaxlen - 1); + + strcpy(temp, smb_username); + if (temp[strlen(temp) - 1] == 0x0a) + temp[strlen(temp) - 1] = 0x00; + + if (temp[0]) strncpy(username, temp, unmaxlen - 1); + + strcpy(temp, smb_password); + if (temp[strlen(temp) - 1] == 0x0a) + temp[strlen(temp) - 1] = 0x00; + + if (temp[0]) strncpy(password, temp, pwmaxlen - 1); +} + +static int seek(stream_t *s,off_t newpos) { + s->pos = newpos; + if(smbc_lseek(s->fd,s->pos,SEEK_SET)<0) { + s->eof=1; + return 0; + } + return 1; +} + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + int r = smbc_read(s->fd,buffer,max_len); + return (r <= 0) ? -1 : r; +} + +static int write_buffer(stream_t *s, char* buffer, int len) { + int r = smbc_write(s->fd,buffer,len); + return (r <= 0) ? -1 : r; +} + +static void close_f(stream_t *s){ + smbc_close(s->fd); +} + +static int open_f (stream_t *stream, int mode, void *opts, int* file_format) { + struct stream_priv_s *p = (struct stream_priv_s*)opts; + char *filename; + mode_t m = 0; + off_t len; + int fd, err; + + filename = stream->url; + + if(mode == STREAM_READ) + m = O_RDONLY; + else if (mode == STREAM_WRITE) //who's gonna do that ? + m = O_WRONLY; + else { + mp_msg(MSGT_OPEN, MSGL_ERR, "[smb] Unknown open mode %d\n", mode); + m_struct_free (&stream_opts, opts); + return STREAM_UNSUPORTED; + } + + if(!filename) { + mp_msg(MSGT_OPEN,MSGL_ERR, "[smb] Bad url\n"); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + err = smbc_init(smb_auth_fn, 1); + if (err < 0) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_SMBInitError,err); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + fd = smbc_open(filename, m,0644); + if (fd < 0) { + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_SMBFileNotFound, filename); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + len = smbc_lseek(fd,0,SEEK_END); + smbc_lseek (fd, 0, SEEK_SET); + if (len <= 0) + stream->flags = 0; + else { + stream->flags = STREAM_READ | STREAM_SEEK; + stream->end_pos = len; + stream->seek = seek; + } + stream->type = STREAMTYPE_SMB; + stream->fd = fd; + stream->fill_buffer = fill_buffer; + stream->write_buffer = write_buffer; + stream->close = close_f; + + m_struct_free(&stream_opts, opts); + return STREAM_OK; +} + +stream_info_t stream_info_smb = { + "Server Message Block", + "smb", + "M. Tourne", + "based on the code from 'a bulgarian' (one says)", + open_f, + {"smb", NULL}, + &stream_opts, + 0 //Url is an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_vcd.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,152 @@ + +#include "config.h" + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> + +#if defined(__FreeBSD__) || defined(__DragonFly__) +#include <sys/cdrio.h> +#include "vcd_read_fbsd.h" +#elif defined(__NetBSD__) || defined (__OpenBSD__) +#include "vcd_read_nbsd.h" +#elif defined(SYS_DARWIN) +#include "vcd_read_darwin.h" +#else +#include "vcd_read.h" +#endif + +extern char *cdrom_device; + +static struct stream_priv_s { + int track; + char* device; +} stream_priv_dflts = { + 1, + NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + { "track", ST_OFF(track), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, + { "device", ST_OFF(device), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + /// For url parsing + { "hostname", ST_OFF(track), CONF_TYPE_INT, M_OPT_MIN, 1, 0, NULL }, + { "filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; +static struct m_struct_st stream_opts = { + "vcd", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + if(s->pos > s->end_pos) /// don't past end of current track + return 0; + return vcd_read(s->priv,buffer); +} + +static int seek(stream_t *s,off_t newpos) { + s->pos = newpos; + vcd_set_msf(s->priv,s->pos/VCD_SECTOR_DATA); + return 1; +} + +static void close_s(stream_t *stream) { + free(stream->priv); +} + +static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { + struct stream_priv_s* p = (struct stream_priv_s*)opts; + int ret,ret2,f; + mp_vcd_priv_t* vcd; +#ifdef __FreeBSD__ + int bsize = VCD_SECTOR_SIZE; +#endif + + if(mode != STREAM_READ) { + m_struct_free(&stream_opts,opts); + return STREAM_UNSUPORTED; + } + + if (!p->device) { + if(cdrom_device) + p->device = strdup(cdrom_device); + else + p->device = strdup(DEFAULT_CDROM_DEVICE); + } + + f=open(p->device,O_RDONLY); + if(f<0){ + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_CdDevNotfound,p->device); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + + vcd = vcd_read_toc(f); + if(!vcd) { + mp_msg(MSGT_OPEN,MSGL_ERR,"Failed to get cd toc\n"); + close(f); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + ret2=vcd_get_track_end(vcd,p->track); + if(ret2<0){ + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (get)\n"); + close(f); + free(vcd); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + ret=vcd_seek_to_track(vcd,p->track); + if(ret<0){ + mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_ErrTrackSelect " (seek)\n"); + close(f); + free(vcd); + m_struct_free(&stream_opts,opts); + return STREAM_ERROR; + } + mp_msg(MSGT_OPEN,MSGL_V,"VCD start byte position: 0x%X end: 0x%X\n",ret,ret2); + +#ifdef __FreeBSD__ + if (ioctl (f, CDRIOCSETBLOCKSIZE, &bsize) == -1) { + mp_msg(MSGT_OPEN,MSGL_WARN,"Error in CDRIOCSETBLOCKSIZE"); + } +#endif + + stream->fd = f; + stream->type = STREAMTYPE_VCD; + stream->sector_size = VCD_SECTOR_DATA; + stream->start_pos=ret; + stream->end_pos=ret2; + stream->priv = vcd; + + stream->fill_buffer = fill_buffer; + stream->seek = seek; + stream->close = close_s; + + m_struct_free(&stream_opts,opts); + return STREAM_OK; +} + +stream_info_t stream_info_vcd = { + "Video CD", + "vcd", + "Albeu", + "based on the code from ???", + open_s, + { "vcd", NULL }, + &stream_opts, + 1 // Urls are an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/stream_vstream.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,180 @@ +/* + * stream_vstream.c + * + * Copyright (C) Joey Parrish + * + * This file is part of MPlayer, a free movie player. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + */ + +/* + * If you have a tivo with the vstream server installed, (and most tivo + * hackers do,) then you can connect to it and stream ty files using + * this module. The url syntax is tivo://host/fsid or tivo://host/list + * to list the available recordings and their fsid's. + * This module depends on libvstream-client, which is available from + * http://armory.nicewarrior.org/projects/vstream-client . + * + */ + + +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> + +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <errno.h> + +#include "mp_msg.h" +#include "stream.h" +#include "help_mp.h" +#include "m_option.h" +#include "m_struct.h" + +#include <vstream-client.h> + +void vstream_error(const char *format, ...) { + char buf[1024]; + va_list va; + va_start(va, format); + vsnprintf(buf, 1024, format, va); + va_end(va); + mp_msg(MSGT_STREAM, MSGL_ERR, buf); +} + +static struct stream_priv_s { + char* host; + char* fsid; +} stream_priv_dflts = { + NULL, + NULL +}; + +#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) +/// URL definition +static m_option_t stream_opts_fields[] = { + {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + {"filename", ST_OFF(fsid), CONF_TYPE_STRING, 0, 0 ,0, NULL}, + { NULL, NULL, 0, 0, 0, 0, NULL } +}; + +static struct m_struct_st stream_opts = { + "vstream", + sizeof(struct stream_priv_s), + &stream_priv_dflts, + stream_opts_fields +}; + +static int fill_buffer(stream_t *s, char* buffer, int max_len){ + struct stream_priv_s* p = (struct stream_priv_s*)s->priv; + int len = vstream_load_chunk(p->fsid, buffer, max_len, s->pos); + if (len <= 0) return 0; + return len; +} + +static int seek(stream_t *s,off_t newpos) { + s->pos = newpos; + return 1; +} + +static int control(struct stream_st *s,int cmd,void* arg) { + return STREAM_UNSUPORTED; +} + +static void close_s(struct stream_st *s) { +} + +static int open_s(stream_t *stream, int mode, void* opts, int* file_format) { + int f; + struct stream_priv_s* p = (struct stream_priv_s*)opts; + + if(mode != STREAM_READ) + return STREAM_UNSUPORTED; + + if(!p->host) { + mp_msg(MSGT_OPEN, MSGL_ERR, "We need a host name (ex: tivo://hostname/fsid)\n"); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + if(!p->fsid || strlen(p->fsid) == 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, "We need an fsid (ex: tivo://hostname/fsid)\n"); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + f = connect2Server(p->host, VSERVER_PORT, 1); + + if(f < 0) { + mp_msg(MSGT_OPEN, MSGL_ERR, "Connection to %s failed\n", p->host); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + stream->fd = f; + + vstream_set_socket_fd(f); + + if (!strcmp(p->fsid, "list")) { + vstream_list_streams(0); + return STREAM_ERROR; + } else if (!strcmp(p->fsid, "llist")) { + vstream_list_streams(1); + return STREAM_ERROR; + } + + if (vstream_start()) { + mp_msg(MSGT_OPEN, MSGL_ERR, "Cryptic internal error #1\n"); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + if (vstream_startstream(p->fsid)) { + mp_msg(MSGT_OPEN, MSGL_ERR, "Cryptic internal error #2\n"); + m_struct_free(&stream_opts, opts); + return STREAM_ERROR; + } + + stream->start_pos = 0; + stream->end_pos = vstream_streamsize(); + mp_msg(MSGT_OPEN, MSGL_DBG2, "Tivo stream size is %d\n", stream->end_pos); + + stream->priv = p; + stream->fill_buffer = fill_buffer; + stream->control = control; + stream->seek = seek; + stream->close = close_s; + stream->type = STREAMTYPE_VSTREAM; + + return STREAM_OK; +} + +stream_info_t stream_info_vstream = { + "vstream client", + "vstream", + "Joey", + "", + open_s, + { "tivo", NULL }, + &stream_opts, + 1 // Url is an option string +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tv.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,919 @@ +/* + TV Interface for MPlayer + + (C) Alex Beregszaszi + + API idea based on libvo2 + + Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu) + to add support for audio, and bktr *BSD support. + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/time.h> + +#include "config.h" + +int tv_param_on = 0; + +#include "mp_msg.h" +#include "help_mp.h" + +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" + +#include "libaf/af_format.h" +#include "libvo/img_format.h" +#include "libvo/fastmemcpy.h" + +#include "tv.h" + +#include "frequencies.h" + +/* some default values */ +int tv_param_audiorate = 44100; +int tv_param_noaudio = 0; +int tv_param_immediate = 0; +char *tv_param_freq = NULL; +char *tv_param_channel = NULL; +char *tv_param_norm = "pal"; +#ifdef HAVE_TV_V4L2 +int tv_param_normid = -1; +#endif +char *tv_param_chanlist = "europe-east"; +char *tv_param_device = NULL; +char *tv_param_driver = "dummy"; +int tv_param_width = -1; +int tv_param_height = -1; +int tv_param_input = 0; /* used in v4l and bttv */ +int tv_param_outfmt = -1; +float tv_param_fps = -1.0; +char **tv_param_channels = NULL; +int tv_param_audio_id = 0; +#if defined(HAVE_TV_V4L) +int tv_param_amode = -1; +int tv_param_volume = -1; +int tv_param_bass = -1; +int tv_param_treble = -1; +int tv_param_balance = -1; +int tv_param_forcechan = -1; +int tv_param_force_audio = 0; +int tv_param_buffer_size = -1; +int tv_param_mjpeg = 0; +int tv_param_decimation = 2; +int tv_param_quality = 90; +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) +int tv_param_alsa = 0; +#endif +char* tv_param_adevice = NULL; +#endif +int tv_param_brightness = 0; +int tv_param_contrast = 0; +int tv_param_hue = 0; +int tv_param_saturation = 0; +tv_channels_t *tv_channel_list; +tv_channels_t *tv_channel_current, *tv_channel_last; +char *tv_channel_last_real; + +/* ================== DEMUX_TV ===================== */ +/* + Return value: + 0 = EOF(?) or no stream + 1 = successfully read a packet +*/ +/* fill demux->video and demux->audio */ + +static int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds) +{ + tvi_handle_t *tvh=(tvi_handle_t*)(demux->priv); + demux_packet_t* dp; + unsigned int len=0; + + /* ================== ADD AUDIO PACKET =================== */ + + if (ds==demux->audio && tv_param_noaudio == 0 && + tvh->functions->control(tvh->priv, + TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) + { + len = tvh->functions->get_audio_framesize(tvh->priv); + + dp=new_demux_packet(len); + dp->flags|=1; /* Keyframe */ + dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len); + ds_add_packet(demux->audio,dp); + } + + /* ================== ADD VIDEO PACKET =================== */ + + if (ds==demux->video && tvh->functions->control(tvh->priv, + TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE) + { + len = tvh->functions->get_video_framesize(tvh->priv); + dp=new_demux_packet(len); + dp->flags|=1; /* Keyframe */ + dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len); + ds_add_packet(demux->video,dp); + } + + return 1; +} + +static int norm_from_string(tvi_handle_t *tvh, char* norm) +{ +#ifdef HAVE_TV_V4L2 + if (strcmp(tv_param_driver, "v4l2") != 0) { +#endif + if (!strcasecmp(norm, "pal")) + return TV_NORM_PAL; + else if (!strcasecmp(norm, "ntsc")) + return TV_NORM_NTSC; + else if (!strcasecmp(norm, "secam")) + return TV_NORM_SECAM; + else if (!strcasecmp(norm, "palnc")) + return TV_NORM_PALNC; + else if (!strcasecmp(norm, "palm")) + return TV_NORM_PALM; + else if (!strcasecmp(norm, "paln")) + return TV_NORM_PALN; + else if (!strcasecmp(norm, "ntscjp")) + return TV_NORM_NTSCJP; + else { + mp_msg(MSGT_TV, MSGL_V, "tv.c: norm_from_string(%s): Bogus norm parameter, setting PAL.\n", norm); + return TV_NORM_PAL; + } +#ifdef HAVE_TV_V4L2 + } else { + tvi_functions_t *funcs = tvh->functions; + char str[8]; + strncpy(str, norm, sizeof(str)-1); + str[sizeof(str)-1] = '\0'; + if (funcs->control(tvh->priv, TVI_CONTROL_SPC_GET_NORMID, str) != TVI_CONTROL_TRUE) + return 0; + return *(int *)str; + } +#endif +} + +static int open_tv(tvi_handle_t *tvh) +{ + int i; + tvi_functions_t *funcs = tvh->functions; + int tv_fmt_list[] = { + IMGFMT_YV12, + IMGFMT_I420, + IMGFMT_UYVY, + IMGFMT_YUY2, + IMGFMT_RGB32, + IMGFMT_RGB24, + IMGFMT_RGB16, + IMGFMT_RGB15 + }; + + if (funcs->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) != TVI_CONTROL_TRUE) + { + mp_msg(MSGT_TV, MSGL_ERR, "Error: No video input present!\n"); + return 0; + } + + if (tv_param_outfmt == -1) + for (i = 0; i < sizeof (tv_fmt_list) / sizeof (*tv_fmt_list); i++) + { + tv_param_outfmt = tv_fmt_list[i]; + if (funcs->control (tvh->priv, TVI_CONTROL_VID_SET_FORMAT, + &tv_param_outfmt) == TVI_CONTROL_TRUE) + break; + } + else + { + switch(tv_param_outfmt) + { + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_UYVY: + case IMGFMT_YUY2: + case IMGFMT_RGB32: + case IMGFMT_RGB24: + case IMGFMT_BGR32: + case IMGFMT_BGR24: + case IMGFMT_BGR16: + case IMGFMT_BGR15: + break; + default: + mp_msg(MSGT_TV, MSGL_ERR, "==================================================================\n"); + mp_msg(MSGT_TV, MSGL_ERR, " WARNING: UNTESTED OR UNKNOWN OUTPUT IMAGE FORMAT REQUESTED (0x%x)\n", tv_param_outfmt); + mp_msg(MSGT_TV, MSGL_ERR, " This may cause buggy playback or program crash! Bug reports will\n"); + mp_msg(MSGT_TV, MSGL_ERR, " be ignored! You should try again with YV12 (which is the default\n"); + mp_msg(MSGT_TV, MSGL_ERR, " colorspace) and read the documentation!\n"); + mp_msg(MSGT_TV, MSGL_ERR, "==================================================================\n"); + } + funcs->control(tvh->priv, TVI_CONTROL_VID_SET_FORMAT, &tv_param_outfmt); + } + + /* set some params got from cmdline */ + funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tv_param_input); + +#ifdef HAVE_TV_V4L2 + if (!strcmp(tv_param_driver, "v4l2") && tv_param_normid >= 0) { + mp_msg(MSGT_TV, MSGL_V, "Selected norm id: %d\n", tv_param_normid); + if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tv_param_normid) != TVI_CONTROL_TRUE) { + mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); + } + } else { +#endif + /* select video norm */ + tvh->norm = norm_from_string(tvh, tv_param_norm); + + mp_msg(MSGT_TV, MSGL_V, "Selected norm: %s\n", tv_param_norm); + if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { + mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); + } +#ifdef HAVE_TV_V4L2 + } +#endif + +#ifdef HAVE_TV_V4L1 + if ( tv_param_mjpeg ) + { + /* set width to expected value */ + if (tv_param_width == -1) + { + tv_param_width = 704/tv_param_decimation; + } + if (tv_param_height == -1) + { + if ( tvh->norm != TV_NORM_NTSC ) + tv_param_height = 576/tv_param_decimation; + else + tv_param_height = 480/tv_param_decimation; + } + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: width %d height %d\n", tv_param_width, tv_param_height); + } +#endif + + /* limits on w&h are norm-dependent -- JM */ + /* set width */ + if (tv_param_width != -1) + { + if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_WIDTH, &tv_param_width) == TVI_CONTROL_TRUE) + funcs->control(tvh->priv, TVI_CONTROL_VID_SET_WIDTH, &tv_param_width); + else + { + mp_msg(MSGT_TV, MSGL_ERR, "Unable to set requested width: %d\n", tv_param_width); + funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &tv_param_width); + } + } + + /* set height */ + if (tv_param_height != -1) + { + if (funcs->control(tvh->priv, TVI_CONTROL_VID_CHK_HEIGHT, &tv_param_height) == TVI_CONTROL_TRUE) + funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HEIGHT, &tv_param_height); + else + { + mp_msg(MSGT_TV, MSGL_ERR, "Unable to set requested height: %d\n", tv_param_height); + funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &tv_param_height); + } + } + + if (funcs->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) != TVI_CONTROL_TRUE) + { + mp_msg(MSGT_TV, MSGL_WARN, "Selected input hasn't got a tuner!\n"); + goto done; + } + + /* select channel list */ + for (i = 0; chanlists[i].name != NULL; i++) + { + if (!strcasecmp(chanlists[i].name, tv_param_chanlist)) + { + tvh->chanlist = i; + tvh->chanlist_s = chanlists[i].list; + break; + } + } + + if (tvh->chanlist == -1) + mp_msg(MSGT_TV, MSGL_WARN, "Unable to find selected channel list! (%s)\n", + tv_param_chanlist); + else + mp_msg(MSGT_TV, MSGL_V, "Selected channel list: %s (including %d channels)\n", + chanlists[tvh->chanlist].name, chanlists[tvh->chanlist].count); + + if (tv_param_freq && tv_param_channel) + { + mp_msg(MSGT_TV, MSGL_WARN, "You can't set frequency and channel simultaneously!\n"); + goto done; + } + + /* Handle channel names */ + if (tv_param_channels) { + char** channels = tv_param_channels; + mp_msg(MSGT_TV, MSGL_INFO, "TV channel names detected.\n"); + tv_channel_list = malloc(sizeof(tv_channels_t)); + tv_channel_list->index=1; + tv_channel_list->next=NULL; + tv_channel_list->prev=NULL; + tv_channel_current = tv_channel_list; + + while (*channels) { + char* tmp = *(channels++); + char* sep = strchr(tmp,'-'); + int i; + struct CHANLIST cl; + + if (!sep) continue; // Wrong syntax, but mplayer should not crash + + strlcpy(tv_channel_current->name, sep + 1, + sizeof(tv_channel_current->name)); + sep[0] = '\0'; + strncpy(tv_channel_current->number, tmp, 5); + + while ((sep=strchr(tv_channel_current->name, '_'))) + sep[0] = ' '; + + tv_channel_current->freq = 0; + for (i = 0; i < chanlists[tvh->chanlist].count; i++) { + cl = tvh->chanlist_s[i]; + if (!strcasecmp(cl.name, tv_channel_current->number)) { + tv_channel_current->freq=cl.freq; + break; + } + } + if (tv_channel_current->freq == 0) + mp_msg(MSGT_TV, MSGL_ERR, "Couldn't find frequency for channel %s (%s)\n", + tv_channel_current->number, tv_channel_current->name); + else { + sep = strchr(tv_channel_current->name, '-'); + if ( !sep ) sep = strchr(tv_channel_current->name, '+'); + + if ( sep ) { + i = atoi (sep+1); + if ( sep[0] == '+' ) tv_channel_current->freq += i * 100; + if ( sep[0] == '-' ) tv_channel_current->freq -= i * 100; + sep[0] = '\0'; + } + } + + /*mp_msg(MSGT_TV, MSGL_INFO, "-- Detected channel %s - %s (%5.3f)\n", + tv_channel_current->number, tv_channel_current->name, + (float)tv_channel_current->freq/1000);*/ + + tv_channel_current->next = malloc(sizeof(tv_channels_t)); + tv_channel_current->next->index = tv_channel_current->index + 1; + tv_channel_current->next->prev = tv_channel_current; + tv_channel_current->next->next = NULL; + tv_channel_current = tv_channel_current->next; + } + if (tv_channel_current->prev) + tv_channel_current->prev->next = NULL; + free(tv_channel_current); + } else + tv_channel_last_real = malloc(5); + + if (tv_channel_list) { + int i; + int channel = 0; + if (tv_param_channel) + { + if (isdigit(*tv_param_channel)) + /* if tv_param_channel begins with a digit interpret it as a number */ + channel = atoi(tv_param_channel); + else + { + /* if tv_param_channel does not begin with a digit + set the first channel that contains tv_param_channel in its name */ + + tv_channel_current = tv_channel_list; + while ( tv_channel_current ) { + if ( strstr(tv_channel_current->name, tv_param_channel) ) + break; + tv_channel_current = tv_channel_current->next; + } + if ( !tv_channel_current ) tv_channel_current = tv_channel_list; + } + } + else + channel = 1; + + if ( channel ) { + tv_channel_current = tv_channel_list; + for (i = 1; i < channel; i++) + if (tv_channel_current->next) + tv_channel_current = tv_channel_current->next; + } + + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, + tv_channel_current->name, (float)tv_channel_current->freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); + tv_channel_last = tv_channel_current; + } else { + /* we need to set frequency */ + if (tv_param_freq) + { + unsigned long freq = atof(tv_param_freq)*16; + + /* set freq in MHz */ + funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); + + funcs->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); + mp_msg(MSGT_TV, MSGL_V, "Selected frequency: %lu (%.3f)\n", + freq, (float)freq/16); + } + + if (tv_param_channel) { + struct CHANLIST cl; + + mp_msg(MSGT_TV, MSGL_V, "Requested channel: %s\n", tv_param_channel); + for (i = 0; i < chanlists[tvh->chanlist].count; i++) + { + cl = tvh->chanlist_s[i]; + // printf("count%d: name: %s, freq: %d\n", + // i, cl.name, cl.freq); + if (!strcasecmp(cl.name, tv_param_channel)) + { + strcpy(tv_channel_last_real, cl.name); + tvh->channel = i; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", + cl.name, (float)cl.freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); + break; + } + } + } + } + + /* grep frequency in chanlist */ + { + unsigned long i2; + int freq; + + tv_get_freq(tvh, &i2); + + freq = (int) (((float)(i2/16))*1000)+250; + + for (i = 0; i < chanlists[tvh->chanlist].count; i++) + { + if (tvh->chanlist_s[i].freq == freq) + { + tvh->channel = i+1; + break; + } + } + } + +done: + /* also start device! */ + return 1; +} + +static demuxer_t* demux_open_tv(demuxer_t *demuxer) +{ + tvi_handle_t *tvh; + sh_video_t *sh_video; + sh_audio_t *sh_audio = NULL; + tvi_functions_t *funcs; + + if(!(tvh=tv_begin())) return NULL; + if (!tv_init(tvh)) return NULL; + if (!open_tv(tvh)){ + tv_uninit(tvh); + return NULL; + } + funcs = tvh->functions; + demuxer->priv=tvh; + + sh_video = new_sh_video(demuxer, 0); + + /* get IMAGE FORMAT */ + funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &sh_video->format); +// if (IMGFMT_IS_RGB(sh_video->format) || IMGFMT_IS_BGR(sh_video->format)) +// sh_video->format = 0x0; + + /* set FPS and FRAMETIME */ + + if(!sh_video->fps) + { + float tmp; + if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE) + sh_video->fps = 25.0f; /* on PAL */ + else sh_video->fps = tmp; + } + + if (tv_param_fps != -1.0f) + sh_video->fps = tv_param_fps; + + sh_video->frametime = 1.0f/sh_video->fps; + + /* If playback only mode, go to immediate mode, fail silently */ + if(tv_param_immediate == 1) + { + funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0); + tv_param_noaudio = 1; + } + + /* disable TV audio if -nosound is present */ + if (!demuxer->audio || demuxer->audio->id == -2) { + tv_param_noaudio = 1; + } + + /* set width */ + funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w); + + /* set height */ + funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h); + + demuxer->video->sh = sh_video; + sh_video->ds = demuxer->video; + demuxer->video->id = 0; + demuxer->seekable = 0; + + /* here comes audio init */ + if (tv_param_noaudio == 0 && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) + { + int audio_format; + int sh_audio_format; + char buf[128]; + + /* yeah, audio is present */ + + funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, + &tv_param_audiorate); + + if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE) + goto no_audio; + + switch(audio_format) + { + case AF_FORMAT_U8: + case AF_FORMAT_S8: + case AF_FORMAT_U16_LE: + case AF_FORMAT_U16_BE: + case AF_FORMAT_S16_LE: + case AF_FORMAT_S16_BE: + case AF_FORMAT_S32_LE: + case AF_FORMAT_S32_BE: + sh_audio_format = 0x1; /* PCM */ + break; + case AF_FORMAT_IMA_ADPCM: + case AF_FORMAT_MU_LAW: + case AF_FORMAT_A_LAW: + case AF_FORMAT_MPEG2: + case AF_FORMAT_AC3: + default: + mp_msg(MSGT_TV, MSGL_ERR, "Audio type '%s (%x)' unsupported!\n", + af_fmt2str(audio_format, buf, 128), audio_format); + goto no_audio; + } + + sh_audio = new_sh_audio(demuxer, 0); + + funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, + &sh_audio->samplerate); + funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE, + &sh_audio->samplesize); + funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, + &sh_audio->channels); + + sh_audio->format = sh_audio_format; + sh_audio->sample_format = audio_format; + + sh_audio->i_bps = sh_audio->o_bps = + sh_audio->samplerate * sh_audio->samplesize * + sh_audio->channels; + + // emulate WF for win32 codecs: + sh_audio->wf = malloc(sizeof(WAVEFORMATEX)); + sh_audio->wf->wFormatTag = sh_audio->format; + sh_audio->wf->nChannels = sh_audio->channels; + sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8; + sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; + sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels; + sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps; + + mp_msg(MSGT_DECVIDEO, MSGL_V, " TV audio: %d channels, %d bits, %d Hz\n", + sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample, + sh_audio->wf->nSamplesPerSec); + + demuxer->audio->sh = sh_audio; + sh_audio->ds = demuxer->audio; + demuxer->audio->id = 0; + } +no_audio: + + if(!(funcs->start(tvh->priv))){ + // start failed :( + tv_uninit(tvh); + return NULL; + } + + /* set color eq */ + tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tv_param_brightness); + tv_set_color_options(tvh, TV_COLOR_HUE, tv_param_hue); + tv_set_color_options(tvh, TV_COLOR_SATURATION, tv_param_saturation); + tv_set_color_options(tvh, TV_COLOR_CONTRAST, tv_param_contrast); + + return demuxer; +} + +static void demux_close_tv(demuxer_t *demuxer) +{ + tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv); + tvh->functions->uninit(tvh->priv); +} + +/* ================== STREAM_TV ===================== */ +tvi_handle_t *tvi_init_dummy(char *device); +tvi_handle_t *tvi_init_v4l(char *device, char *adevice); +tvi_handle_t *tvi_init_v4l2(char *device, char *adevice); +tvi_handle_t *tvi_init_bsdbt848(char *device); + +tvi_handle_t *tv_begin(void) +{ + if (!strcmp(tv_param_driver, "dummy")) + return tvi_init_dummy(tv_param_device); +#ifdef HAVE_TV_V4L1 + if (!strcmp(tv_param_driver, "v4l")) + return tvi_init_v4l(tv_param_device, tv_param_adevice); +#endif +#ifdef HAVE_TV_V4L2 + if (!strcmp(tv_param_driver, "v4l2")) + return tvi_init_v4l2(tv_param_device, tv_param_adevice); +#endif +#ifdef HAVE_TV_BSDBT848 + if (!strcmp(tv_param_driver, "bsdbt848")) + return tvi_init_bsdbt848(tv_param_device); +#endif + + mp_msg(MSGT_TV, MSGL_ERR, "No such driver: %s\n", tv_param_driver); + return(NULL); +} + +int tv_init(tvi_handle_t *tvh) +{ + mp_msg(MSGT_TV, MSGL_INFO, "Selected driver: %s\n", tvh->info->short_name); + mp_msg(MSGT_TV, MSGL_INFO, " name: %s\n", tvh->info->name); + mp_msg(MSGT_TV, MSGL_INFO, " author: %s\n", tvh->info->author); + if (tvh->info->comment) + mp_msg(MSGT_TV, MSGL_INFO, " comment: %s\n", tvh->info->comment); + + return(tvh->functions->init(tvh->priv)); +} + +int tv_uninit(tvi_handle_t *tvh) +{ + return(tvh->functions->uninit(tvh->priv)); +} + +/* utilities for mplayer (not mencoder!!) */ +int tv_set_color_options(tvi_handle_t *tvh, int opt, int value) +{ + tvi_functions_t *funcs = tvh->functions; + + switch(opt) + { + case TV_COLOR_BRIGHTNESS: + return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_BRIGHTNESS, &value); + case TV_COLOR_HUE: + return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_HUE, &value); + case TV_COLOR_SATURATION: + return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_SATURATION, &value); + case TV_COLOR_CONTRAST: + return funcs->control(tvh->priv, TVI_CONTROL_VID_SET_CONTRAST, &value); + default: + mp_msg(MSGT_TV, MSGL_WARN, "Unknown color option (%d) specified!\n", opt); + } + + return(TVI_CONTROL_UNKNOWN); +} + +int tv_get_color_options(tvi_handle_t *tvh, int opt, int* value) +{ + tvi_functions_t *funcs = tvh->functions; + + switch(opt) + { + case TV_COLOR_BRIGHTNESS: + return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_BRIGHTNESS, value); + case TV_COLOR_HUE: + return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HUE, value); + case TV_COLOR_SATURATION: + return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_SATURATION, value); + case TV_COLOR_CONTRAST: + return funcs->control(tvh->priv, TVI_CONTROL_VID_GET_CONTRAST, value); + default: + mp_msg(MSGT_TV, MSGL_WARN, "Unknown color option (%d) specified!\n", opt); + } + + return(TVI_CONTROL_UNKNOWN); +} + +int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq) +{ + if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) + { + tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, freq); + mp_msg(MSGT_TV, MSGL_V, "Current frequency: %lu (%.3f)\n", + *freq, (float)*freq/16); + } + return(1); +} + +int tv_set_freq(tvi_handle_t *tvh, unsigned long freq) +{ + if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_TUNER, 0) == TVI_CONTROL_TRUE) + { +// unsigned long freq = atof(tv_param_freq)*16; + + /* set freq in MHz */ + tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); + + tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &freq); + mp_msg(MSGT_TV, MSGL_V, "Current frequency: %lu (%.3f)\n", + freq, (float)freq/16); + } + return(1); +} + +int tv_step_channel_real(tvi_handle_t *tvh, int direction) +{ + struct CHANLIST cl; + + if (direction == TV_CHANNEL_LOWER) + { + if (tvh->channel-1 >= 0) + { + strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); + cl = tvh->chanlist_s[--tvh->channel]; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", + cl.name, (float)cl.freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); + } + } + + if (direction == TV_CHANNEL_HIGHER) + { + if (tvh->channel+1 < chanlists[tvh->chanlist].count) + { + strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); + cl = tvh->chanlist_s[++tvh->channel]; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", + cl.name, (float)cl.freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); + } + } + return(1); +} + +int tv_step_channel(tvi_handle_t *tvh, int direction) { + if (tv_channel_list) { + if (direction == TV_CHANNEL_HIGHER) { + tv_channel_last = tv_channel_current; + if (tv_channel_current->next) + tv_channel_current = tv_channel_current->next; + else + tv_channel_current = tv_channel_list; + tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", + tv_channel_current->number, tv_channel_current->name, (float)tv_channel_current->freq/1000); + } + if (direction == TV_CHANNEL_LOWER) { + tv_channel_last = tv_channel_current; + if (tv_channel_current->prev) + tv_channel_current = tv_channel_current->prev; + else + while (tv_channel_current->next) + tv_channel_current = tv_channel_current->next; + tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", + tv_channel_current->number, tv_channel_current->name, (float)tv_channel_current->freq/1000); + } + } else tv_step_channel_real(tvh, direction); + return(1); +} + +int tv_set_channel_real(tvi_handle_t *tvh, char *channel) { + int i; + struct CHANLIST cl; + + strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); + for (i = 0; i < chanlists[tvh->chanlist].count; i++) + { + cl = tvh->chanlist_s[i]; +// printf("count%d: name: %s, freq: %d\n", +// i, cl.name, cl.freq); + if (!strcasecmp(cl.name, channel)) + { + tvh->channel = i; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", + cl.name, (float)cl.freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); + break; + } + } + return(1); +} + +int tv_set_channel(tvi_handle_t *tvh, char *channel) { + int i, channel_int; + + if (tv_channel_list) { + tv_channel_last = tv_channel_current; + channel_int = atoi(channel); + tv_channel_current = tv_channel_list; + for (i = 1; i < channel_int; i++) + if (tv_channel_current->next) + tv_channel_current = tv_channel_current->next; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, + tv_channel_current->name, (float)tv_channel_current->freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); + } else tv_set_channel_real(tvh, channel); + return(1); +} + +int tv_last_channel(tvi_handle_t *tvh) { + + if (tv_channel_list) { + tv_channels_t *tmp; + + tmp = tv_channel_last; + tv_channel_last = tv_channel_current; + tv_channel_current = tmp; + + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s - %s (freq: %.3f)\n", tv_channel_current->number, + tv_channel_current->name, (float)tv_channel_current->freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); + } else { + int i; + struct CHANLIST cl; + + for (i = 0; i < chanlists[tvh->chanlist].count; i++) + { + cl = tvh->chanlist_s[i]; + if (!strcasecmp(cl.name, tv_channel_last_real)) + { + strcpy(tv_channel_last_real, tvh->chanlist_s[tvh->channel].name); + tvh->channel = i; + mp_msg(MSGT_TV, MSGL_INFO, "Selected channel: %s (freq: %.3f)\n", + cl.name, (float)cl.freq/1000); + tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); + break; + } + } + } + return(1); +} + +int tv_step_norm(tvi_handle_t *tvh) +{ + tvh->norm++; + if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, + &tvh->norm) != TVI_CONTROL_TRUE) { + tvh->norm = 0; + if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, + &tvh->norm) != TVI_CONTROL_TRUE) { + mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); + return 0; + } + } + return(1); +} + +int tv_step_chanlist(tvi_handle_t *tvh) +{ + return(1); +} + +int tv_set_norm(tvi_handle_t *tvh, char* norm) +{ + tvh->norm = norm_from_string(tvh, norm); + + mp_msg(MSGT_TV, MSGL_V, "Selected norm: %s\n", tv_param_norm); + if (tvh->functions->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) { + mp_msg(MSGT_TV, MSGL_ERR, "Error: Cannot set norm!\n"); + return 0; + } + return(1); +} + +demuxer_desc_t demuxer_desc_tv = { + "Tv card demuxer", + "tv", + "TV", + "Alex Beregszaszi, Charles R. Henrich", + "?", + DEMUXER_TYPE_TV, + 0, // no autodetect + NULL, + demux_tv_fill_buffer, + demux_open_tv, + demux_close_tv, + NULL, + NULL +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tv.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,200 @@ +#ifndef TV_H +#define TV_H + +extern int tv_param_on; + +#ifdef USE_TV +//#include "libao2/afmt.h" +//#include "libvo/img_format.h" +//#include "libvo/fastmemcpy.h" +//#include "mp_msg.h" + +extern char *tv_param_freq; +extern char *tv_param_channel; +extern char *tv_param_chanlist; +extern char *tv_param_norm; +#ifdef HAVE_TV_V4L2 +extern int tv_param_normid; +#endif +extern char *tv_param_device; +extern char *tv_param_driver; +extern int tv_param_width; +extern int tv_param_height; +extern int tv_param_input; +extern int tv_param_outfmt; +extern float tv_param_fps; +extern char **tv_param_channels; +extern int tv_param_noaudio; +extern int tv_param_immediate; +extern int tv_param_audiorate; +extern int tv_param_audio_id; +#if defined(HAVE_TV_V4L) +extern int tv_param_amode; +extern int tv_param_volume; +extern int tv_param_bass; +extern int tv_param_treble; +extern int tv_param_balance; +extern int tv_param_forcechan; +extern int tv_param_force_audio; +extern int tv_param_buffer_size; +extern int tv_param_mjpeg; +extern int tv_param_decimation; +extern int tv_param_quality; +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) +extern int tv_param_alsa; +#endif +extern char* tv_param_adevice; +#endif +extern int tv_param_brightness; +extern int tv_param_contrast; +extern int tv_param_hue; +extern int tv_param_saturation; + +typedef struct tvi_info_s +{ + const char *name; + const char *short_name; + const char *author; + const char *comment; +} tvi_info_t; + +typedef struct tvi_functions_s +{ + int (*init)(); + int (*uninit)(); + int (*control)(); + int (*start)(); + double (*grab_video_frame)(); +#ifdef HAVE_TV_BSDBT848 + double (*grabimmediate_video_frame)(); +#endif + int (*get_video_framesize)(); + double (*grab_audio_frame)(); + int (*get_audio_framesize)(); +} tvi_functions_t; + +typedef struct tvi_handle_s { + tvi_info_t *info; + tvi_functions_t *functions; + void *priv; + int seq; + + /* specific */ + int norm; + int chanlist; + const struct CHANLIST *chanlist_s; + int channel; +} tvi_handle_t; + +typedef struct tv_channels_s { + int index; + char number[5]; + char name[20]; + int freq; + struct tv_channels_s *next; + struct tv_channels_s *prev; +} tv_channels_t; + +extern tv_channels_t *tv_channel_list; +extern tv_channels_t *tv_channel_current, *tv_channel_last; +extern char *tv_channel_last_real; + +#define TVI_CONTROL_FALSE 0 +#define TVI_CONTROL_TRUE 1 +#define TVI_CONTROL_NA -1 +#define TVI_CONTROL_UNKNOWN -2 + +/* ======================== CONTROLS =========================== */ + +/* GENERIC controls */ +#define TVI_CONTROL_IS_AUDIO 0x1 +#define TVI_CONTROL_IS_VIDEO 0x2 +#define TVI_CONTROL_IS_TUNER 0x3 +#define TVI_CONTROL_IMMEDIATE 0x4 + +/* VIDEO controls */ +#define TVI_CONTROL_VID_GET_FPS 0x101 +#define TVI_CONTROL_VID_GET_PLANES 0x102 +#define TVI_CONTROL_VID_GET_BITS 0x103 +#define TVI_CONTROL_VID_CHK_BITS 0x104 +#define TVI_CONTROL_VID_SET_BITS 0x105 +#define TVI_CONTROL_VID_GET_FORMAT 0x106 +#define TVI_CONTROL_VID_CHK_FORMAT 0x107 +#define TVI_CONTROL_VID_SET_FORMAT 0x108 +#define TVI_CONTROL_VID_GET_WIDTH 0x109 +#define TVI_CONTROL_VID_CHK_WIDTH 0x110 +#define TVI_CONTROL_VID_SET_WIDTH 0x111 +#define TVI_CONTROL_VID_GET_HEIGHT 0x112 +#define TVI_CONTROL_VID_CHK_HEIGHT 0x113 +#define TVI_CONTROL_VID_SET_HEIGHT 0x114 +#define TVI_CONTROL_VID_GET_BRIGHTNESS 0x115 +#define TVI_CONTROL_VID_SET_BRIGHTNESS 0x116 +#define TVI_CONTROL_VID_GET_HUE 0x117 +#define TVI_CONTROL_VID_SET_HUE 0x118 +#define TVI_CONTROL_VID_GET_SATURATION 0x119 +#define TVI_CONTROL_VID_SET_SATURATION 0x11a +#define TVI_CONTROL_VID_GET_CONTRAST 0x11b +#define TVI_CONTROL_VID_SET_CONTRAST 0x11c +#define TVI_CONTROL_VID_GET_PICTURE 0x11d +#define TVI_CONTROL_VID_SET_PICTURE 0x11e + +/* TUNER controls */ +#define TVI_CONTROL_TUN_GET_FREQ 0x201 +#define TVI_CONTROL_TUN_SET_FREQ 0x202 +#define TVI_CONTROL_TUN_GET_TUNER 0x203 /* update priv->tuner struct for used input */ +#define TVI_CONTROL_TUN_SET_TUNER 0x204 /* update priv->tuner struct for used input */ +#define TVI_CONTROL_TUN_GET_NORM 0x205 +#define TVI_CONTROL_TUN_SET_NORM 0x206 + +/* AUDIO controls */ +#define TVI_CONTROL_AUD_GET_FORMAT 0x301 +#define TVI_CONTROL_AUD_GET_SAMPLERATE 0x302 +#define TVI_CONTROL_AUD_GET_SAMPLESIZE 0x303 +#define TVI_CONTROL_AUD_GET_CHANNELS 0x304 +#define TVI_CONTROL_AUD_SET_SAMPLERATE 0x305 + +/* SPECIFIC controls */ +#define TVI_CONTROL_SPC_GET_INPUT 0x401 /* set input channel (tv,s-video,composite..) */ +#define TVI_CONTROL_SPC_SET_INPUT 0x402 /* set input channel (tv,s-video,composite..) */ +#define TVI_CONTROL_SPC_GET_NORMID 0x403 /* get normid from norm name */ + +extern tvi_handle_t *tv_begin(void); +extern int tv_init(tvi_handle_t *tvh); +extern int tv_uninit(tvi_handle_t *tvh); + +int tv_set_color_options(tvi_handle_t *tvh, int opt, int val); +int tv_get_color_options(tvi_handle_t *tvh, int opt, int* val); +#define TV_COLOR_BRIGHTNESS 1 +#define TV_COLOR_HUE 2 +#define TV_COLOR_SATURATION 3 +#define TV_COLOR_CONTRAST 4 + +int tv_step_channel_real(tvi_handle_t *tvh, int direction); +int tv_step_channel(tvi_handle_t *tvh, int direction); +#define TV_CHANNEL_LOWER 1 +#define TV_CHANNEL_HIGHER 2 + +int tv_last_channel(tvi_handle_t *tvh); + +int tv_set_channel_real(tvi_handle_t *tvh, char *channel); +int tv_set_channel(tvi_handle_t *tvh, char *channel); + +int tv_step_norm(tvi_handle_t *tvh); +int tv_step_chanlist(tvi_handle_t *tvh); + +int tv_set_freq(tvi_handle_t *tvh, unsigned long freq); +int tv_get_freq(tvi_handle_t *tvh, unsigned long *freq); + +int tv_set_norm(tvi_handle_t *tvh, char* norm); + +#define TV_NORM_PAL 1 +#define TV_NORM_NTSC 2 +#define TV_NORM_SECAM 3 +#define TV_NORM_PALNC 4 +#define TV_NORM_PALM 5 +#define TV_NORM_PALN 6 +#define TV_NORM_NTSCJP 7 + +#endif /* USE_TV */ + +#endif /* TV_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tvi_bsdbt848.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,846 @@ +/* + (C)2002 Charles R. Henrich (henrich@msu.edu) + *BSD (hopefully, requires working driver!) BrookTree capture support. + + Still in (active) development! + + v1.1 Mar 13 2002 Fully functional, need to move ring buffer to + the kernel driver. + v1.0 Feb 19 2002 First Release, need to add support for changing + audio parameters. +*/ + +#include "config.h" + +#define RINGSIZE 8 +#define FRAGSIZE 4096 /* (2^12 see SETFRAGSIZE below) */ + +#define TRUE (1==1) +#define FALSE (1==0) + +#define PAL_WIDTH 768 +#define PAL_HEIGHT 576 +#define PAL_FPS 25 + +#define NTSC_WIDTH 640 +#define NTSC_HEIGHT 480 +#define NTSC_FPS 29.97 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/filio.h> +#include <sys/time.h> +#include <signal.h> +#include <string.h> + +#include <sys/param.h> +#ifdef __NetBSD__ +#include <dev/ic/bt8xx.h> +#include <sys/audioio.h> +#elif defined(__DragonFly__) +#include <dev/video/meteor/ioctl_meteor.h> +#include <dev/video/bktr/ioctl_bt848.h> +#elif __FreeBSD_version >= 502100 +#include <dev/bktr/ioctl_meteor.h> +#include <dev/bktr/ioctl_bt848.h> +#else +#include <machine/ioctl_meteor.h> +#include <machine/ioctl_bt848.h> +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include <sys/soundcard.h> +#else +#ifdef HAVE_SOUNDCARD_H +#include <soundcard.h> +#else +#include <machine/soundcard.h> +#endif +#endif + +#include "libaf/af_format.h" +#include "libvo/img_format.h" +#include "tv.h" + +/* information about this file */ +static tvi_info_t info = { + "Brooktree848 Support", + "bsdbt848", + "Charles Henrich", + "in development" +}; + +typedef struct { + int dirty; + double timestamp; + char *buf; +} RBFRAME; + +/* private data's */ +typedef struct { + +/* Audio */ + char *dspdev; + int dspready; + int dspfd; + int dspsamplesize; + int dspstereo; + int dspspeed; + int dspfmt; + int dspframesize; + int dsprate; + long long dspbytesread; + +/* Video */ + char *btdev; + int videoready; + int btfd; + int source; + float maxfps; + float fps; + int iformat; + int maxheight; + int maxwidth; + struct meteor_geomet geom; + struct meteor_capframe capframe; + +/* Frame Buffer */ + + int framebufsize; + float timestamp; + int curpaintframe; + int curbufframe; + unsigned char *livebuf; + RBFRAME framebuf[RINGSIZE]; + +/* Inputs */ + + int input; + +/* Tuner */ + + char *tunerdev; + int tunerfd; + int tunerready; + u_long tunerfreq; + struct bktr_chnlset cset; + +/* Other */ + + int immediatemode; + double starttime; + +} priv_t; + +#include "tvi_def.h" + +static priv_t *G_private=NULL; + +static int getinput(int innumber); + +static void processframe(int signal) +{ +struct timeval curtime; + +if(G_private->immediatemode == TRUE) return; + +gettimeofday(&curtime, NULL); + +if(G_private->framebuf[G_private->curpaintframe].dirty == TRUE) + { + memcpy(G_private->framebuf[G_private->curpaintframe].buf, + G_private->livebuf, G_private->framebufsize); + + G_private->framebuf[G_private->curpaintframe].dirty = FALSE; + + G_private->framebuf[G_private->curpaintframe].timestamp = + curtime.tv_sec + curtime.tv_usec*.000001; + + G_private->curpaintframe++; + + if(G_private->curpaintframe >= RINGSIZE) G_private->curpaintframe = 0; + } + +return; +} + +/* handler creator - entry point ! */ +tvi_handle_t *tvi_init_bsdbt848(char *device) +{ + return(new_handle()); +} + +static int control(priv_t *priv, int cmd, void *arg) +{ + switch(cmd) + { + +/* Tuner Controls */ + + case TVI_CONTROL_IS_TUNER: + if(priv->tunerready == FALSE) return TVI_CONTROL_FALSE; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_TUN_GET_FREQ: + { + if(ioctl(priv->tunerfd, TVTUNER_GETFREQ, &priv->tunerfreq) < 0) + { + perror("GETFREQ:ioctl"); + return(TVI_CONTROL_FALSE); + } + + (int)*(void **)arg = priv->tunerfreq; + return(TVI_CONTROL_TRUE); + } + + case TVI_CONTROL_TUN_SET_FREQ: + { + priv->tunerfreq = (int)*(void **)arg; + + if(ioctl(priv->tunerfd, TVTUNER_SETFREQ, &priv->tunerfreq) < 0) + { + perror("SETFREQ:ioctl"); + return(0); + } + + return(TVI_CONTROL_TRUE); + } + + case TVI_CONTROL_TUN_GET_TUNER: + case TVI_CONTROL_TUN_SET_TUNER: + +/* Inputs */ + + case TVI_CONTROL_SPC_GET_INPUT: + { + if(ioctl(priv->btfd, METEORGINPUT, &priv->input) < 0) + { + perror("GINPUT:ioctl"); + return(TVI_CONTROL_FALSE); + } + + (int)*(void **)arg = priv->input; + return(TVI_CONTROL_TRUE); + } + + case TVI_CONTROL_SPC_SET_INPUT: + { + priv->input = getinput((int)*(void **)arg); + + if(ioctl(priv->btfd, METEORSINPUT, &priv->input) < 0) + { + perror("tunerfreq:ioctl"); + return(0); + } + + return(TVI_CONTROL_TRUE); + } + +/* Audio Controls */ + + case TVI_CONTROL_IS_AUDIO: + if(priv->dspready == FALSE) return TVI_CONTROL_FALSE; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_AUD_GET_FORMAT: + { + (int)*(void **)arg = AF_FORMAT_S16_LE; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_CHANNELS: + { + (int)*(void **)arg = 2; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_SET_SAMPLERATE: + { + int dspspeed = (int)*(void **)arg; + + if(ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &dspspeed) == -1) + { + perror("invalidaudiorate"); + return(TVI_CONTROL_FALSE); + } + + priv->dspspeed = dspspeed; + + priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/ + priv->fps * (priv->dspstereo+1); + priv->dsprate = priv->dspspeed * priv->dspsamplesize/8* + (priv->dspstereo+1); + + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_SAMPLERATE: + { + (int)*(void **)arg = priv->dspspeed; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_SAMPLESIZE: + { + (int)*(void **)arg = priv->dspsamplesize/8; + return(TVI_CONTROL_TRUE); + } + +/* Video Controls */ + + case TVI_CONTROL_IS_VIDEO: + if(priv->videoready == FALSE) return TVI_CONTROL_FALSE; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_TUN_SET_NORM: + { + int req_mode = (int)*(void **)arg; + u_short tmp_fps; + + priv->iformat = METEOR_FMT_AUTOMODE; + + if(req_mode == TV_NORM_PAL) + { + priv->iformat = METEOR_FMT_PAL; + priv->maxheight = PAL_HEIGHT; + priv->maxwidth = PAL_WIDTH; + priv->maxfps = PAL_FPS; + priv->fps = PAL_FPS; + + if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; + + if(priv->geom.rows > priv->maxheight) + { + priv->geom.rows = priv->maxheight; + } + + if(priv->geom.columns > priv->maxwidth) + { + priv->geom.columns = priv->maxwidth; + } + } + + if(req_mode == TV_NORM_NTSC) + { + priv->iformat = METEOR_FMT_NTSC; + priv->maxheight = NTSC_HEIGHT; + priv->maxwidth = NTSC_WIDTH; + priv->maxfps = NTSC_FPS; + priv->fps = NTSC_FPS; + + priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/ + priv->fps * (priv->dspstereo+1); + priv->dsprate = priv->dspspeed * priv->dspsamplesize/8 * + (priv->dspstereo+1); + + if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; + + if(priv->geom.rows > priv->maxheight) + { + priv->geom.rows = priv->maxheight; + } + + if(priv->geom.columns > priv->maxwidth) + { + priv->geom.columns = priv->maxwidth; + } + } + + if(req_mode == TV_NORM_SECAM) priv->iformat = METEOR_FMT_SECAM; + + if(ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) + { + perror("format:ioctl"); + return(TVI_CONTROL_FALSE); + } + + if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) + { + perror("geo:ioctl"); + return(0); + } + + tmp_fps = priv->fps; + if(ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) + { + perror("fps:ioctl"); + return(0); + } + +#ifdef BT848_SAUDIO + if(priv->tunerready == TRUE && + ioctl(priv->tunerfd, BT848_SAUDIO, &tv_param_audio_id) < 0) + { + perror("audioid:ioctl"); + } +#endif + + return(TVI_CONTROL_TRUE); + } + + case TVI_CONTROL_VID_GET_FORMAT: + (int)*(void **)arg = IMGFMT_UYVY; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_VID_SET_FORMAT: + { + int req_fmt = (int)*(void **)arg; + + if(req_fmt != IMGFMT_UYVY) return(TVI_CONTROL_FALSE); + + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_VID_SET_WIDTH: + priv->geom.columns = (int)*(void **)arg; + + if(priv->geom.columns > priv->maxwidth) + { + priv->geom.columns = priv->maxwidth; + } + + if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) + { + perror("width:ioctl"); + return(0); + } + + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_VID_GET_WIDTH: + (int)*(void **)arg = priv->geom.columns; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_VID_SET_HEIGHT: + priv->geom.rows = (int)*(void **)arg; + + if(priv->geom.rows > priv->maxheight) + { + priv->geom.rows = priv->maxheight; + } + + if(priv->geom.rows <= priv->maxheight / 2) + { + priv->geom.oformat |= METEOR_GEO_EVEN_ONLY; + } + + if(ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) + { + perror("height:ioctl"); + return(0); + } + + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_VID_GET_HEIGHT: + (int)*(void **)arg = priv->geom.rows; + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_VID_GET_FPS: + *(float *)arg = priv->fps; + return(TVI_CONTROL_TRUE); + +/* + case TVI_CONTROL_VID_SET_FPS: + priv->fps = (int)*(void **)arg; + + if(priv->fps > priv->maxfps) priv->fps = priv->maxfps; + + if(ioctl(priv->btfd, METEORSFPS, &priv->fps) < 0) + { + perror("fps:ioctl"); + return(0); + } + + return(TVI_CONTROL_TRUE); +*/ + + case TVI_CONTROL_VID_CHK_WIDTH: + case TVI_CONTROL_VID_CHK_HEIGHT: + return(TVI_CONTROL_TRUE); + + case TVI_CONTROL_IMMEDIATE: + priv->immediatemode = TRUE; + return(TVI_CONTROL_TRUE); + } + + return(TVI_CONTROL_UNKNOWN); +} + +static int init(priv_t *priv) +{ +int marg; +int count; +u_short tmp_fps; + +G_private = priv; /* Oooh, sick */ + +/* Video Configuration */ + +priv->videoready = TRUE; +priv->btdev = strdup("/dev/bktr0"); +priv->immediatemode = FALSE; +priv->iformat = METEOR_FMT_PAL; +priv->maxheight = PAL_HEIGHT; +priv->maxwidth = PAL_WIDTH; +priv->maxfps = PAL_FPS; +priv->source = METEOR_INPUT_DEV0; +priv->fps = priv->maxfps; + +priv->starttime=0; +priv->curpaintframe=0; +priv->curbufframe=0; + +priv->geom.columns = priv->maxwidth; +priv->geom.rows = priv->maxheight; +priv->geom.frames = 1; +priv->geom.oformat = METEOR_GEO_YUV_PACKED; + +priv->btfd = open(priv->btdev, O_RDONLY); + +if(priv->btfd < 0) + { + perror("bktr open"); + priv->videoready = FALSE; + } + +if(priv->videoready == TRUE && + ioctl(priv->btfd, METEORSFMT, &priv->iformat) < 0) + { + perror("FMT:ioctl"); + } + +if(priv->videoready == TRUE && + ioctl(priv->btfd, METEORSINPUT, &priv->source) < 0) + { + perror("SINPUT:ioctl"); + } + +tmp_fps = priv->fps; +if(priv->videoready == TRUE && + ioctl(priv->btfd, METEORSFPS, &tmp_fps) < 0) + { + perror("SFPS:ioctl"); + } + +if(priv->videoready == TRUE && + ioctl(priv->btfd, METEORSETGEO, &priv->geom) < 0) + { + perror("SGEO:ioctl"); + } + +if(priv->videoready == TRUE) + { + priv->framebufsize = (priv->geom.columns * priv->geom.rows * 2); + + priv->livebuf = (u_char *)mmap((caddr_t)0, priv->framebufsize, PROT_READ, + MAP_SHARED, priv->btfd, (off_t)0); + + if(priv->livebuf == (u_char *) MAP_FAILED) + { + perror("mmap"); + priv->videoready = FALSE; + } + + for(count=0;count<RINGSIZE;count++) + { + priv->framebuf[count].buf = malloc(priv->framebufsize); + + if(priv->framebuf[count].buf == NULL) + { + perror("framebufmalloc"); + priv->videoready = FALSE; + break; + } + + priv->framebuf[count].dirty = TRUE; + priv->framebuf[count].timestamp = 0; + } + } + +/* Tuner Configuration */ + +priv->tunerdev = strdup("/dev/tuner0"); +priv->tunerready = TRUE; + +priv->tunerfd = open(priv->tunerdev, O_RDONLY); + +if(priv->tunerfd < 0) + { + perror("tune open"); + priv->tunerready = FALSE; + } + +/* Audio Configuration */ + +priv->dspready = TRUE; +#ifdef __NetBSD__ +priv->dspdev = strdup("/dev/sound"); +#else +priv->dspdev = strdup("/dev/dsp"); +#endif +priv->dspsamplesize = 16; +priv->dspstereo = 1; +priv->dspspeed = 44100; +priv->dspfmt = AFMT_S16_LE; +priv->dspbytesread = 0; +priv->dsprate = priv->dspspeed * priv->dspsamplesize/8*(priv->dspstereo+1); +priv->dspframesize = priv->dspspeed*priv->dspsamplesize/8/priv->fps * + (priv->dspstereo+1); + +if((priv->dspfd = open (priv->dspdev, O_RDONLY, 0)) < 0) + { + perror("dsp open"); + priv->dspready = FALSE; + } + +marg = (256 << 16) | 12; + +if (ioctl(priv->dspfd, SNDCTL_DSP_SETFRAGMENT, &marg ) < 0 ) + { + perror("setfrag"); + priv->dspready = FALSE; + } + +if((priv->dspready == TRUE) && + ((ioctl(priv->dspfd, SNDCTL_DSP_SAMPLESIZE, &priv->dspsamplesize) == -1) || + (ioctl(priv->dspfd, SNDCTL_DSP_STEREO, &priv->dspstereo) == -1) || + (ioctl(priv->dspfd, SNDCTL_DSP_SPEED, &priv->dspspeed) == -1) || + (ioctl(priv->dspfd, SNDCTL_DSP_SETFMT, &priv->dspfmt) == -1))) + { + perror ("configuration of dsp failed"); + close(priv->dspfd); + priv->dspready = FALSE; + } + +return(1); +} + +/* that's the real start, we'got the format parameters (checked with control) */ +static int start(priv_t *priv) +{ +int tmp; +struct timeval curtime; +int marg; + +fprintf(stderr,"START\n"); +if(priv->videoready == FALSE) return(0); + +signal(SIGUSR1, processframe); +signal(SIGALRM, processframe); + +marg = SIGUSR1; + +if(ioctl(priv->btfd, METEORSSIGNAL, &marg) < 0) + { + perror("METEORSSIGNAL failed"); + return(0); + } + +read(priv->dspfd, &tmp, 2); + +gettimeofday(&curtime, NULL); + +priv->starttime = curtime.tv_sec + (curtime.tv_usec *.000001); + +marg = METEOR_CAP_CONTINOUS; + +if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0) + { + perror("METEORCAPTUR failed"); + return(0); + } + +return(1); +} + +static int uninit(priv_t *priv) +{ +int marg; + +if(priv->videoready == FALSE) return(0); + +marg = METEOR_SIG_MODE_MASK; + +if(ioctl( priv->btfd, METEORSSIGNAL, &marg) < 0 ) + { + perror("METEORSSIGNAL"); + return(0); + } + +marg = METEOR_CAP_STOP_CONT; + +if(ioctl(priv->btfd, METEORCAPTUR, &marg) < 0 ) + { + perror("METEORCAPTUR STOP"); + return(0); + } + +close(priv->btfd); +close(priv->dspfd); + +priv->dspfd = -1; +priv->btfd = -1; + +priv->dspready = priv->videoready = FALSE; + +return(1); +} + + +static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) +{ +struct timeval curtime; +sigset_t sa_mask; + +if(priv->videoready == FALSE) return(0); + +alarm(1); +sigfillset(&sa_mask); +sigdelset(&sa_mask,SIGINT); +sigdelset(&sa_mask,SIGUSR1); +sigdelset(&sa_mask,SIGALRM); +sigsuspend(&sa_mask); +alarm(0); + +memcpy(buffer, priv->livebuf, len); + +/* PTS = 0, show the frame NOW, this routine is only used in playback mode + without audio capture .. */ + +return(0); +} + +static double grab_video_frame(priv_t *priv, char *buffer, int len) +{ +struct timeval curtime; +double timestamp=0; +sigset_t sa_mask; + +if(priv->videoready == FALSE) return(0); + +if(priv->immediatemode == TRUE) + { + return grabimmediate_video_frame(priv, buffer, len); + } + +while(priv->framebuf[priv->curbufframe].dirty == TRUE) + { + alarm(1); + sigemptyset(&sa_mask); + sigsuspend(&sa_mask); + alarm(0); + } + +memcpy(buffer, priv->framebuf[priv->curbufframe].buf, len); +timestamp = priv->framebuf[priv->curbufframe].timestamp; +priv->framebuf[priv->curbufframe].dirty = TRUE; + +priv->curbufframe++; +if(priv->curbufframe >= RINGSIZE) priv->curbufframe = 0; + +return(timestamp-priv->starttime); +} + +static int get_video_framesize(priv_t *priv) +{ +return(priv->geom.columns*priv->geom.rows*16/8); +} + +static double grab_audio_frame(priv_t *priv, char *buffer, int len) +{ +struct timeval curtime; +double curpts; +double timeskew; +int bytesavail; +int bytesread; +int ret; + +if(priv->dspready == FALSE) return 0; + +gettimeofday(&curtime, NULL); + +/* Get exactly one frame of audio, which forces video sync to audio.. */ + +bytesread=read(priv->dspfd, buffer, len); + +while(bytesread < len) + { + ret=read(priv->dspfd, &buffer[bytesread], len-bytesread); + + if(ret == -1) + { + perror("Audio read failed!"); + return 0; + } + + bytesread+=ret; + } + +priv->dspbytesread += bytesread; + +curpts = curtime.tv_sec + curtime.tv_usec * .000001; + +timeskew = priv->dspbytesread * 1.0 / priv->dsprate - (curpts-priv->starttime); + +if(timeskew > .125/priv->fps) + { + priv->starttime -= timeskew; + } +else + { + if(timeskew < -.125/priv->fps) + { + priv->starttime -= timeskew; + } + } + +return(priv->dspbytesread * 1.0 / priv->dsprate); +} + +static int get_audio_framesize(priv_t *priv) +{ +int bytesavail; +#ifdef __NetBSD__ +struct audio_info auinf; +#endif + +if(priv->dspready == FALSE) return 0; + +#ifdef __NetBSD__ +if(ioctl(priv->dspfd, AUDIO_GETINFO, &auinf) < 0) + { + perror("AUDIO_GETINFO"); + return(TVI_CONTROL_FALSE); + } +else + bytesavail = auinf.record.seek; /* *priv->dspsamplesize; */ +#else +if(ioctl(priv->dspfd, FIONREAD, &bytesavail) < 0) + { + perror("FIONREAD"); + return(TVI_CONTROL_FALSE); + } +#endif + +/* When mencoder wants audio data, it wants data.. + it won't go do anything else until it gets it :( */ + +if(bytesavail == 0) return FRAGSIZE; + +return(bytesavail); +} + +static int getinput(int innumber) +{ +switch(innumber) + { + case 0: return METEOR_INPUT_DEV0; /* RCA */ + case 1: return METEOR_INPUT_DEV1; /* Tuner */ + case 2: return METEOR_INPUT_DEV2; /* In 1 */ + case 3: return METEOR_INPUT_DEV3; /* In 2 */ + case 4: return METEOR_INPUT_DEV_RGB; /* RGB */ + case 5: return METEOR_INPUT_DEV_SVIDEO; /* SVid */ + } + +return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tvi_def.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,61 @@ +#include <stdlib.h> /* malloc */ +#include <string.h> /* memset */ + +static int init(priv_t *priv); +static int uninit(priv_t *priv); +static int control(priv_t *priv, int cmd, void *arg); +static int start(priv_t *priv); +static double grab_video_frame(priv_t *priv, char *buffer, int len); +#ifdef HAVE_TV_BSDBT848 +static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len); +#endif +static int get_video_framesize(priv_t *priv); +static double grab_audio_frame(priv_t *priv, char *buffer, int len); +static int get_audio_framesize(priv_t *priv); + +static tvi_functions_t functions = +{ + init, + uninit, + control, + start, + grab_video_frame, +#ifdef HAVE_TV_BSDBT848 + grabimmediate_video_frame, +#endif + get_video_framesize, + grab_audio_frame, + get_audio_framesize +}; + +static tvi_handle_t *new_handle(void) +{ + tvi_handle_t *h = (tvi_handle_t *)malloc(sizeof(tvi_handle_t)); + + if (!h) + return(NULL); + h->priv = (priv_t *)malloc(sizeof(priv_t)); + if (!h->priv) + { + free(h); + return(NULL); + } + memset(h->priv, 0, sizeof(priv_t)); + h->info = &info; + h->functions = &functions; + h->seq = 0; + h->chanlist = -1; + h->chanlist_s = NULL; + h->norm = -1; + h->channel = -1; + return(h); +} + +static void free_handle(tvi_handle_t *h) +{ + if (h) { + if (h->priv) + free(h->priv); + free(h); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tvi_dummy.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,120 @@ +/* + Only a sample! +*/ + +#include "config.h" + +#include <stdio.h> +#include "libvo/img_format.h" +#include "tv.h" + +/* information about this file */ +static tvi_info_t info = { + "NULL-TV", + "dummy", + "alex", + NULL +}; + +/* private data's */ +typedef struct { + int width; + int height; +} priv_t; + +#include "tvi_def.h" + +/* handler creator - entry point ! */ +tvi_handle_t *tvi_init_dummy(char *device) +{ + return(new_handle()); +} + +/* initialisation */ +static int init(priv_t *priv) +{ + priv->width = 320; + priv->height = 200; + return(1); +} + +/* that's the real start, we'got the format parameters (checked with control) */ +static int start(priv_t *priv) +{ + return(1); +} + +static int uninit(priv_t *priv) +{ + return(1); +} + +static int control(priv_t *priv, int cmd, void *arg) +{ + switch(cmd) + { + case TVI_CONTROL_IS_VIDEO: + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_FORMAT: +// *(int *)arg = IMGFMT_YV12; + *(int *)arg = IMGFMT_YV12; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_SET_FORMAT: + { +// int req_fmt = *(int *)arg; + int req_fmt = *(int *)arg; + if (req_fmt != IMGFMT_YV12) + return(TVI_CONTROL_FALSE); + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_VID_SET_WIDTH: + priv->width = *(int *)arg; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_WIDTH: + *(int *)arg = priv->width; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_SET_HEIGHT: + priv->height = *(int *)arg; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_HEIGHT: + *(int *)arg = priv->height; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_CHK_WIDTH: + case TVI_CONTROL_VID_CHK_HEIGHT: + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_TUN_SET_NORM: + return(TVI_CONTROL_TRUE); + } + return(TVI_CONTROL_UNKNOWN); +} + +#ifdef HAVE_TV_BSDBT848 +static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) +{ + memset(buffer, 0xCC, len); + return(1); +} +#endif + +static double grab_video_frame(priv_t *priv, char *buffer, int len) +{ + memset(buffer, 0x42, len); + return(1); +} + +static int get_video_framesize(priv_t *priv) +{ + /* YV12 */ + return(priv->width*priv->height*12/8); +} + +static double grab_audio_frame(priv_t *priv, char *buffer, int len) +{ + memset(buffer, 0x42, len); + return(1); +} + +static int get_audio_framesize(priv_t *priv) +{ + return(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tvi_v4l.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,1759 @@ +/* + Video 4 Linux input + + (C) Alex Beregszaszi + + Some ideas are based on xawtv/libng's grab-v4l.c written by + Gerd Knorr <kraxel@bytesex.org> + + Multithreading, a/v sync and native ALSA support by + Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz> + + Mjpeg hardware encoding support by + Iván Szántó <szivan@freemail.hu> + + CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! +*/ + +#include "config.h" + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/time.h> + +/* Necessary to prevent collisions between <linux/time.h> and <sys/time.h> when V4L2 is installed. */ +#define _LINUX_TIME_H + +#include <linux/videodev.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#ifdef HAVE_SYS_SYSINFO_H +#include <sys/sysinfo.h> +#endif + +#include "mp_msg.h" +#include "libaf/af_format.h" +#include "libvo/img_format.h" +#include "libvo/fastmemcpy.h" +#include "libvo/videodev_mjpeg.h" + +#include "tv.h" + +#include "audio_in.h" + +static tvi_info_t info = { + "Video 4 Linux input", + "v4l", + "Alex Beregszaszi", + "under development" +}; + +#define PAL_WIDTH 768 +#define PAL_HEIGHT 576 +#define PAL_FPS 25 + +#define NTSC_WIDTH 640 +#define NTSC_HEIGHT 480 +#define NTSC_FPS (30000.0/1001.0) + +#define MAX_AUDIO_CHANNELS 10 + +#define VID_BUF_SIZE_IMMEDIATE 2 +#define VIDEO_AVG_BUFFER_SIZE 600 + +typedef struct { + /* general */ + char *video_device; + int video_fd; + struct video_capability capability; + struct video_channel *channels; + int act_channel; + struct video_tuner tuner; + + /* video */ + struct video_picture picture; + int format; /* output format */ + int width; + int height; + int bytesperline; + float fps; + + struct video_mbuf mbuf; + unsigned char *mmap; + struct video_mmap *buf; + int nbuf; + + /* audio */ + char *audio_device; + audio_in_t audio_in; + + int audio_id; + struct video_audio audio[MAX_AUDIO_CHANNELS]; + int audio_channels[MAX_AUDIO_CHANNELS]; + + /* buffering stuff */ + int immediate_mode; + + int audio_buffer_size; + int aud_skew_cnt; + unsigned char *audio_ringbuffer; + long long *audio_skew_buffer; + volatile int audio_head; + volatile int audio_tail; + volatile int audio_cnt; + volatile long long audio_skew; + volatile double audio_skew_factor; + volatile long long audio_skew_measure_time; + volatile int audio_drop; + + int first; + int video_buffer_size_max; + volatile int video_buffer_size_current; + unsigned char **video_ringbuffer; + long long *video_timebuffer; + long long *video_avg_buffer; + int video_avg_ptr; + int video_interval_sum; + volatile int video_head; + volatile int video_tail; + volatile int video_cnt; + + volatile int shutdown; + + pthread_t audio_grabber_thread; + pthread_t video_grabber_thread; + pthread_mutex_t audio_starter; + pthread_mutex_t skew_mutex; + pthread_mutex_t video_buffer_mutex; + + long long starttime; + double audio_secs_per_block; + long long audio_skew_total; + long audio_recv_blocks_total; + long audio_sent_blocks_total; + long mjpeg_bufsize; + +} priv_t; + +#include "tvi_def.h" + +static const char *device_cap2name[] = { + "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", + "frameram", "scales", "monochrome", "subcapture", "mpeg-decoder", + "mpeg-encoder", "mjpeg-decoder", "mjpeg-encoder", NULL +}; + +static const char *device_palette2name[] = { + "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422", + "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p", + "yuv420p", "yuv410p" +}; +#define PALETTE(x) ((x < sizeof(device_palette2name)/sizeof(char*)) ? device_palette2name[x] : "UNKNOWN") + +static const char *norm2name(int mode) +{ + switch (mode) { + case VIDEO_MODE_PAL: + return "pal"; + case VIDEO_MODE_SECAM: + return "secam"; + case VIDEO_MODE_NTSC: + return "ntsc"; + case VIDEO_MODE_AUTO: + return "auto"; + default: + return "unknown"; + } +}; + +static const char *audio_mode2name(int mode) +{ + switch (mode) { + case VIDEO_SOUND_MONO: + return "mono"; + case VIDEO_SOUND_STEREO: + return "stereo"; + case VIDEO_SOUND_LANG1: + return "language1"; + case VIDEO_SOUND_LANG2: + return "language2"; + default: + return "unknown"; + } +}; + +static void *audio_grabber(void *data); +static void *video_grabber(void *data); + +static int palette2depth(int palette) +{ + switch(palette) + { + /* component */ + case VIDEO_PALETTE_RGB555: + return(15); + case VIDEO_PALETTE_RGB565: + return(16); + case VIDEO_PALETTE_RGB24: + return(24); + case VIDEO_PALETTE_RGB32: + return(32); + /* planar */ + case VIDEO_PALETTE_YUV411P: + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_YUV410P: + return(12); + /* packed */ + case VIDEO_PALETTE_YUV422P: + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_UYVY: + case VIDEO_PALETTE_YUV420: + case VIDEO_PALETTE_YUV411: + return(16); + } + return(-1); +} + +static int format2palette(int format) +{ + switch(format) + { + case IMGFMT_BGR15: + return(VIDEO_PALETTE_RGB555); + case IMGFMT_BGR16: + return(VIDEO_PALETTE_RGB565); + case IMGFMT_BGR24: + return(VIDEO_PALETTE_RGB24); + case IMGFMT_BGR32: + return(VIDEO_PALETTE_RGB32); + case IMGFMT_YV12: + case IMGFMT_I420: + return(VIDEO_PALETTE_YUV420P); + case IMGFMT_YUY2: + return(VIDEO_PALETTE_YUV422); + case IMGFMT_UYVY: + return(VIDEO_PALETTE_UYVY); + } + return(-1); +} + +// sets and sanitizes audio buffer/block sizes +static void setup_audio_buffer_sizes(priv_t *priv) +{ + int bytes_per_sample = priv->audio_in.bytes_per_sample; + + // make the audio buffer at least 5 seconds long + priv->audio_buffer_size = 1 + 5*priv->audio_in.samplerate + *priv->audio_in.channels + *bytes_per_sample/priv->audio_in.blocksize; + if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; + + // make the skew buffer at least 1 second long + priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate + *priv->audio_in.channels + *bytes_per_sample/priv->audio_in.blocksize; + if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; + + mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", + priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); +} + +tvi_handle_t *tvi_init_v4l(char *device, char *adevice) +{ + tvi_handle_t *h; + priv_t *priv; + + h = new_handle(); + if (!h) + return(NULL); + + priv = h->priv; + + /* set video device name */ + if (!device) + priv->video_device = strdup("/dev/video0"); + else + priv->video_device = strdup(device); + + /* set video device name */ + if (!adevice) + priv->audio_device = NULL; + else { + priv->audio_device = strdup(adevice); + } + + /* allocation failed */ + if (!priv->video_device) { + free_handle(h); + return(NULL); + } + + return(h); +} + +/* retrieves info about audio channels from the BTTV */ +static void init_v4l_audio(priv_t *priv) +{ + int i; + int reqmode; + + if (!priv->capability.audios) return; + + /* audio chanlist */ + + mp_msg(MSGT_TV, MSGL_V, " Audio devices: %d\n", priv->capability.audios); + + mp_msg(MSGT_TV, MSGL_V, "Video capture card reports the audio setup as follows:\n"); + for (i = 0; i < priv->capability.audios; i++) + { + if (i >= MAX_AUDIO_CHANNELS) + { + mp_msg(MSGT_TV, MSGL_ERR, "no space for more audio channels (increase in source!) (%d > %d)\n", + i, MAX_AUDIO_CHANNELS); + i = priv->capability.audios; + break; + } + + priv->audio[i].audio = i; + if (ioctl(priv->video_fd, VIDIOCGAUDIO, &priv->audio[i]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get audio failed: %s\n", strerror(errno)); + break; + } + + /* mute all channels */ + priv->audio[i].flags |= VIDEO_AUDIO_MUTE; + reqmode = -1; + if (tv_param_amode >= 0) { + switch (tv_param_amode) { + case 0: + reqmode = VIDEO_SOUND_MONO; + break; + case 1: + reqmode = VIDEO_SOUND_STEREO; + break; + case 2: + reqmode = VIDEO_SOUND_LANG1; + break; + case 3: + reqmode = VIDEO_SOUND_LANG2; + break; + default: + mp_msg(MSGT_TV, MSGL_ERR, "Unknown audio mode requested.\n"); + break; + } + if (reqmode >= 0) priv->audio[i].mode = reqmode; + } + ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[i]); + + // get the parameters back + if (ioctl(priv->video_fd, VIDIOCGAUDIO, &priv->audio[i]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get audio failed: %s\n", strerror(errno)); + break; + } + + switch(priv->audio[i].mode) + { + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_LANG1: + case VIDEO_SOUND_LANG2: + priv->audio_channels[i] = 1; + break; + case VIDEO_SOUND_STEREO: + priv->audio_channels[i] = 2; + break; + default: + mp_msg(MSGT_TV, MSGL_ERR, "Card reports an unknown audio mode !\n"); + mp_msg(MSGT_TV, MSGL_ERR, "Trying two channel audio. Use forcechan to override.\n"); + priv->audio_channels[i] = 2; + break; + } + + if (reqmode >= 0 && priv->audio[i].mode != reqmode) { + mp_msg(MSGT_TV, MSGL_ERR, "Audio mode setup warning!\n"); + mp_msg(MSGT_TV, MSGL_ERR, "Requested mode was %s, but v4l still reports %s.\n", + audio_mode2name(reqmode), audio_mode2name(priv->audio[i].mode)); + mp_msg(MSGT_TV, MSGL_ERR, "You may need \"forcechan\" option to force stereo/mono audio recording.\n"); + } + + /* display stuff */ + mp_msg(MSGT_TV, MSGL_V, " %d: %s: ", priv->audio[i].audio, + priv->audio[i].name); + if (priv->audio[i].flags & VIDEO_AUDIO_MUTABLE) { + mp_msg(MSGT_TV, MSGL_V, "muted=%s ", + (priv->audio[i].flags & VIDEO_AUDIO_MUTE) ? "yes" : "no"); + } + mp_msg(MSGT_TV, MSGL_V, "vol=%d bass=%d treble=%d balance=%d mode=%s", + priv->audio[i].volume, priv->audio[i].bass, priv->audio[i].treble, + priv->audio[i].balance, audio_mode2name(priv->audio[i].mode)); + mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[i]); + + if (tv_param_forcechan >= 0) + priv->audio_channels[i] = tv_param_forcechan; + + // we'll call VIDIOCSAUDIO again when starting capture + // let's set audio mode to requested mode again for the case + // when VIDIOCGAUDIO just cannot report the mode correctly + if (reqmode >= 0) priv->audio[i].mode = reqmode; + } +} + +#if !defined(__LINUX_VIDEODEV2_H) && !defined(VIDIOC_QUERYCAP) +struct v4l2_capability +{ + __u8 driver[16]; /* i.e. "bttv" */ + __u8 card[32]; /* i.e. "Hauppauge WinTV" */ + __u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */ + __u32 version; /* should use KERNEL_VERSION() */ + __u32 capabilities; /* Device capabilities */ + __u32 reserved[4]; +}; + +#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) +#endif + +static int init(priv_t *priv) +{ + int i; + + if (tv_param_immediate == 1) + tv_param_noaudio = 1; + + priv->video_ringbuffer = NULL; + priv->video_timebuffer = NULL; + priv->video_avg_buffer = NULL; + priv->audio_ringbuffer = NULL; + priv->audio_skew_buffer = NULL; + + priv->video_fd = open(priv->video_device, O_RDWR); + mp_msg(MSGT_TV, MSGL_DBG2, "Video fd: %d, %p\n", priv->video_fd, + priv->video_device); + if (priv->video_fd == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "unable to open '%s': %s\n", + priv->video_device, strerror(errno)); + goto err; + } + + /* check for v4l2 */ + if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) == 0) { + mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); + mp_msg(MSGT_TV, MSGL_ERR, " WARNING: YOU ARE USING V4L DEMUXER WITH V4L2 DRIVERS!!!\n"); + mp_msg(MSGT_TV, MSGL_ERR, " As the V4L1 compatibility layer is broken, this may not work.\n"); + mp_msg(MSGT_TV, MSGL_ERR, " If you encounter any problems, use driver=v4l2 instead.\n"); + mp_msg(MSGT_TV, MSGL_ERR, " Bugreports on driver=v4l with v4l2 drivers will be ignored.\n"); + mp_msg(MSGT_TV, MSGL_ERR, "=================================================================\n"); + } + + /* get capabilities (priv->capability is needed!) */ + if (ioctl(priv->video_fd, VIDIOCGCAP, &priv->capability) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); + goto err; + } + + fcntl(priv->video_fd, F_SETFD, FD_CLOEXEC); + + mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.name); + mp_msg(MSGT_TV, MSGL_INFO, " Capabilites: "); + for (i = 0; device_cap2name[i] != NULL; i++) + if (priv->capability.type & (1 << i)) + mp_msg(MSGT_TV, MSGL_INFO, "%s ", device_cap2name[i]); + mp_msg(MSGT_TV, MSGL_INFO, "\n"); + mp_msg(MSGT_TV, MSGL_INFO, " Device type: %d\n", priv->capability.type); + mp_msg(MSGT_TV, MSGL_INFO, " Supported sizes: %dx%d => %dx%d\n", + priv->capability.minwidth, priv->capability.minheight, + priv->capability.maxwidth, priv->capability.maxheight); + priv->width = priv->capability.minwidth; + priv->height = priv->capability.minheight; + + /* somewhere here could disable tv_param_mjpeg, if it is not a capability */ + + /* initialize if necessary */ + if ( tv_param_mjpeg ) + { + struct mjpeg_params bparm; + struct mjpeg_requestbuffers breq; /* buffer requests */ + + if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, + " MJP: Error getting video parameters: %s\n", strerror(errno)); + goto err; + } + + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: previous params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", + bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, + bparm.decimation, bparm.field_per_buff); + + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", + bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); + + bparm.input = tv_param_input; /* tv */ + if (!strcasecmp(tv_param_norm, "pal")) + bparm.norm = 0; /* PAL */ + else if (!strcasecmp(tv_param_norm, "ntsc")) + bparm.norm = 1; /* NTSC */ + else if (!strcasecmp(tv_param_norm, "secam")) + bparm.norm = 2; /* SECAM */ + bparm.quality = tv_param_quality; + bparm.decimation = tv_param_decimation; + + mp_msg(MSGT_TV, MSGL_INFO, " MJP: setting params to decimation: %d, quality: %d\n", + bparm.decimation, bparm.quality); + + if (ioctl(priv->video_fd, MJPIOC_S_PARAMS, &bparm) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, + " MJP: Error setting video parameters: %s\n", strerror(errno)); + goto err; + } + + if (ioctl(priv->video_fd, MJPIOC_G_PARAMS, &bparm) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, + " MJP: Error getting video parameters: %s\n", strerror(errno)); + goto err; + } + + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: current params: x: %d, y: %d, w: %d, h: %d, decim: %d, fields: %d,\n", + bparm.img_x, bparm.img_y, bparm.img_width, bparm.img_height, + bparm.decimation, bparm.field_per_buff); + + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: HorDcm: %d, VerDcm: %d, TmpDcm: %d\n", + bparm.HorDcm, bparm.VerDcm, bparm.TmpDcm); + + + breq.count = 64; + priv -> nbuf = breq.count; + priv->mbuf.frames = priv -> nbuf; + priv->mjpeg_bufsize = 256*1024; + if (tv_param_buffer_size >= 0) { + priv->mjpeg_bufsize = tv_param_buffer_size*1024; + } + breq.size = priv -> mjpeg_bufsize; + if (ioctl(priv->video_fd, MJPIOC_REQBUFS,&(breq)) < 0) + { + mp_msg (MSGT_TV, MSGL_ERR, + " MJP: Error requesting video buffers: %s\n", strerror(errno)); + goto err; + } + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: Got %ld buffers of size %ld KB\n", + breq.count, breq.size/1024); + + priv -> mmap = mmap(0, breq.count * breq.size, + PROT_READ|PROT_WRITE, MAP_SHARED, priv->video_fd, 0); + if (priv -> mmap == MAP_FAILED) + { + mp_msg(MSGT_TV, MSGL_INFO, + " MJP: Error mapping video buffers: %s\n", strerror(errno)); + goto err; + } + } + + mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels); + priv->channels = calloc(priv->capability.channels, sizeof(struct video_channel)); + if (!priv->channels) + goto malloc_failed; + memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels); + for (i = 0; i < priv->capability.channels; i++) + { + priv->channels[i].channel = i; + if (ioctl(priv->video_fd, VIDIOCGCHAN, &priv->channels[i]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); + break; + } + mp_msg(MSGT_TV, MSGL_INFO, " %d: %s: %s%s%s%s (tuner:%d, norm:%s)\n", i, + priv->channels[i].name, + (priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", + (priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", + (priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "", + (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "", + priv->channels[i].tuners, + norm2name(priv->channels[i].norm)); + } + priv->act_channel = 0; + + if (!(priv->capability.type & VID_TYPE_CAPTURE)) + { + mp_msg(MSGT_TV, MSGL_ERR, "Only grabbing supported (for overlay use another program)\n"); + goto err; + } + + if ( !tv_param_mjpeg ) + { + /* map grab buffer */ + if (ioctl(priv->video_fd, VIDIOCGMBUF, &priv->mbuf) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get mbuf failed: %s\n", strerror(errno)); + goto err; + } + + mp_msg(MSGT_TV, MSGL_V, "mbuf: size=%d, frames=%d\n", + priv->mbuf.size, priv->mbuf.frames); + priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE, + MAP_SHARED, priv->video_fd, 0); + if (priv->mmap == (unsigned char *)-1) + { + mp_msg(MSGT_TV, MSGL_ERR, "Unable to map memory for buffers: %s\n", strerror(errno)); + goto err; + } + mp_msg(MSGT_TV, MSGL_DBG2, "our buffer: %p\n", priv->mmap); + + /* num of buffers */ + priv->nbuf = priv->mbuf.frames; + + /* video buffers */ + priv->buf = calloc(priv->nbuf, sizeof(struct video_mmap)); + if (!priv->buf) + goto malloc_failed; + memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap)); + } + + /* init v4l audio even when we don't capture */ + init_v4l_audio(priv); + + if (!priv->capability.audios && !tv_param_force_audio) tv_param_noaudio = 1; + + /* audio init */ + if (!tv_param_noaudio) { + +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + if (tv_param_alsa) + audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); + else + audio_in_init(&priv->audio_in, AUDIO_IN_OSS); +#else + audio_in_init(&priv->audio_in, AUDIO_IN_OSS); +#endif + + if (priv->audio_device) { + audio_in_set_device(&priv->audio_in, priv->audio_device); + } + + if (tv_param_audio_id < priv->capability.audios) + priv->audio_id = tv_param_audio_id; + else + priv->audio_id = 0; + audio_in_set_samplerate(&priv->audio_in, 44100); + if (priv->capability.audios) { + audio_in_set_channels(&priv->audio_in, priv->audio_channels[priv->audio_id]); + } else { + if (tv_param_forcechan >= 0) { + audio_in_set_channels(&priv->audio_in, tv_param_forcechan); + } else { + audio_in_set_channels(&priv->audio_in, 2); + } + } + if (audio_in_setup(&priv->audio_in) < 0) return 0; + setup_audio_buffer_sizes(priv); + } + + return(1); + +malloc_failed: + if (priv->channels) + free(priv->channels); + if (priv->buf) + free(priv->buf); +err: + if (priv->video_fd != -1) + close(priv->video_fd); + return(0); +} + +static int uninit(priv_t *priv) +{ + unsigned long num; + priv->shutdown = 1; + + mp_msg(MSGT_TV, MSGL_V, "Waiting for threads to finish... "); + if (!tv_param_noaudio) { + pthread_join(priv->audio_grabber_thread, NULL); + pthread_mutex_destroy(&priv->audio_starter); + pthread_mutex_destroy(&priv->skew_mutex); + } + pthread_mutex_destroy(&priv->video_buffer_mutex); + pthread_join(priv->video_grabber_thread, NULL); + mp_msg(MSGT_TV, MSGL_V, "done\n"); + + if (priv->capability.audios) { + priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; + ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); + } + + if ( tv_param_mjpeg ) + { + num = -1; + if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, "\n MJP: ioctl MJPIOC_QBUF_CAPT failed: %s\n", strerror(errno)); + } + } + else + { + // We need to munmap as close don't close mem mappings + if(munmap(priv->mmap,priv->mbuf.size)) + mp_msg(MSGT_TV, MSGL_ERR, "Munmap failed: %s\n",strerror(errno)); + } + + if(close(priv->video_fd)) + mp_msg(MSGT_TV, MSGL_ERR, "Close tv failed: %s\n",strerror(errno)); + + audio_in_uninit(&priv->audio_in); + + if (priv->video_ringbuffer) { + int i; + for (i = 0; i < priv->video_buffer_size_current; i++) { + free(priv->video_ringbuffer[i]); + } + free(priv->video_ringbuffer); + } + + if (priv->video_timebuffer) + free(priv->video_timebuffer); + if (priv->video_avg_buffer) + free(priv->video_avg_buffer); + if (!tv_param_noaudio) { + if (priv->audio_ringbuffer) + free(priv->audio_ringbuffer); + if (priv->audio_skew_buffer) + free(priv->audio_skew_buffer); + } + + return(1); +} + +static int get_capture_buffer_size(priv_t *priv) +{ + int bufsize, cnt; + + if (tv_param_buffer_size >= 0) { + bufsize = tv_param_buffer_size*1024*1024; + } else { +#ifdef HAVE_SYS_SYSINFO_H + struct sysinfo si; + + sysinfo(&si); + if (si.totalram<2*1024*1024) { + bufsize = 1024*1024; + } else { + bufsize = si.totalram/2; + } +#else + bufsize = 16*1024*1024; +#endif + } + + cnt = bufsize/(priv->height*priv->bytesperline); + if (cnt < 2) cnt = 2; + + return cnt; +} + +static int start(priv_t *priv) +{ + int i; + int bytes_per_sample; + + if (ioctl(priv->video_fd, VIDIOCGPICT, &priv->picture) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); + return(0); + } + + priv->picture.palette = format2palette(priv->format); + priv->picture.depth = palette2depth(priv->picture.palette); + + if (priv->format != IMGFMT_BGR15) { + priv->bytesperline = priv->width * priv->picture.depth / 8; + } else { + priv->bytesperline = priv->width * 2; + } + + mp_msg(MSGT_TV, MSGL_V, "Picture values:\n"); + mp_msg(MSGT_TV, MSGL_V, " Depth: %d, Palette: %s (Format: %s)\n", priv->picture.depth, + PALETTE(priv->picture.palette), vo_format_name(priv->format)); + mp_msg(MSGT_TV, MSGL_V, " Brightness: %d, Hue: %d, Colour: %d, Contrast: %d\n", + priv->picture.brightness, priv->picture.hue, + priv->picture.colour, priv->picture.contrast); + + + if (ioctl(priv->video_fd, VIDIOCSPICT, &priv->picture) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set picture failed: %s\n", strerror(errno)); + } + + if ( !tv_param_mjpeg ) + { + priv->nbuf = priv->mbuf.frames; + for (i=0; i < priv->nbuf; i++) + { + priv->buf[i].format = priv->picture.palette; + priv->buf[i].frame = i; + priv->buf[i].width = priv->width; + priv->buf[i].height = priv->height; + mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]); + } + } + +#if 0 + { + struct video_play_mode pmode; + + pmode.mode = VID_PLAY_NORMAL; + pmode.p1 = 1; + pmode.p2 = 0; + if (ioctl(priv->video_fd, VIDIOCSPLAYMODE, &pmode) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set play mode failed: %s\n", strerror(errno)); +// return(0); + } + } +#endif + +#if 0 + { + struct video_window win; + + win.x = 0; + win.y = 0; + win.width = priv->width; + win.height = priv->height; + win.chromakey = -1; + win.flags = 0; + //win.clipcount = 0; + + ioctl(priv->video_fd, VIDIOCSWIN, &win); + } + + // initialize video capture + if (ioctl(priv->video_fd, VIDIOCCAPTURE, &one) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "FATAL: ioctl ccapture failed: %s\n", strerror(errno)); + return(0); + } +#endif + + /* setup audio parameters */ + if (!tv_param_noaudio) { + setup_audio_buffer_sizes(priv); + bytes_per_sample = priv->audio_in.bytes_per_sample; + priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); + if (!priv->audio_skew_buffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); + return 0; + } + + priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); + if (!priv->audio_ringbuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); + return 0; + } + + priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate + *priv->audio_in.channels + *bytes_per_sample); + priv->audio_head = 0; + priv->audio_tail = 0; + priv->audio_cnt = 0; + priv->audio_drop = 0; + priv->audio_skew = 0; + priv->audio_skew_total = 0; + priv->audio_recv_blocks_total = 0; + priv->audio_sent_blocks_total = 0; + } + + /* setup video parameters */ + if (priv->immediate_mode) { + priv->video_buffer_size_max = VID_BUF_SIZE_IMMEDIATE; + } else { + priv->video_buffer_size_max = get_capture_buffer_size(priv); + } + priv->video_buffer_size_current = 0; + + if (!tv_param_noaudio) { + if (priv->video_buffer_size_max < 3.0*priv->fps*priv->audio_secs_per_block) { + mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" + "You will probably experience heavy framedrops.\n"); + } + } + + mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", + priv->video_buffer_size_max, + priv->video_buffer_size_max*priv->height*priv->bytesperline/(1024*1024)); + + priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(unsigned char*)); + if (!priv->video_ringbuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); + return 0; + } + for (i = 0; i < priv->video_buffer_size_max; i++) + priv->video_ringbuffer[i] = NULL; + + priv->video_timebuffer = calloc(priv->video_buffer_size_max, sizeof(long long)); + if (!priv->video_timebuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); + return 0; + } + priv->video_avg_buffer = malloc(sizeof(long long) * VIDEO_AVG_BUFFER_SIZE); + if (!priv->video_avg_buffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate period buffer: %s\n", strerror(errno)); + return 0; + } + priv->video_interval_sum = (1e6/priv->fps)*VIDEO_AVG_BUFFER_SIZE; + for (i = 0; i < VIDEO_AVG_BUFFER_SIZE; i++) { + priv->video_avg_buffer[i] = 1e6/priv->fps; + } + + priv->video_avg_ptr = 0; + + priv->video_head = 0; + priv->video_tail = 0; + priv->video_cnt = 0; + priv->first = 1; + + if (priv->capability.audios) { + /* enable audio */ + if (tv_param_volume >= 0) + priv->audio[priv->audio_id].volume = tv_param_volume; + if (tv_param_bass >= 0) + priv->audio[priv->audio_id].bass = tv_param_bass; + if (tv_param_treble >= 0) + priv->audio[priv->audio_id].treble = tv_param_treble; + if (tv_param_balance >= 0) + priv->audio[priv->audio_id].balance = tv_param_balance; + priv->audio[priv->audio_id].flags &= ~VIDEO_AUDIO_MUTE; + mp_msg(MSGT_TV, MSGL_V, "Enabling tv audio. Requested setup is:\n"); + mp_msg(MSGT_TV, MSGL_V, "id=%d vol=%d bass=%d treble=%d balance=%d mode=%s", + priv->audio_id, + priv->audio[priv->audio_id].volume, priv->audio[priv->audio_id].bass, priv->audio[priv->audio_id].treble, + priv->audio[priv->audio_id].balance, audio_mode2name(priv->audio[priv->audio_id].mode)); + mp_msg(MSGT_TV, MSGL_V, " chan=%d\n", priv->audio_channels[priv->audio_id]); + ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); + } + + /* launch capture threads */ + priv->shutdown = 0; + if (!tv_param_noaudio) { + pthread_mutex_init(&priv->audio_starter, NULL); + pthread_mutex_init(&priv->skew_mutex, NULL); + pthread_mutex_lock(&priv->audio_starter); + pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); + } + pthread_mutex_init(&priv->video_buffer_mutex, NULL); + /* we'll launch the video capture later, when a first request for a frame arrives */ + + return(1); +} + + +static int control(priv_t *priv, int cmd, void *arg) +{ + mp_msg(MSGT_TV, MSGL_DBG2, "\ndebug: control(priv=%p, cmd=%d, arg=%p)\n", + priv, cmd, arg); + switch(cmd) + { + /* ========== GENERIC controls =========== */ + case TVI_CONTROL_IS_VIDEO: + { + if (priv->capability.type & VID_TYPE_CAPTURE) + return(TVI_CONTROL_TRUE); + return(TVI_CONTROL_FALSE); + } + case TVI_CONTROL_IS_AUDIO: + if (tv_param_force_audio) return(TVI_CONTROL_TRUE); + if (priv->channels[priv->act_channel].flags & VIDEO_VC_AUDIO) + { + return(TVI_CONTROL_TRUE); + } + return(TVI_CONTROL_FALSE); + case TVI_CONTROL_IS_TUNER: + { +// if (priv->capability.type & VID_TYPE_TUNER) + if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) + return(TVI_CONTROL_TRUE); + return(TVI_CONTROL_FALSE); + } + + /* ========== VIDEO controls =========== */ + case TVI_CONTROL_VID_GET_FORMAT: + { + int output_fmt = -1; + + output_fmt = priv->format; + if ( tv_param_mjpeg ) + { + mp_msg(MSGT_TV, MSGL_INFO, " MJP: setting sh_video->format to mjpg\n"); + output_fmt = 0x47504a4d; + output_fmt = 0x67706a6d; + *(int *)arg = output_fmt; + mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", "mjpg"); + } + else + { + *(int *)arg = output_fmt; + mp_msg(MSGT_TV, MSGL_V, "Output format: %s\n", vo_format_name(output_fmt)); + } + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_VID_SET_FORMAT: + priv->format = *(int *)arg; + // !HACK! v4l uses BGR format instead of RGB + // and we have to correct this. Fortunately, + // tv.c reads later the format back so we + // can persuade it to use what we want. + if (IMGFMT_IS_RGB(priv->format)) { + priv->format &= ~IMGFMT_RGB_MASK; + priv->format |= IMGFMT_BGR; + } + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_PLANES: + *(int *)arg = 1; /* FIXME, also not needed at this time */ + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_BITS: + *(int *)arg = palette2depth(format2palette(priv->format)); + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_WIDTH: + *(int *)arg = priv->width; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_CHK_WIDTH: + { + int req_width = *(int *)arg; + + mp_msg(MSGT_TV, MSGL_V, "Requested width: %d\n", req_width); + if ((req_width >= priv->capability.minwidth) && + (req_width <= priv->capability.maxwidth)) + return(TVI_CONTROL_TRUE); + return(TVI_CONTROL_FALSE); + } + case TVI_CONTROL_VID_SET_WIDTH: + priv->width = *(int *)arg; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_HEIGHT: + *(int *)arg = priv->height; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_CHK_HEIGHT: + { + int req_height = *(int *)arg; + + mp_msg(MSGT_TV, MSGL_V, "Requested height: %d\n", req_height); + if ((req_height >= priv->capability.minheight) && + (req_height <= priv->capability.maxheight)) + return(TVI_CONTROL_TRUE); + return(TVI_CONTROL_FALSE); + } + case TVI_CONTROL_VID_SET_HEIGHT: + priv->height = *(int *)arg; + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_GET_PICTURE: + if (ioctl(priv->video_fd, VIDIOCGPICT, &priv->picture) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_SET_PICTURE: + if (ioctl(priv->video_fd, VIDIOCSPICT, &priv->picture) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_VID_SET_BRIGHTNESS: + priv->picture.brightness = (327*(*(int *)arg+100)) + 68; + return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); + case TVI_CONTROL_VID_SET_HUE: + priv->picture.hue = (327*(*(int *)arg+100)) + 68; + return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); + case TVI_CONTROL_VID_SET_SATURATION: + priv->picture.colour = (327*(*(int *)arg+100)) + 68; + return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); + case TVI_CONTROL_VID_SET_CONTRAST: + priv->picture.contrast = (327*(*(int *)arg+100)) + 68; + return control(priv, TVI_CONTROL_VID_SET_PICTURE, 0); + case TVI_CONTROL_VID_GET_BRIGHTNESS: + if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; + *(int*)arg = ((int)priv->picture.brightness-68)/327-100; + return 1; + case TVI_CONTROL_VID_GET_HUE: + if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; + *(int*)arg = ((int)priv->picture.hue-68)/327-100; + return 1; + case TVI_CONTROL_VID_GET_SATURATION: + if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; + *(int*)arg = ((int)priv->picture.colour-68)/327-100; + return 1; + case TVI_CONTROL_VID_GET_CONTRAST: + if(!control(priv, TVI_CONTROL_VID_GET_PICTURE, 0)) return 0; + *(int*)arg = ((int)priv->picture.contrast-68)/327-100; + return 1; + case TVI_CONTROL_VID_GET_FPS: + *(float *)arg=priv->fps; + return(TVI_CONTROL_TRUE); + + /* ========== TUNER controls =========== */ + case TVI_CONTROL_TUN_GET_FREQ: + { + unsigned long freq; + + if (ioctl(priv->video_fd, VIDIOCGFREQ, &freq) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get freq failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + + /* tuner uses khz not mhz ! */ +// if (priv->tuner.flags & VIDEO_TUNER_LOW) +// freq /= 1000; + *(unsigned long *)arg = freq; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_TUN_SET_FREQ: + { + /* argument is in MHz ! */ + unsigned long freq = *(unsigned long *)arg; + + if (priv->capability.audios) { + priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; + ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); + } + + mp_msg(MSGT_TV, MSGL_V, "requested frequency: %.3f\n", (float)freq/16); + + /* tuner uses khz not mhz ! */ +// if (priv->tuner.flags & VIDEO_TUNER_LOW) +// freq *= 1000; +// mp_msg(MSGT_TV, MSGL_V, " requesting from driver: freq=%.3f\n", (float)freq/16); + if (ioctl(priv->video_fd, VIDIOCSFREQ, &freq) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set freq failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + usleep(100000); // wait to suppress noise during switching + + if (priv->capability.audios) { + priv->audio[priv->audio_id].flags &= ~VIDEO_AUDIO_MUTE; + ioctl(priv->video_fd, VIDIOCSAUDIO, &priv->audio[priv->audio_id]); + } + + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_TUN_GET_TUNER: + { + if (ioctl(priv->video_fd, VIDIOCGTUNER, &priv->tuner) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get tuner failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + + mp_msg(MSGT_TV, MSGL_V, "Tuner (%s) range: %lu -> %lu\n", priv->tuner.name, + priv->tuner.rangelow, priv->tuner.rangehigh); + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_TUN_SET_TUNER: + { + if (ioctl(priv->video_fd, VIDIOCSTUNER, &priv->tuner) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set tuner failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_TUN_SET_NORM: + { + int req_mode = *(int *)arg; + + if ((req_mode != TV_NORM_PAL) && (req_mode != TV_NORM_NTSC) && (req_mode != TV_NORM_SECAM) + && (req_mode != TV_NORM_PALNC) && (req_mode != TV_NORM_PALM) && (req_mode != TV_NORM_PALN) + && (req_mode != TV_NORM_NTSCJP)) { + mp_msg(MSGT_TV, MSGL_ERR, "Unknown norm!\n"); + return(TVI_CONTROL_FALSE); + } + + if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) { + int prev_mode; + + control(priv, TVI_CONTROL_TUN_GET_TUNER, 0); + if (((req_mode == TV_NORM_PAL + || req_mode == TV_NORM_PALNC + || req_mode == TV_NORM_PALN) && !(priv->tuner.flags & VIDEO_TUNER_PAL)) || + ((req_mode == TV_NORM_NTSC + || req_mode == TV_NORM_NTSCJP + || req_mode == TV_NORM_PALM) && !(priv->tuner.flags & VIDEO_TUNER_NTSC)) || + ((req_mode == TV_NORM_SECAM) && !(priv->tuner.flags & VIDEO_TUNER_SECAM))) + { + mp_msg(MSGT_TV, MSGL_ERR, "Tuner isn't capable to set norm!\n"); + return(TVI_CONTROL_FALSE); + } + + prev_mode = priv->tuner.mode; + + switch(req_mode) { + case TV_NORM_PAL: + case TV_NORM_PALNC: + case TV_NORM_PALN: + priv->tuner.mode = VIDEO_MODE_PAL; + break; + case TV_NORM_NTSC: + case TV_NORM_NTSCJP: + case TV_NORM_PALM: + priv->tuner.mode = VIDEO_MODE_NTSC; + break; + case TV_NORM_SECAM: + priv->tuner.mode = VIDEO_MODE_SECAM; + break; + } + + if (control(priv, TVI_CONTROL_TUN_SET_TUNER, &priv->tuner) != TVI_CONTROL_TRUE) { + // norm setting failed, but maybe it's only because it's fixed + if (priv->tuner.mode != prev_mode) return(TVI_CONTROL_FALSE); // no it really failed + } + + } + + switch(req_mode) { + case TV_NORM_PAL: + priv->channels[priv->act_channel].norm = VIDEO_MODE_PAL; + break; + case TV_NORM_NTSC: + priv->channels[priv->act_channel].norm = VIDEO_MODE_NTSC; + break; + case TV_NORM_SECAM: + priv->channels[priv->act_channel].norm = VIDEO_MODE_SECAM; + break; + case TV_NORM_PALNC: + priv->channels[priv->act_channel].norm = 3; + break; + case TV_NORM_PALM: + priv->channels[priv->act_channel].norm = 4; + break; + case TV_NORM_PALN: + priv->channels[priv->act_channel].norm = 5; + break; + case TV_NORM_NTSCJP: + priv->channels[priv->act_channel].norm = 6; + break; + } + if (ioctl(priv->video_fd, VIDIOCSCHAN, &priv->channels[priv->act_channel]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set chan failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + + if (ioctl(priv->video_fd, VIDIOCGCAP, &priv->capability) == -1) { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + + if(req_mode == TV_NORM_PAL || req_mode == TV_NORM_SECAM || req_mode == TV_NORM_PALN || req_mode == TV_NORM_PALNC) { + priv->fps = PAL_FPS; + } + + if(req_mode == TV_NORM_NTSC || req_mode == TV_NORM_NTSCJP || req_mode == TV_NORM_PALM) { + priv->fps = NTSC_FPS; + } + + if(priv->height > priv->capability.maxheight) { + priv->height = priv->capability.maxheight; + } + + if(priv->width > priv->capability.maxwidth) { + priv->width = priv->capability.maxwidth; + } + + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_TUN_GET_NORM: + { + *(int *)arg = priv->tuner.mode; + + return(TVI_CONTROL_TRUE); + } + + /* ========== AUDIO controls =========== */ + case TVI_CONTROL_AUD_GET_FORMAT: + { + *(int *)arg = AF_FORMAT_S16_LE; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_CHANNELS: + { + *(int *)arg = priv->audio_in.channels; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_SAMPLERATE: + { + *(int *)arg = priv->audio_in.samplerate; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_GET_SAMPLESIZE: + { + *(int *)arg = priv->audio_in.bytes_per_sample; + return(TVI_CONTROL_TRUE); + } + case TVI_CONTROL_AUD_SET_SAMPLERATE: + { + if (audio_in_set_samplerate(&priv->audio_in, *(int *)arg) < 0) return TVI_CONTROL_FALSE; + setup_audio_buffer_sizes(priv); + return(TVI_CONTROL_TRUE); + } + /* ========== SPECIFIC controls =========== */ + case TVI_CONTROL_SPC_GET_INPUT: + { + int req_chan = *(int *)arg; + int i; + + for (i = 0; i < priv->capability.channels; i++) + { + if (priv->channels[i].channel == req_chan) + break; + } + + priv->act_channel = i; + + if (ioctl(priv->video_fd, VIDIOCGCHAN, &priv->channels[i]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + return(TVI_CONTROL_TRUE); + } + + case TVI_CONTROL_SPC_SET_INPUT: + { + struct video_channel chan; + int req_chan = *(int *)arg; + int i; + + if (req_chan >= priv->capability.channels) + { + mp_msg(MSGT_TV, MSGL_ERR, "Invalid input requested: %d, valid: 0-%d\n", + req_chan, priv->capability.channels - 1); + return(TVI_CONTROL_FALSE); + } + + for (i = 0; i < priv->capability.channels; i++) + { + if (priv->channels[i].channel == req_chan) + chan = priv->channels[i]; + } + + if (ioctl(priv->video_fd, VIDIOCSCHAN, &chan) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "ioctl set chan failed: %s\n", strerror(errno)); + return(TVI_CONTROL_FALSE); + } + mp_msg(MSGT_TV, MSGL_INFO, "Using input '%s'\n", chan.name); + + priv->act_channel = i; + + /* update tuner state */ +// if (priv->capability.type & VID_TYPE_TUNER) + if (priv->channels[priv->act_channel].flags & VIDEO_VC_TUNER) + control(priv, TVI_CONTROL_TUN_GET_TUNER, 0); + + /* update local channel list */ + control(priv, TVI_CONTROL_SPC_GET_INPUT, &req_chan); + return(TVI_CONTROL_TRUE); + case TVI_CONTROL_IMMEDIATE: + priv->immediate_mode = 1; + return(TVI_CONTROL_TRUE); + } + } + + return(TVI_CONTROL_UNKNOWN); +} + +// copies a video frame +// for RGB (i.e. BGR in mplayer) flips the image upside down +// for YV12 swaps the 2nd and 3rd plane +static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *source) +{ + int i; + unsigned char *sptr; + + // YV12 uses VIDEO_PALETTE_YUV420P, but the planes are swapped + if (priv->format == IMGFMT_YV12) { + memcpy(dest, source, priv->width * priv->height); + memcpy(dest+priv->width * priv->height*5/4, source+priv->width * priv->height, priv->width * priv->height/4); + memcpy(dest+priv->width * priv->height, source+priv->width * priv->height*5/4, priv->width * priv->height/4); + return; + } + + switch (priv->picture.palette) { + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_RGB32: + case VIDEO_PALETTE_RGB555: + case VIDEO_PALETTE_RGB565: + sptr = source + (priv->height-1)*priv->bytesperline; + for (i = 0; i < priv->height; i++) { + memcpy(dest, sptr, priv->bytesperline); + dest += priv->bytesperline; + sptr -= priv->bytesperline; + } + break; + case VIDEO_PALETTE_UYVY: + case VIDEO_PALETTE_YUV420P: + default: + memcpy(dest, source, priv->bytesperline * priv->height); + } + +} + +// maximum skew change, in frames +#define MAX_SKEW_DELTA 0.6 +static void *video_grabber(void *data) +{ +#define MAXTOL (priv->nbuf) + priv_t *priv = (priv_t*)data; + struct timeval curtime; + long long skew, prev_skew, xskew, interval, prev_interval; + int frame; + int i; + int framecount; + int tolerance; + unsigned long num; + + /* start the capture process */ + + if ( tv_param_mjpeg ) + { + mp_msg(MSGT_TV, MSGL_INFO, " MJP: gonna capture ! \n"); + for (i=0; i < priv->nbuf; i++) { + num = i; + if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, + "\n MJP: ioctl MJPIOC_QBUF_CAPT b failed: %s\n", strerror(errno)); + } + } + } + else + { + for (i=0; i < priv->nbuf; i++) { + if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[i]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno)); + } + } + } + + gettimeofday(&curtime, NULL); + priv->starttime = (long long)1e6*curtime.tv_sec + curtime.tv_usec; + priv->audio_skew_measure_time = 0; + pthread_mutex_unlock(&priv->audio_starter); + xskew = 0; + skew = 0; + interval = 0; + + prev_interval = 0; + prev_skew = 0; + + tolerance = MAXTOL; + + for (framecount = 0; !priv->shutdown;) + { + for (i = 0; i < priv->nbuf && !priv->shutdown; i++, framecount++) { + + if (priv->immediate_mode) { + while (priv->video_cnt == priv->video_buffer_size_max) { + usleep(10000); + if (priv->shutdown) { + return NULL; + } + } + } + + frame = i; + + if ( tv_param_mjpeg ) + { + while (ioctl(priv->video_fd, MJPIOC_SYNC, &priv->buf[frame].frame) < 0 && + (errno == EAGAIN || errno == EINTR)); + + } + else + { + while (ioctl(priv->video_fd, VIDIOCSYNC, &priv->buf[frame].frame) < 0 && + (errno == EAGAIN || errno == EINTR)); + } + mp_dbg(MSGT_TV, MSGL_DBG3, "\npicture sync failed\n"); + + gettimeofday(&curtime, NULL); + if (!priv->immediate_mode) { + interval = (long long)1e6*curtime.tv_sec + curtime.tv_usec - priv->starttime; + } else { + interval = (long long)1e6*framecount/priv->fps; + } + + if (!priv->immediate_mode) { + long long period, orig_interval; + + if (tolerance == 0) { + if (interval - prev_interval == 0) { + mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta = 0\n"); + } else if ((interval - prev_interval < (long long)0.85e6/priv->fps) + || (interval - prev_interval > (long long)1.15e6/priv->fps) ) { + mp_msg(MSGT_TV, MSGL_V, "\nvideo capture thread: frame delta ~ %.1lf fps\n", + (double)1e6/(interval - prev_interval)); + } + } + + // correct the rate fluctuations on a small scale + orig_interval = interval; + period = priv->video_interval_sum/VIDEO_AVG_BUFFER_SIZE; + if (interval - prev_interval > 105*period/100) { + if (tolerance > 0) { + mp_msg(MSGT_TV, MSGL_DBG3, "correcting timestamp\n"); + interval = prev_interval + priv->video_interval_sum/VIDEO_AVG_BUFFER_SIZE; + tolerance--; + } else { + mp_msg(MSGT_TV, MSGL_DBG3, "bad - frames were dropped\n"); + tolerance = MAXTOL; + } + } else { + if (tolerance < MAXTOL) { + mp_msg(MSGT_TV, MSGL_DBG3, "fluctuation overcome\n"); + } + tolerance = MAXTOL; + } + + priv->video_interval_sum -= priv->video_avg_buffer[priv->video_avg_ptr]; + priv->video_avg_buffer[priv->video_avg_ptr++] = orig_interval-prev_interval; + priv->video_interval_sum += orig_interval-prev_interval; + if (priv->video_avg_ptr >= VIDEO_AVG_BUFFER_SIZE) priv->video_avg_ptr = 0; + +// fprintf(stderr, "fps: %lf\n", (double)1e6*VIDEO_AVG_BUFFER_SIZE/priv->video_interval_sum); + + // interpolate the skew in time + pthread_mutex_lock(&priv->skew_mutex); + xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; + pthread_mutex_unlock(&priv->skew_mutex); + // correct extreme skew changes to avoid (especially) moving backwards in time + if (xskew - prev_skew > (interval - prev_interval)*MAX_SKEW_DELTA) { + skew = prev_skew + (interval - prev_interval)*MAX_SKEW_DELTA; + } else if (xskew - prev_skew < -(interval - prev_interval)*MAX_SKEW_DELTA) { + skew = prev_skew - (interval - prev_interval)*MAX_SKEW_DELTA; + } else { + skew = xskew; + } + } + + mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n", + (interval != prev_interval) ? (double)1e6/(interval - prev_interval) : -1, + (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); + mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); + + prev_skew = skew; + prev_interval = interval; + + /* allocate a new buffer, if needed */ + pthread_mutex_lock(&priv->video_buffer_mutex); + if (priv->video_buffer_size_current < priv->video_buffer_size_max) { + if (priv->video_cnt == priv->video_buffer_size_current) { + unsigned char *newbuf = calloc(priv->bytesperline, priv->height); + if (newbuf) { + memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, + (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *)); + memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail, + (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long)); + priv->video_ringbuffer[priv->video_tail] = newbuf; + if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; + priv->video_buffer_size_current++; + } + } + } + pthread_mutex_unlock(&priv->video_buffer_mutex); + + if (priv->video_cnt == priv->video_buffer_size_current) { + if (!priv->immediate_mode) { + mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); + } + } else { + if (priv->immediate_mode) { + priv->video_timebuffer[priv->video_tail] = interval; + } else { + // compensate for audio skew + // negative skew => there are more audio samples, increase interval + // positive skew => less samples, shorten the interval + priv->video_timebuffer[priv->video_tail] = interval - skew; + } + + if ( tv_param_mjpeg ) + copy_frame(priv, priv->video_ringbuffer[priv->video_tail], + priv->mmap+(priv->mjpeg_bufsize)*i); + else + copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->mmap+priv->mbuf.offsets[frame]); + priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; + priv->video_cnt++; + } + + if ( tv_param_mjpeg ) + { + num = frame; + if (ioctl(priv->video_fd, MJPIOC_QBUF_CAPT, &num) < 0) + { + mp_msg(MSGT_TV, MSGL_ERR, "\n MJP: ioctl MJPIOC_QBUF_CAPT end failed: %s\n", + strerror(errno)); + continue; + } + } + else + { + if (ioctl(priv->video_fd, VIDIOCMCAPTURE, &priv->buf[frame]) == -1) + { + mp_msg(MSGT_TV, MSGL_ERR, "\nioctl mcapture failed: %s\n", strerror(errno)); + continue; + } + } + + } + + } + mp_msg(MSGT_TV, MSGL_INFO, " MJP: returning! \n"); + return NULL; +} + +static double grab_video_frame(priv_t *priv, char *buffer, int len) +{ + double interval; + + if (priv->first) { + pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); + priv->first = 0; + } + + while (priv->video_cnt == 0) { + usleep(10000); + } + + pthread_mutex_lock(&priv->video_buffer_mutex); + interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; + memcpy(buffer, priv->video_ringbuffer[priv->video_head], len); + priv->video_cnt--; + priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; + pthread_mutex_unlock(&priv->video_buffer_mutex); + + return interval; +} + +static int get_video_framesize(priv_t *priv) +{ + return(priv->bytesperline * priv->height); +} + +static void *audio_grabber(void *data) +{ + priv_t *priv = (priv_t*)data; + struct timeval tv; + int i, audio_skew_ptr = 0; + long long current_time, prev_skew = 0; + + pthread_mutex_lock(&priv->audio_starter); + + audio_in_start_capture(&priv->audio_in); + for (i = 0; i < priv->aud_skew_cnt; i++) + priv->audio_skew_buffer[i] = 0; + + for (; !priv->shutdown;) + { + if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) + continue; + + gettimeofday(&tv, NULL); + + priv->audio_recv_blocks_total++; + current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->starttime; + + priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; + priv->audio_skew_buffer[audio_skew_ptr] = current_time + - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total; + priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; + audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; + + pthread_mutex_lock(&priv->skew_mutex); + // linear interpolation - here we interpolate current skew value + // from the moving average, which we expect to be in the middle + // of the interval + if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { + priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; + priv->audio_skew += (priv->audio_skew*priv->aud_skew_cnt)/(2*priv->audio_recv_blocks_total-priv->aud_skew_cnt); + } else { + // this smoothes the evolution of audio_skew at startup a bit + priv->audio_skew = ((priv->aud_skew_cnt+priv->audio_recv_blocks_total)*priv->audio_skew_total)/(priv->aud_skew_cnt*priv->audio_recv_blocks_total); + } + // current skew factor (assuming linearity) + // used for further interpolation in video_grabber + // probably overkill but seems to be necessary for + // stress testing by dropping half of the audio frames ;) + // especially when using ALSA with large block sizes + // where audio_skew remains a long while behind + if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { + priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); + } else { + priv->audio_skew_factor = 0.0; + } + + priv->audio_skew_measure_time = current_time; + prev_skew = priv->audio_skew; + pthread_mutex_unlock(&priv->skew_mutex); + + if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { + mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); + priv->audio_drop++; + } else { + priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; + priv->audio_cnt++; + } + } + return NULL; +} + +static double grab_audio_frame(priv_t *priv, char *buffer, int len) +{ + mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", + priv, buffer, len); + + if (priv->first) { + pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); + priv->first = 0; + } + + // compensate for dropped audio frames + if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { + priv->audio_drop--; + priv->audio_sent_blocks_total++; + memset(buffer, 0, len); + return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; + } + + while (priv->audio_head == priv->audio_tail) { + usleep(10000); + } + memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); + priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; + priv->audio_cnt--; + priv->audio_sent_blocks_total++; + return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; +} + +static int get_audio_framesize(priv_t *priv) +{ + return(priv->audio_in.blocksize); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/tvi_v4l2.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,1746 @@ +/* +** Video 4 Linux 2 input +** +** This file is part of MPlayer, see http://mplayerhq.hu/ for info. +** +** (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de> +** (c) 2003 Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz> +** +** File licensed under the GPL, see http://www.fsf.org/ for more info. +** +** Some ideas are based on works from +** Alex Beregszaszi <alex@fsn.hu> +** Gerd Knorr <kraxel@bytesex.org> +** +** CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! +*/ + +/* + +known issues: +- norm setting isn't consistent with tvi_v4l +- the same for volume/bass/treble/balance + +*/ + +#include "config.h" + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#ifdef HAVE_SYS_SYSINFO_H +#include <sys/sysinfo.h> +#endif +#include <linux/types.h> +#include <linux/videodev2.h> +#include "mp_msg.h" +#include "libvo/img_format.h" +#include "libaf/af_format.h" +#include "tv.h" +#include "audio_in.h" + +/* information about this file */ +static tvi_info_t info = { + "Video 4 Linux 2 input", + "v4l2", + "Martin Olschewski <olschewski@zpr.uni-koeln.de>", + "first try, more to come ;-)" +}; + +struct map { + struct v4l2_buffer buf; + void *addr; + size_t len; +}; + +#define BUFFER_COUNT 6 + +/* private data */ +typedef struct { + /* video */ + char *video_dev; + int video_fd; + int mp_format; + struct v4l2_capability capability; + struct v4l2_input input; + struct v4l2_format format; + struct v4l2_standard standard; + struct v4l2_tuner tuner; + struct map *map; + int mapcount; + int frames; + volatile long long first_frame; + long long curr_frame; + /* audio video interleaving ;-) */ + volatile int streamon; + pthread_t audio_grabber_thread; + pthread_mutex_t skew_mutex; + + /* 2nd level video buffers */ + int first; + int immediate_mode; + + int video_buffer_size_max; + volatile int video_buffer_size_current; + unsigned char **video_ringbuffer; + long long *video_timebuffer; + volatile int video_head; + volatile int video_tail; + volatile int video_cnt; + pthread_t video_grabber_thread; + pthread_mutex_t video_buffer_mutex; + + /* audio */ + char *audio_dev; + audio_in_t audio_in; + + long long audio_start_time; + int audio_buffer_size; + int aud_skew_cnt; + unsigned char *audio_ringbuffer; + long long *audio_skew_buffer; + long long *audio_skew_delta_buffer; + volatile int audio_head; + volatile int audio_tail; + volatile int audio_cnt; + volatile long long audio_skew; + volatile double audio_skew_factor; + volatile long long audio_skew_measure_time; + volatile int audio_drop; + volatile int shutdown; + + int audio_inited; + double audio_secs_per_block; + long long audio_usecs_per_block; + long long audio_skew_total; + long long audio_skew_delta_total; + long audio_recv_blocks_total; + long audio_sent_blocks_total; + pthread_mutex_t audio_mutex; + int audio_insert_null_samples; + volatile long audio_null_blocks_inserted; + volatile long long dropped_frames_timeshift; + long long dropped_frames_compensated; +} priv_t; + +#include "tvi_def.h" + +static void *audio_grabber(void *data); +static void *video_grabber(void *data); + +/**********************************************************************\ + + Only few of the fourccs are the same in v4l2 and mplayer: + + IMGFMT_YVU9 == V4L2_PIX_FMT_YVU410 + IMGFMT_YV12 == V4L2_PIX_FMT_YVU420 + IMGFMT_NV12 == V4L2_PIX_FMT_NV12 + IMGFMT_422P == V4L2_PIX_FMT_YUV422P + IMGFMT_411P == V4L2_PIX_FMT_YUV411P + IMGFMT_UYVY == V4L2_PIX_FMT_UYVY + IMGFMT_Y41P == V4L2_PIX_FMT_Y41P + + This may be an useful translation table for some others: + + IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332 + IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555 + IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565 + IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24 + IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32 + IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24 + IMGFMT_BGR32 == V4L2_PIX_FMT_BGR32 + IMGFMT_Y800 == V4L2_PIX_FMT_GREY + IMGFMT_IF09 == V4L2_PIX_FMT_YUV410 + IMGFMT_I420 == V4L2_PIX_FMT_YUV420 + IMGFMT_YUY2 == V4L2_PIX_FMT_YUYV + +\**********************************************************************/ + +/* +** Translate a mplayer fourcc to a video4linux2 pixel format. +*/ +static int fcc_mp2vl(int fcc) +{ + switch (fcc) { + case IMGFMT_RGB8: return V4L2_PIX_FMT_RGB332; + case IMGFMT_BGR15: return V4L2_PIX_FMT_RGB555; + case IMGFMT_BGR16: return V4L2_PIX_FMT_RGB565; + case IMGFMT_RGB24: return V4L2_PIX_FMT_RGB24; + case IMGFMT_RGB32: return V4L2_PIX_FMT_RGB32; + case IMGFMT_BGR24: return V4L2_PIX_FMT_BGR24; + case IMGFMT_BGR32: return V4L2_PIX_FMT_BGR32; + case IMGFMT_Y800: return V4L2_PIX_FMT_GREY; + case IMGFMT_IF09: return V4L2_PIX_FMT_YUV410; + case IMGFMT_I420: return V4L2_PIX_FMT_YUV420; + case IMGFMT_YUY2: return V4L2_PIX_FMT_YUYV; + case IMGFMT_YV12: return V4L2_PIX_FMT_YVU420; + case IMGFMT_UYVY: return V4L2_PIX_FMT_UYVY; + } + return fcc; +} + +/* +** Translate a video4linux2 fourcc aka pixel format to mplayer. +*/ +static int fcc_vl2mp(int fcc) +{ + switch (fcc) { + case V4L2_PIX_FMT_RGB332: return IMGFMT_RGB8; + case V4L2_PIX_FMT_RGB555: return IMGFMT_BGR15; + case V4L2_PIX_FMT_RGB565: return IMGFMT_BGR16; + case V4L2_PIX_FMT_RGB24: return IMGFMT_RGB24; + case V4L2_PIX_FMT_RGB32: return IMGFMT_RGB32; + case V4L2_PIX_FMT_BGR24: return IMGFMT_BGR24; + case V4L2_PIX_FMT_BGR32: return IMGFMT_BGR32; + case V4L2_PIX_FMT_GREY: return IMGFMT_Y800; + case V4L2_PIX_FMT_YUV410: return IMGFMT_IF09; + case V4L2_PIX_FMT_YUV420: return IMGFMT_I420; + case V4L2_PIX_FMT_YVU420: return IMGFMT_YV12; + case V4L2_PIX_FMT_YUYV: return IMGFMT_YUY2; + case V4L2_PIX_FMT_UYVY: return IMGFMT_UYVY; + } + return fcc; +} + +/* +** Translate a video4linux2 fourcc aka pixel format +** to a human readable string. +*/ +static const char *pixfmt2name(int pixfmt) +{ + static char unknown[24]; + + switch (pixfmt) { + case V4L2_PIX_FMT_RGB332: return "RGB332"; + case V4L2_PIX_FMT_RGB555: return "RGB555"; + case V4L2_PIX_FMT_RGB565: return "RGB565"; + case V4L2_PIX_FMT_RGB555X: return "RGB555X"; + case V4L2_PIX_FMT_RGB565X: return "RGB565X"; + case V4L2_PIX_FMT_BGR24: return "BGR24"; + case V4L2_PIX_FMT_RGB24: return "RGB24"; + case V4L2_PIX_FMT_BGR32: return "BGR32"; + case V4L2_PIX_FMT_RGB32: return "RGB32"; + case V4L2_PIX_FMT_GREY: return "GREY"; + case V4L2_PIX_FMT_YVU410: return "YVU410"; + case V4L2_PIX_FMT_YVU420: return "YVU420"; + case V4L2_PIX_FMT_YUYV: return "YUYV"; + case V4L2_PIX_FMT_UYVY: return "UYVY"; +/* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */ +/* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */ + case V4L2_PIX_FMT_YUV422P: return "YUV422P"; + case V4L2_PIX_FMT_YUV411P: return "YUV411P"; + case V4L2_PIX_FMT_Y41P: return "Y41P"; + case V4L2_PIX_FMT_NV12: return "NV12"; + case V4L2_PIX_FMT_NV21: return "NV21"; + case V4L2_PIX_FMT_YUV410: return "YUV410"; + case V4L2_PIX_FMT_YUV420: return "YUV420"; + case V4L2_PIX_FMT_YYUV: return "YYUV"; + case V4L2_PIX_FMT_HI240: return "HI240"; + case V4L2_PIX_FMT_WNVA: return "WNVA"; + } + sprintf(unknown, "unknown (0x%x)", pixfmt); + return unknown; +} + + +/* +** Gives the depth of a video4linux2 fourcc aka pixel format in bits. +*/ +static int pixfmt2depth(int pixfmt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_RGB332: + return 8; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565X: + return 16; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: + return 24; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + return 32; + case V4L2_PIX_FMT_GREY: + return 8; + case V4L2_PIX_FMT_YVU410: + return 9; + case V4L2_PIX_FMT_YVU420: + return 12; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV411P: + return 16; + case V4L2_PIX_FMT_Y41P: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + return 12; + case V4L2_PIX_FMT_YUV410: + return 9; + case V4L2_PIX_FMT_YUV420: + return 12; + case V4L2_PIX_FMT_YYUV: + return 16; + case V4L2_PIX_FMT_HI240: + return 8; + + } + return 0; +} + +static int amode2v4l(int amode) +{ + switch (amode) { + case 0: + return V4L2_TUNER_MODE_MONO; + case 1: + return V4L2_TUNER_MODE_STEREO; + case 2: + return V4L2_TUNER_MODE_LANG1; + case 3: + return V4L2_TUNER_MODE_LANG2; + default: + return -1; + } +} + + +// sets and sanitizes audio buffer/block sizes +static void setup_audio_buffer_sizes(priv_t *priv) +{ + int bytes_per_sample = priv->audio_in.bytes_per_sample; + double fps = (double)priv->standard.frameperiod.denominator / + priv->standard.frameperiod.numerator; + int seconds = priv->video_buffer_size_max/fps; + + if (seconds < 5) seconds = 5; + if (seconds > 500) seconds = 500; + + // make the audio buffer at least as the video buffer capacity (or 5 seconds) long + priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate + *priv->audio_in.channels + *bytes_per_sample/priv->audio_in.blocksize; + if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; + + // make the skew buffer at least 1 second long + priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate + *priv->audio_in.channels + *bytes_per_sample/priv->audio_in.blocksize; + if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; + + mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", + priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); +} + +static void init_audio(priv_t *priv) +{ + if (priv->audio_inited) return; + + if (!tv_param_noaudio) { +#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) + if (tv_param_alsa) + audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); + else + audio_in_init(&priv->audio_in, AUDIO_IN_OSS); +#else + audio_in_init(&priv->audio_in, AUDIO_IN_OSS); +#endif + + if (priv->audio_dev) { + audio_in_set_device(&priv->audio_in, priv->audio_dev); + } + + audio_in_set_samplerate(&priv->audio_in, 44100); + if (priv->capability.capabilities & V4L2_CAP_TUNER) { + if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) { + audio_in_set_channels(&priv->audio_in, 2); + } else { + audio_in_set_channels(&priv->audio_in, 1); + } + } else { + if (tv_param_forcechan >= 0) { + audio_in_set_channels(&priv->audio_in, tv_param_forcechan); + } else { + audio_in_set_channels(&priv->audio_in, 2); + } + } + + if (audio_in_setup(&priv->audio_in) < 0) return; + + priv->audio_inited = 1; + } +} + +#if 0 +/* +** the number of milliseconds elapsed between time0 and time1 +*/ +static size_t difftv(struct timeval time1, struct timeval time0) +{ + return (time1.tv_sec - time0.tv_sec) * 1000 + + (time1.tv_usec - time0.tv_usec) / 1000; +} +#endif + +/* +** Get current video capture format. +*/ +static int getfmt(priv_t *priv) +{ + int i; + + priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if ((i = ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get format failed: %s\n", + info.short_name, strerror(errno)); + } + return i; +} + + +/* +** Get current video capture standard. +*/ +static int getstd(priv_t *priv) +{ + v4l2_std_id id; + int i=0; + + if (ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get standard failed: %s\n", + info.short_name, strerror(errno)); + return -1; + } + do { + priv->standard.index = i++; + if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { + return -1; + } + } while (priv->standard.id != id); + return 0; +} + +/***********************************************************************\ + * * + * * + * Interface to mplayer * + * * + * * +\***********************************************************************/ + +static int set_mute(priv_t *priv, int value) +{ + struct v4l2_control control; + control.id = V4L2_CID_AUDIO_MUTE; + control.value = value; + if (ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) { + mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set mute failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + return 1; +} + +/* +** MPlayer uses values from -100 up to 100 for controls. +** Here they are scaled to what the tv card needs and applied. +*/ +static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) { + struct v4l2_queryctrl qctrl; + + qctrl.id = control->id; + if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + + if (val_signed) { + if (control->value < 0) { + control->value = qctrl.default_value + control->value * + (qctrl.default_value - qctrl.minimum) / 100; + } else { + control->value = qctrl.default_value + control->value * + (qctrl.maximum - qctrl.default_value) / 100; + } + } else { + if (control->value < 50) { + control->value = qctrl.default_value + (control->value-50) * + (qctrl.default_value - qctrl.minimum) / 50; + } else { + control->value = qctrl.default_value + (control->value-50) * + (qctrl.maximum - qctrl.default_value) / 50; + } + } + + + if (ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) { + mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl set %s %d failed: %s\n", + info.short_name, qctrl.name, control->value, strerror(errno)); + return TVI_CONTROL_FALSE; + } + mp_msg(MSGT_TV, MSGL_V, "%s: set %s: %d [%d, %d]\n", info.short_name, + qctrl.name, control->value, qctrl.minimum, qctrl.maximum); + + return TVI_CONTROL_TRUE; +} + + +/* +** Scale the control values back to what mplayer needs. +*/ +static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) { + struct v4l2_queryctrl qctrl; + + qctrl.id = control->id; + if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + + if (ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) { + mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl get %s failed: %s\n", + info.short_name, qctrl.name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + mp_msg(MSGT_TV, MSGL_V, "%s: get %s: %d [%d, %d]\n", info.short_name, + qctrl.name, control->value, qctrl.minimum, qctrl.maximum); + + if (val_signed) { + if (control->value < qctrl.default_value) { + control->value = (control->value - qctrl.default_value) * 100 / + (qctrl.default_value - qctrl.minimum); + } else { + control->value = (control->value - qctrl.default_value) * 100 / + (qctrl.maximum - qctrl.default_value); + } + } else { + if (control->value < qctrl.default_value) { + control->value = (control->value - qctrl.default_value) * 50 / + (qctrl.default_value - qctrl.minimum) + 50; + } else { + control->value = (control->value - qctrl.default_value) * 50 / + (qctrl.maximum - qctrl.default_value) + 50; + } + } + + return TVI_CONTROL_TRUE; +} + +static int control(priv_t *priv, int cmd, void *arg) +{ + struct v4l2_control control; + struct v4l2_frequency frequency; + + switch(cmd) { + case TVI_CONTROL_IS_VIDEO: + return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? + TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; + case TVI_CONTROL_IS_AUDIO: + if (tv_param_force_audio) return TVI_CONTROL_TRUE; + case TVI_CONTROL_IS_TUNER: + return priv->capability.capabilities & V4L2_CAP_TUNER? + TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; + case TVI_CONTROL_IMMEDIATE: + priv->immediate_mode = 1; + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_FPS: + *(float *)arg = (float)priv->standard.frameperiod.denominator / + priv->standard.frameperiod.numerator; + mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name, + *(float *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_BITS: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat); + mp_msg(MSGT_TV, MSGL_V, "%s: get depth: %d\n", info.short_name, + *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_FORMAT: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat); + mp_msg(MSGT_TV, MSGL_V, "%s: get format: %s\n", info.short_name, + pixfmt2name(priv->format.fmt.pix.pixelformat)); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_SET_FORMAT: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg); + priv->format.fmt.pix.field = V4L2_FIELD_ANY; + + priv->mp_format = *(int *)arg; + mp_msg(MSGT_TV, MSGL_V, "%s: set format: %s\n", info.short_name, + pixfmt2name(priv->format.fmt.pix.pixelformat)); + if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers + might even always return the default parameters -> update the format here*/ + priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_WIDTH: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + *(int *)arg = priv->format.fmt.pix.width; + mp_msg(MSGT_TV, MSGL_V, "%s: get width: %d\n", info.short_name, + *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_CHK_WIDTH: + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_SET_WIDTH: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + priv->format.fmt.pix.width = *(int *)arg; + mp_msg(MSGT_TV, MSGL_V, "%s: set width: %d\n", info.short_name, + *(int *)arg); + if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set width failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_HEIGHT: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + *(int *)arg = priv->format.fmt.pix.height; + mp_msg(MSGT_TV, MSGL_V, "%s: get height: %d\n", info.short_name, + *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_CHK_HEIGHT: + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_SET_HEIGHT: + if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; + priv->format.fmt.pix.height = *(int *)arg; + priv->format.fmt.pix.field = V4L2_FIELD_ANY; + mp_msg(MSGT_TV, MSGL_V, "%s: set height: %d\n", info.short_name, + *(int *)arg); + if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set height failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_VID_GET_BRIGHTNESS: + control.id = V4L2_CID_BRIGHTNESS; + if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { + *(int *)arg = control.value; + return TVI_CONTROL_TRUE; + } + return TVI_CONTROL_FALSE; + case TVI_CONTROL_VID_SET_BRIGHTNESS: + control.id = V4L2_CID_BRIGHTNESS; + control.value = *(int *)arg; + return set_control(priv, &control, 1); + case TVI_CONTROL_VID_GET_HUE: + control.id = V4L2_CID_HUE; + if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { + *(int *)arg = control.value; + return TVI_CONTROL_TRUE; + } + return TVI_CONTROL_FALSE; + case TVI_CONTROL_VID_SET_HUE: + control.id = V4L2_CID_HUE; + control.value = *(int *)arg; + return set_control(priv, &control, 1); + case TVI_CONTROL_VID_GET_SATURATION: + control.id = V4L2_CID_SATURATION; + if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { + *(int *)arg = control.value; + return TVI_CONTROL_TRUE; + } + return TVI_CONTROL_FALSE; + case TVI_CONTROL_VID_SET_SATURATION: + control.id = V4L2_CID_SATURATION; + control.value = *(int *)arg; + return set_control(priv, &control, 1); + case TVI_CONTROL_VID_GET_CONTRAST: + control.id = V4L2_CID_CONTRAST; + if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { + *(int *)arg = control.value; + return TVI_CONTROL_TRUE; + } + return TVI_CONTROL_FALSE; + case TVI_CONTROL_VID_SET_CONTRAST: + control.id = V4L2_CID_CONTRAST; + control.value = *(int *)arg; + return set_control(priv, &control, 1); + case TVI_CONTROL_TUN_GET_FREQ: + frequency.tuner = 0; + frequency.type = V4L2_TUNER_ANALOG_TV; + if (ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) { + mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl get frequency failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + *(int *)arg = frequency.frequency; + return TVI_CONTROL_TRUE; + case TVI_CONTROL_TUN_SET_FREQ: +#if 0 + set_mute(priv, 1); + usleep(100000); // wait to suppress noise during switching +#endif + frequency.tuner = 0; + frequency.type = V4L2_TUNER_ANALOG_TV; + frequency.frequency = *(int *)arg; + if (ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) { + mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set frequency failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } +#if 0 + usleep(100000); // wait to suppress noise during switching + set_mute(priv, 0); +#endif + return TVI_CONTROL_TRUE; + case TVI_CONTROL_TUN_GET_TUNER: + mp_msg(MSGT_TV, MSGL_V, "%s: get tuner\n",info.short_name); + if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_TUN_SET_TUNER: + mp_msg(MSGT_TV, MSGL_V, "%s: set tuner\n",info.short_name); + if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_TUN_GET_NORM: + *(int *)arg = priv->standard.index; + return TVI_CONTROL_TRUE; + case TVI_CONTROL_TUN_SET_NORM: + priv->standard.index = *(int *)arg; + if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum norm failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + mp_msg(MSGT_TV, MSGL_V, "%s: set norm: %s\n", info.short_name, priv->standard.name); + if (ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set norm failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_SPC_GET_NORMID: + { + int i; + for (i = 0;; i++) { + struct v4l2_standard standard; + memset(&standard, 0, sizeof(standard)); + standard.index = i; + if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) + return TVI_CONTROL_FALSE; + if (!strcasecmp(standard.name, (char *)arg)) { + *(int *)arg = i; + return TVI_CONTROL_TRUE; + } + } + return TVI_CONTROL_FALSE; + } + case TVI_CONTROL_SPC_GET_INPUT: + if (ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_SPC_SET_INPUT: + mp_msg(MSGT_TV, MSGL_V, "%s: set input: %d\n", info.short_name, *(int *)arg); + priv->input.index = *(int *)arg; + if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum input failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + if (ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set input failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + return TVI_CONTROL_TRUE; + case TVI_CONTROL_AUD_GET_FORMAT: + init_audio(priv); + if (!priv->audio_inited) return TVI_CONTROL_FALSE; + *(int *)arg = AF_FORMAT_S16_LE; + mp_msg(MSGT_TV, MSGL_V, "%s: get audio format: %d\n", + info.short_name, *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_AUD_GET_SAMPLERATE: + init_audio(priv); + if (!priv->audio_inited) return TVI_CONTROL_FALSE; + *(int *)arg = priv->audio_in.samplerate; + mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplerate: %d\n", + info.short_name, *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_AUD_GET_SAMPLESIZE: + init_audio(priv); + if (!priv->audio_inited) return TVI_CONTROL_FALSE; + *(int *)arg = priv->audio_in.bytes_per_sample; + mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplesize: %d\n", + info.short_name, *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_AUD_GET_CHANNELS: + init_audio(priv); + if (!priv->audio_inited) return TVI_CONTROL_FALSE; + *(int *)arg = priv->audio_in.channels; + mp_msg(MSGT_TV, MSGL_V, "%s: get audio channels: %d\n", + info.short_name, *(int *)arg); + return TVI_CONTROL_TRUE; + case TVI_CONTROL_AUD_SET_SAMPLERATE: + init_audio(priv); + mp_msg(MSGT_TV, MSGL_V, "%s: set audio samplerate: %d\n", + info.short_name, *(int *)arg); + if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; +// setup_audio_buffer_sizes(priv); + return TVI_CONTROL_TRUE; + } + mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd); + return(TVI_CONTROL_UNKNOWN); +} + + +#define PRIV ((priv_t *) (tvi_handle->priv)) + +/* handler creator - entry point ! */ +tvi_handle_t *tvi_init_v4l2(char *video_dev, char *audio_dev) +{ + tvi_handle_t *tvi_handle; + + /* new_handle initializes priv with memset 0 */ + tvi_handle = new_handle(); + if (!tvi_handle) { + return NULL; + } + PRIV->video_fd = -1; + + PRIV->video_dev = strdup(video_dev? video_dev: "/dev/video0"); + if (!PRIV->video_dev) { + free_handle(tvi_handle); + return NULL; + } + + if (audio_dev) { + PRIV->audio_dev = strdup(audio_dev); + if (!PRIV->audio_dev) { + free(PRIV->video_dev); + free_handle(tvi_handle); + return NULL; + } + } + + return tvi_handle; +} + +#undef PRIV + + +static int uninit(priv_t *priv) +{ + int i, frames, dropped = 0; + + priv->shutdown = 1; + if(priv->video_grabber_thread) + pthread_join(priv->video_grabber_thread, NULL); + pthread_mutex_destroy(&priv->video_buffer_mutex); + + if (priv->streamon) { + struct v4l2_buffer buf; + + /* get performance */ + frames = 1 + (priv->curr_frame - priv->first_frame + + priv->standard.frameperiod.numerator * 500000 / + priv->standard.frameperiod.denominator) * + priv->standard.frameperiod.denominator / + priv->standard.frameperiod.numerator / 1000000; + dropped = frames - priv->frames; + + /* turn off streaming */ + if (ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamoff failed: %s\n", + info.short_name, strerror(errno)); + } + priv->streamon = 0; + + /* unqueue all remaining buffers */ + memset(&buf,0,sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf)); + } + + /* unmap all buffers */ + for (i = 0; i < priv->mapcount; i++) { + if (munmap(priv->map[i].addr, priv->map[i].len) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n", + info.short_name, strerror(errno)); + } + } + + /* stop audio thread */ + if (!tv_param_noaudio && priv->audio_grabber_thread) { + pthread_join(priv->audio_grabber_thread, NULL); + pthread_mutex_destroy(&priv->skew_mutex); + pthread_mutex_destroy(&priv->audio_mutex); + } + + set_mute(priv, 1); + + /* free memory and close device */ + free(priv->map); priv->map = NULL; + priv->mapcount = 0; + if(priv->video_fd!=-1)close(priv->video_fd); priv->video_fd = -1; + free(priv->video_dev); priv->video_dev = NULL; + + if (priv->video_ringbuffer) { + int i; + for (i = 0; i < priv->video_buffer_size_current; i++) { + free(priv->video_ringbuffer[i]); + } + free(priv->video_ringbuffer); + } + if (priv->video_timebuffer) + free(priv->video_timebuffer); + if (!tv_param_noaudio) { + if (priv->audio_ringbuffer) + free(priv->audio_ringbuffer); + if (priv->audio_skew_buffer) + free(priv->audio_skew_buffer); + if (priv->audio_skew_delta_buffer) + free(priv->audio_skew_delta_buffer); + } + + /* show some nice statistics ;-) */ + mp_msg(MSGT_TV, MSGL_INFO, + "%s: %d frames successfully processed, %d frames dropped.\n", + info.short_name, priv->frames, dropped); + mp_msg(MSGT_TV, MSGL_V, "%s: up to %u video frames buffered.\n", + info.short_name, priv->video_buffer_size_current); + return 1; +} + + +/* initialisation */ +static int init(priv_t *priv) +{ + int i; + + priv->audio_ringbuffer = NULL; + priv->audio_skew_buffer = NULL; + priv->audio_skew_delta_buffer = NULL; + + priv->audio_inited = 0; + + /* Open the video device. */ + priv->video_fd = open(priv->video_dev, O_RDWR); + if (priv->video_fd < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: unable to open '%s': %s\n", + info.short_name, priv->video_dev, strerror(errno)); + uninit(priv); + return 0; + } + mp_msg(MSGT_TV, MSGL_DBG2, "%s: video fd: %s: %d\n", + info.short_name, priv->video_dev, priv->video_fd); + + /* + ** Query the video capabilities and current settings + ** for further control calls. + */ + if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query capabilities failed: %s\n", + info.short_name, strerror(errno)); + uninit(priv); + return 0; + } + + if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + { + mp_msg(MSGT_TV, MSGL_ERR, "Device %s is not a video capture device.\n", + priv->video_dev); + return 0; + } + + if (getfmt(priv) < 0) { + uninit(priv); + return 0; + } + getstd(priv); + /* + ** if this device has got a tuner query it's settings + ** otherwise set some nice defaults + */ + if (priv->capability.capabilities & V4L2_CAP_TUNER) { + if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", + info.short_name, strerror(errno)); + uninit(priv); + return 0; + } + } + mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.card); + if (priv->capability.capabilities & V4L2_CAP_TUNER) { + mp_msg(MSGT_TV, MSGL_INFO, " Tuner cap:%s%s%s\n", + (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", + (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", + (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); + mp_msg(MSGT_TV, MSGL_INFO, " Tuner rxs:%s%s%s%s\n", + (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "", + (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", + (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", + (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); + } + mp_msg(MSGT_TV, MSGL_INFO, " Capabilites:%s%s%s%s%s%s%s%s%s%s%s\n", + priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? + " video capture": "", + priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT? + " video output": "", + priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY? + " video overlay": "", + priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE? + " VBI capture device": "", + priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT? + " VBI output": "", + priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE? + " RDS data capture": "", + priv->capability.capabilities & V4L2_CAP_TUNER? + " tuner": "", + priv->capability.capabilities & V4L2_CAP_AUDIO? + " audio": "", + priv->capability.capabilities & V4L2_CAP_READWRITE? + " read/write": "", + priv->capability.capabilities & V4L2_CAP_ASYNCIO? + " async i/o": "", + priv->capability.capabilities & V4L2_CAP_STREAMING? + " streaming": ""); + mp_msg(MSGT_TV, MSGL_INFO, " supported norms:"); + for (i = 0;; i++) { + struct v4l2_standard standard; + memset(&standard, 0, sizeof(standard)); + standard.index = i; + if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) + break; + mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, standard.name); + } + mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:"); + for (i = 0; 1; i++) { + struct v4l2_input input; + + input.index = i; + if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { + break; + } + mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, input.name); + } + if (ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", + info.short_name, strerror(errno)); + } + mp_msg(MSGT_TV, MSGL_INFO, "\n Current input: %d\n", i); + for (i = 0; ; i++) { + struct v4l2_fmtdesc fmtdesc; + + fmtdesc.index = i; + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { + break; + } + mp_msg(MSGT_TV, MSGL_V, " Format %-6s (%2d bits, %s): %s\n", + pixfmt2name(fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), + fmtdesc.description, vo_format_name(fcc_vl2mp(fmtdesc.pixelformat))); + } + mp_msg(MSGT_TV, MSGL_INFO, " Current format: %s\n", + pixfmt2name(priv->format.fmt.pix.pixelformat)); + + /* set some nice defaults */ + if (getfmt(priv) < 0) return 0; + priv->format.fmt.pix.width = 640; + priv->format.fmt.pix.height = 480; + if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", + info.short_name, strerror(errno)); + uninit(priv); + return 0; + } + +// if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !tv_param_force_audio) tv_param_noaudio = 1; + + if (priv->capability.capabilities & V4L2_CAP_TUNER) { + struct v4l2_control control; + if (tv_param_amode >= 0) { + mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); + priv->tuner.audmode = amode2v4l(tv_param_amode); + if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", + info.short_name, strerror(errno)); + return TVI_CONTROL_FALSE; + } + } + mp_msg(MSGT_TV, MSGL_INFO, "%s: current audio mode is :%s%s%s%s\n", info.short_name, + (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", + (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", + (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", + (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); + + if (tv_param_volume >= 0) { + control.id = V4L2_CID_AUDIO_VOLUME; + control.value = tv_param_volume; + set_control(priv, &control, 0); + } + if (tv_param_bass >= 0) { + control.id = V4L2_CID_AUDIO_BASS; + control.value = tv_param_bass; + set_control(priv, &control, 0); + } + if (tv_param_treble >= 0) { + control.id = V4L2_CID_AUDIO_TREBLE; + control.value = tv_param_treble; + set_control(priv, &control, 0); + } + if (tv_param_balance >= 0) { + control.id = V4L2_CID_AUDIO_BALANCE; + control.value = tv_param_balance; + set_control(priv, &control, 0); + } + } + + return 1; +} + +static int get_capture_buffer_size(priv_t *priv) +{ + int bufsize, cnt; + int w = priv->format.fmt.pix.width; + int h = priv->format.fmt.pix.height; + int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); + int bytesperline = w*d/8; + + if (tv_param_buffer_size >= 0) { + bufsize = tv_param_buffer_size*1024*1024; + } else { +#ifdef HAVE_SYS_SYSINFO_H + struct sysinfo si; + + sysinfo(&si); + if (si.totalram<2*1024*1024) { + bufsize = 1024*1024; + } else { + bufsize = si.totalram/2; + } +#else + bufsize = 16*1024*1024; +#endif + } + + cnt = bufsize/(h*bytesperline); + if (cnt < 2) cnt = 2; + + return cnt; +} + +/* that's the real start, we'got the format parameters (checked with control) */ +static int start(priv_t *priv) +{ + struct v4l2_requestbuffers request; + int i; + + /* setup audio parameters */ + + init_audio(priv); + if (!tv_param_noaudio && !priv->audio_inited) return 0; + + /* we need this to size the audio buffer properly */ + if (priv->immediate_mode) { + priv->video_buffer_size_max = 2; + } else { + priv->video_buffer_size_max = get_capture_buffer_size(priv); + } + + if (!tv_param_noaudio) { + setup_audio_buffer_sizes(priv); + priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); + if (!priv->audio_skew_buffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); + return 0; + } + priv->audio_skew_delta_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); + if (!priv->audio_skew_delta_buffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); + return 0; + } + + priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); + if (!priv->audio_ringbuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); + return 0; + } + + priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate + *priv->audio_in.channels + *priv->audio_in.bytes_per_sample); + priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; + priv->audio_head = 0; + priv->audio_tail = 0; + priv->audio_cnt = 0; + priv->audio_drop = 0; + priv->audio_skew = 0; + priv->audio_skew_total = 0; + priv->audio_skew_delta_total = 0; + priv->audio_recv_blocks_total = 0; + priv->audio_sent_blocks_total = 0; + priv->audio_null_blocks_inserted = 0; + priv->audio_insert_null_samples = 0; + priv->dropped_frames_timeshift = 0; + priv->dropped_frames_compensated = 0; + + pthread_mutex_init(&priv->skew_mutex, NULL); + pthread_mutex_init(&priv->audio_mutex, NULL); + } + + /* setup video parameters */ + if (!tv_param_noaudio) { + if (priv->video_buffer_size_max < (3*priv->standard.frameperiod.denominator) / + priv->standard.frameperiod.numerator + *priv->audio_secs_per_block) { + mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" + "You will probably experience heavy framedrops.\n"); + } + } + + { + int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; + + mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", + priv->video_buffer_size_max, + priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); + } + + priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(unsigned char*)); + if (!priv->video_ringbuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); + return 0; + } + for (i = 0; i < priv->video_buffer_size_max; i++) + priv->video_ringbuffer[i] = NULL; + priv->video_timebuffer = calloc(priv->video_buffer_size_max, sizeof(long long)); + if (!priv->video_timebuffer) { + mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); + return 0; + } + + pthread_mutex_init(&priv->video_buffer_mutex, NULL); + + priv->video_head = 0; + priv->video_tail = 0; + priv->video_cnt = 0; + + /* request buffers */ + if (priv->immediate_mode) { + request.count = 2; + } else { + request.count = BUFFER_COUNT; + } + + request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + request.memory = V4L2_MEMORY_MMAP; + if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + + /* query buffers */ + if (!(priv->map = calloc(request.count, sizeof(struct map)))) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + + /* map and queue buffers */ + for (i = 0; i < request.count; i++) { + memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); + priv->map[i].buf.index = i; + priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + priv->map[i].buf.memory = V4L2_MEMORY_MMAP; + if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", + info.short_name, strerror(errno)); + free(priv->map); + priv->map = NULL; + return 0; + } + priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | + PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); + if (priv->map[i].addr == MAP_FAILED) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", + info.short_name, strerror(errno)); + priv->map[i].len = 0; + return 0; + } + priv->map[i].len = priv->map[i].buf.length; + /* count up to make sure this is correct everytime */ + priv->mapcount++; + + if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + } + + /* start audio thread */ + priv->shutdown = 0; + priv->audio_skew_measure_time = 0; + priv->first_frame = 0; + priv->audio_skew = 0; + priv->first = 1; + + set_mute(priv, 0); + + return 1; +} + + +#ifdef HAVE_TV_BSDBT848 +static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) +{ + memset(buffer, 0xCC, len); + return(1); +} +#endif /* HAVE_TV_BSDBT848 */ + +// copies a video frame +static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *source) +{ + int w = priv->format.fmt.pix.width; + int h = priv->format.fmt.pix.height; + int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); + int bytesperline = w*d/8; + + memcpy(dest, source, bytesperline * h); +} + +// maximum skew change, in frames +#define MAX_SKEW_DELTA 0.6 +static void *video_grabber(void *data) +{ + priv_t *priv = (priv_t*)data; + long long skew, prev_skew, xskew, interval, prev_interval, delta; + int i; + int framesize = priv->format.fmt.pix.height*priv->format.fmt.pix.width* + pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; + fd_set rdset; + struct timeval timeout; + struct v4l2_buffer buf; + + xskew = 0; + skew = 0; + interval = 0; + prev_interval = 0; + prev_skew = 0; + + mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name); + if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + priv->streamon = 1; + + if (!tv_param_noaudio) { + pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); + } + + for (priv->frames = 0; !priv->shutdown;) + { + int ret; + + if (priv->immediate_mode) { + while (priv->video_cnt == priv->video_buffer_size_max) { + usleep(10000); + if (priv->shutdown) { + return NULL; + } + } + } + + FD_ZERO (&rdset); + FD_SET (priv->video_fd, &rdset); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); + if (i < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n", + info.short_name, strerror(errno)); + continue; + } + else if (i == 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name); + continue; + } + else if (!FD_ISSET(priv->video_fd, &rdset)) { + continue; + } + + memset(&buf,0,sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); + + if (ret < 0) { + /* + if there's no signal, the buffer might me dequeued + so we query all the buffers to see which one we should + put back to queue + + observed with saa7134 0.2.8 + don't know if is it a bug or (mis)feature + */ + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n", + info.short_name, strerror(errno), buf.index); + for (i = 0; i < priv->mapcount; i++) { + memset(&buf,0,sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.index = i; + ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); + if (ret < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n", + info.short_name, strerror(errno), buf.index); + return 0; + } + if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { + if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + } + } + continue; + } + + /* store the timestamp of the very first frame as reference */ + if (!priv->frames++) { + if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); + priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec; + if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); + } + priv->curr_frame = (long long)buf.timestamp.tv_sec*1e6+buf.timestamp.tv_usec; +// fprintf(stderr, "idx = %d, ts = %lf\n", buf.index, (double)(priv->curr_frame) / 1e6); + + interval = priv->curr_frame - priv->first_frame; + delta = interval - prev_interval; + + if (!priv->immediate_mode) { + // interpolate the skew in time + if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); + xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; + if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); + // correct extreme skew changes to avoid (especially) moving backwards in time + if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { + skew = prev_skew + delta*MAX_SKEW_DELTA; + } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { + skew = prev_skew - delta*MAX_SKEW_DELTA; + } else { + skew = xskew; + } + } + + mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n", + delta ? (double)1e6/delta : -1, + (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); + mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); + + prev_skew = skew; + prev_interval = interval; + + /* allocate a new buffer, if needed */ + pthread_mutex_lock(&priv->video_buffer_mutex); + if (priv->video_buffer_size_current < priv->video_buffer_size_max) { + if (priv->video_cnt == priv->video_buffer_size_current) { + unsigned char *newbuf = malloc(framesize); + if (newbuf) { + memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, + (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *)); + memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail, + (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long)); + priv->video_ringbuffer[priv->video_tail] = newbuf; + if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; + priv->video_buffer_size_current++; + } + } + } + pthread_mutex_unlock(&priv->video_buffer_mutex); + + if (priv->video_cnt == priv->video_buffer_size_current) { + if (!priv->immediate_mode) { + mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); + if (priv->audio_insert_null_samples) { + pthread_mutex_lock(&priv->audio_mutex); + priv->dropped_frames_timeshift += delta; + pthread_mutex_unlock(&priv->audio_mutex); + } + } + } else { + if (priv->immediate_mode) { + priv->video_timebuffer[priv->video_tail] = 0; + } else { + // compensate for audio skew + // negative skew => there are more audio samples, increase interval + // positive skew => less samples, shorten the interval + priv->video_timebuffer[priv->video_tail] = interval - skew; + if (priv->audio_insert_null_samples && priv->video_timebuffer[priv->video_tail] > 0) { + pthread_mutex_lock(&priv->audio_mutex); + priv->video_timebuffer[priv->video_tail] += + (priv->audio_null_blocks_inserted + - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) + *priv->audio_usecs_per_block; + pthread_mutex_unlock(&priv->audio_mutex); + } + } + + copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->map[buf.index].addr); + priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; + priv->video_cnt++; + } + if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { + mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", + info.short_name, strerror(errno)); + return 0; + } + } + return NULL; +} + +#define MAX_LOOP 50 +static double grab_video_frame(priv_t *priv, char *buffer, int len) +{ + double interval; + int loop_cnt = 0; + + if (priv->first) { + pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); + priv->first = 0; + } + + while (priv->video_cnt == 0) { + usleep(10000); + if (loop_cnt++ > MAX_LOOP) return 0; + } + + pthread_mutex_lock(&priv->video_buffer_mutex); + interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; + memcpy(buffer, priv->video_ringbuffer[priv->video_head], len); + priv->video_cnt--; + priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; + pthread_mutex_unlock(&priv->video_buffer_mutex); + + return interval; +} + +static int get_video_framesize(priv_t *priv) +{ + return priv->format.fmt.pix.sizeimage; +} + +//#define DOUBLESPEED +#ifdef DOUBLESPEED +// for testing purposes only +static void read_doublespeed(priv_t *priv) +{ + char *bufx = calloc(priv->audio_in.blocksize, 2); + short *s; + short *d; + int i; + + audio_in_read_chunk(&priv->audio_in, bufx); + audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize); + + s = bufx; + d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize; + for (i = 0; i < priv->audio_in.blocksize/2; i++) { + *d++ = *s++; + *s++; + } + +} +#endif + +static void *audio_grabber(void *data) +{ + priv_t *priv = (priv_t*)data; + struct timeval tv; + int i, audio_skew_ptr = 0; + long long current_time, prev_skew = 0, prev_skew_uncorr = 0; + long long start_time_avg; + + gettimeofday(&tv, NULL); + start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; + audio_in_start_capture(&priv->audio_in); + for (i = 0; i < priv->aud_skew_cnt; i++) + priv->audio_skew_buffer[i] = 0; + for (i = 0; i < priv->aud_skew_cnt; i++) + priv->audio_skew_delta_buffer[i] = 0; + + for (; !priv->shutdown;) + { +#ifdef DOUBLESPEED + read_doublespeed(priv); +#else + if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) + continue; +#endif + pthread_mutex_lock(&priv->skew_mutex); + if (priv->first_frame == 0) { + // there is no first frame yet (unlikely to happen) + gettimeofday(&tv, NULL); + start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; +// fprintf(stderr, "warning - first frame not yet available!\n"); + pthread_mutex_unlock(&priv->skew_mutex); + continue; + } + pthread_mutex_unlock(&priv->skew_mutex); + + gettimeofday(&tv, NULL); + + priv->audio_recv_blocks_total++; + current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; + + if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { + start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; + priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); + } + +// fprintf(stderr, "spb = %lf, bs = %d, skew = %lf\n", priv->audio_secs_per_block, priv->audio_in.blocksize, +// (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); + + // put the current skew into the ring buffer + priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; + priv->audio_skew_buffer[audio_skew_ptr] = current_time + - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; + priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; + + pthread_mutex_lock(&priv->skew_mutex); + + // skew calculation + + // compute the sliding average of the skews + if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { + priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; + } else { + priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; + } + + // put the current skew change (skew-prev_skew) into the ring buffer + priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; + priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; + priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; + prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value + + audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer + + // sliding average approximates the value in the middle of the interval + // so interpolate the skew value further to the current time + priv->audio_skew += priv->audio_skew_delta_total/2; + + // now finally, priv->audio_skew contains fairly good approximation + // of the current value + + // current skew factor (assuming linearity) + // used for further interpolation in video_grabber + // probably overkill but seems to be necessary for + // stress testing by dropping half of the audio frames ;) + // especially when using ALSA with large block sizes + // where audio_skew remains a long while behind + if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { + priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); + } else { + priv->audio_skew_factor = 0.0; + } + + priv->audio_skew_measure_time = current_time; + prev_skew = priv->audio_skew; + priv->audio_skew += priv->audio_start_time - priv->first_frame; + pthread_mutex_unlock(&priv->skew_mutex); + +// fprintf(stderr, "audio_skew = %lf, delta = %lf\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); + + pthread_mutex_lock(&priv->audio_mutex); + if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { + mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); + priv->audio_drop++; + } else { + priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; + priv->audio_cnt++; + } + pthread_mutex_unlock(&priv->audio_mutex); + } + return NULL; +} + +static double grab_audio_frame(priv_t *priv, char *buffer, int len) +{ + mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", + priv, buffer, len); + + // hack: if grab_audio_frame is called first, it means we are used by mplayer + // => switch to the mode which outputs audio immediately, even if + // it should be silence + if (priv->first) priv->audio_insert_null_samples = 1; + + pthread_mutex_lock(&priv->audio_mutex); + while (priv->audio_insert_null_samples + && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { + // some frames were dropped - drop the corresponding number of audio blocks + if (priv->audio_drop) { + priv->audio_drop--; + } else { + if (priv->audio_head == priv->audio_tail) break; + priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; + } + priv->dropped_frames_compensated += priv->audio_usecs_per_block; + } + + // compensate for dropped audio frames + if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { + priv->audio_drop--; + memset(buffer, 0, len); + goto out; + } + + if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { + // return silence to avoid desync and stuttering + memset(buffer, 0, len); + priv->audio_null_blocks_inserted++; + goto out; + } + + pthread_mutex_unlock(&priv->audio_mutex); + while (priv->audio_head == priv->audio_tail) { + // this is mencoder => just wait until some audio is available + usleep(10000); + } + pthread_mutex_lock(&priv->audio_mutex); + memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); + priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; + priv->audio_cnt--; +out: + pthread_mutex_unlock(&priv->audio_mutex); + priv->audio_sent_blocks_total++; + return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; +} + +static int get_audio_framesize(priv_t *priv) +{ + return(priv->audio_in.blocksize); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/url.c Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,373 @@ +/* + * URL Helper + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + * + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <inttypes.h> + +#include "url.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)-1) +#endif + +URL_t* +url_new(const char* url) { + int pos1, pos2,v6addr = 0; + URL_t* Curl = NULL; + char *escfilename=NULL; + char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL; + int jumpSize = 3; + + if( url==NULL ) return NULL; + + if (strlen(url) > (SIZE_MAX / 3 - 1)) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + escfilename=malloc(strlen(url)*3+1); + if (!escfilename ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + + // Create the URL container + Curl = malloc(sizeof(URL_t)); + if( Curl==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + + // Initialisation of the URL container members + memset( Curl, 0, sizeof(URL_t) ); + + url_escape_string(escfilename,url); + + // Copy the url in the URL container + Curl->url = strdup(escfilename); + if( Curl->url==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + mp_msg(MSGT_OPEN,MSGL_V,"Filename for url is now %s\n",escfilename); + + // extract the protocol + ptr1 = strstr(escfilename, "://"); + if( ptr1==NULL ) { + // Check for a special case: "sip:" (without "//"): + if (strstr(escfilename, "sip:") == escfilename) { + ptr1 = (char *)&url[3]; // points to ':' + jumpSize = 1; + } else { + mp_msg(MSGT_NETWORK,MSGL_V,"Not an URL!\n"); + goto err_out; + } + } + pos1 = ptr1-escfilename; + Curl->protocol = malloc(pos1+1); + if( Curl->protocol==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + strncpy(Curl->protocol, escfilename, pos1); + Curl->protocol[pos1] = '\0'; + + // jump the "://" + ptr1 += jumpSize; + pos1 += jumpSize; + + // check if a username:password is given + ptr2 = strstr(ptr1, "@"); + ptr3 = strstr(ptr1, "/"); + if( ptr3!=NULL && ptr3<ptr2 ) { + // it isn't really a username but rather a part of the path + ptr2 = NULL; + } + if( ptr2!=NULL ) { + // We got something, at least a username... + int len = ptr2-ptr1; + Curl->username = malloc(len+1); + if( Curl->username==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + strncpy(Curl->username, ptr1, len); + Curl->username[len] = '\0'; + + ptr3 = strstr(ptr1, ":"); + if( ptr3!=NULL && ptr3<ptr2 ) { + // We also have a password + int len2 = ptr2-ptr3-1; + Curl->username[ptr3-ptr1]='\0'; + Curl->password = malloc(len2+1); + if( Curl->password==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + strncpy( Curl->password, ptr3+1, len2); + Curl->password[len2]='\0'; + } + ptr1 = ptr2+1; + pos1 = ptr1-escfilename; + } + + // before looking for a port number check if we have an IPv6 type numeric address + // in IPv6 URL the numeric address should be inside square braces. + ptr2 = strstr(ptr1, "["); + ptr3 = strstr(ptr1, "]"); + ptr4 = strstr(ptr1, "/"); + if( ptr2!=NULL && ptr3!=NULL && ptr2 < ptr3 && (!ptr4 || ptr4 > ptr3)) { + // we have an IPv6 numeric address + ptr1++; + pos1++; + ptr2 = ptr3; + v6addr = 1; + } else { + ptr2 = ptr1; + + } + + // look if the port is given + ptr2 = strstr(ptr2, ":"); + // If the : is after the first / it isn't the port + ptr3 = strstr(ptr1, "/"); + if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL; + if( ptr2==NULL ) { + // No port is given + // Look if a path is given + if( ptr3==NULL ) { + // No path/filename + // So we have an URL like http://www.hostname.com + pos2 = strlen(escfilename); + } else { + // We have an URL like http://www.hostname.com/file.txt + pos2 = ptr3-escfilename; + } + } else { + // We have an URL beginning like http://www.hostname.com:1212 + // Get the port number + Curl->port = atoi(ptr2+1); + pos2 = ptr2-escfilename; + } + if( v6addr ) pos2--; + // copy the hostname in the URL container + Curl->hostname = malloc(pos2-pos1+1); + if( Curl->hostname==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + strncpy(Curl->hostname, ptr1, pos2-pos1); + Curl->hostname[pos2-pos1] = '\0'; + + // Look if a path is given + ptr2 = strstr(ptr1, "/"); + if( ptr2!=NULL ) { + // A path/filename is given + // check if it's not a trailing '/' + if( strlen(ptr2)>1 ) { + // copy the path/filename in the URL container + Curl->file = strdup(ptr2); + if( Curl->file==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + } + } + // Check if a filename was given or set, else set it with '/' + if( Curl->file==NULL ) { + Curl->file = malloc(2); + if( Curl->file==NULL ) { + mp_msg(MSGT_NETWORK,MSGL_FATAL,MSGTR_MemAllocFailed); + goto err_out; + } + strcpy(Curl->file, "/"); + } + + free(escfilename); + return Curl; +err_out: + if (escfilename) free(escfilename); + if (Curl) url_free(Curl); + return NULL; +} + +void +url_free(URL_t* url) { + if(!url) return; + if(url->url) free(url->url); + if(url->protocol) free(url->protocol); + if(url->hostname) free(url->hostname); + if(url->file) free(url->file); + if(url->username) free(url->username); + if(url->password) free(url->password); + free(url); +} + + +/* Replace escape sequences in an URL (or a part of an URL) */ +/* works like strcpy(), but without return argument */ +void +url_unescape_string(char *outbuf, const char *inbuf) +{ + unsigned char c,c1,c2; + int i,len=strlen(inbuf); + for (i=0;i<len;i++){ + c = inbuf[i]; + if (c == '%' && i<len-2) { //must have 2 more chars + c1 = toupper(inbuf[i+1]); // we need uppercase characters + c2 = toupper(inbuf[i+2]); + if ( ((c1>='0' && c1<='9') || (c1>='A' && c1<='F')) && + ((c2>='0' && c2<='9') || (c2>='A' && c2<='F')) ) { + if (c1>='0' && c1<='9') c1-='0'; + else c1-='A'-10; + if (c2>='0' && c2<='9') c2-='0'; + else c2-='A'-10; + c = (c1<<4) + c2; + i=i+2; //only skip next 2 chars if valid esc + } + } + *outbuf++ = c; + } + *outbuf++='\0'; //add nullterm to string +} + +static void +url_escape_string_part(char *outbuf, const char *inbuf) { + unsigned char c,c1,c2; + int i,len=strlen(inbuf); + + for (i=0;i<len;i++) { + c = inbuf[i]; + if ((c=='%') && i<len-2 ) { //need 2 more characters + c1=toupper(inbuf[i+1]); c2=toupper(inbuf[i+2]); // need uppercase chars + } else { + c1=129; c2=129; //not escape chars + } + + if( (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c >= 0x7f)) { + *outbuf++ = c; + } else if ( c=='%' && ((c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'F')) && + ((c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'F'))) { + // check if part of an escape sequence + *outbuf++=c; // already + + // dont escape again + mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_URL_StringAlreadyEscaped,c,c1,c2); + // error as this should not happen against RFC 2396 + // to escape a string twice + } else { + /* all others will be escaped */ + c1 = ((c & 0xf0) >> 4); + c2 = (c & 0x0f); + if (c1 < 10) c1+='0'; + else c1+='A'-10; + if (c2 < 10) c2+='0'; + else c2+='A'-10; + *outbuf++ = '%'; + *outbuf++ = c1; + *outbuf++ = c2; + } + } + *outbuf++='\0'; +} + +/* Replace specific characters in the URL string by an escape sequence */ +/* works like strcpy(), but without return argument */ +void +url_escape_string(char *outbuf, const char *inbuf) { + unsigned char c; + int i = 0,j,len = strlen(inbuf); + char* tmp,*unesc = NULL, *in; + + // Look if we have an ip6 address, if so skip it there is + // no need to escape anything in there. + tmp = strstr(inbuf,"://["); + if(tmp) { + tmp = strchr(tmp+4,']'); + if(tmp && (tmp[1] == '/' || tmp[1] == ':' || + tmp[1] == '\0')) { + i = tmp+1-inbuf; + strncpy(outbuf,inbuf,i); + outbuf += i; + tmp = NULL; + } + } + + while(i < len) { + // look for the next char that must be kept + for (j=i;j<len;j++) { + c = inbuf[j]; + if(c=='-' || c=='_' || c=='.' || c=='!' || c=='~' || /* mark characters */ + c=='*' || c=='\'' || c=='(' || c==')' || /* do not touch escape character */ + c==';' || c=='/' || c=='?' || c==':' || c=='@' || /* reserved characters */ + c=='&' || c=='=' || c=='+' || c=='$' || c==',') /* see RFC 2396 */ + break; + } + // we are on a reserved char, write it out + if(j == i) { + *outbuf++ = c; + i++; + continue; + } + // we found one, take that part of the string + if(j < len) { + if(!tmp) tmp = malloc(len+1); + strncpy(tmp,inbuf+i,j-i); + tmp[j-i] = '\0'; + in = tmp; + } else // take the rest of the string + in = (char*)inbuf+i; + + if(!unesc) unesc = malloc(len+1); + // unescape first to avoid escaping escape + url_unescape_string(unesc,in); + // then escape, including mark and other reserved chars + // that can come from escape sequences + url_escape_string_part(outbuf,unesc); + outbuf += strlen(outbuf); + i += strlen(in); + } + *outbuf = '\0'; + if(tmp) free(tmp); + if(unesc) free(unesc); +} + +#ifdef __URL_DEBUG +void +url_debug(const URL_t *url) { + if( url==NULL ) { + printf("URL pointer NULL\n"); + return; + } + if( url->url!=NULL ) { + printf("url=%s\n", url->url ); + } + if( url->protocol!=NULL ) { + printf("protocol=%s\n", url->protocol ); + } + if( url->hostname!=NULL ) { + printf("hostname=%s\n", url->hostname ); + } + printf("port=%d\n", url->port ); + if( url->file!=NULL ) { + printf("file=%s\n", url->file ); + } + if( url->username!=NULL ) { + printf("username=%s\n", url->username ); + } + if( url->password!=NULL ) { + printf("password=%s\n", url->password ); + } +} +#endif //__URL_DEBUG
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/url.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,32 @@ +/* + * URL Helper + * by Bertrand Baudet <bertrand_baudet@yahoo.com> + * (C) 2001, MPlayer team. + */ + +#ifndef __URL_H +#define __URL_H + +//#define __URL_DEBUG + +typedef struct { + char *url; + char *protocol; + char *hostname; + char *file; + unsigned int port; + char *username; + char *password; +} URL_t; + +URL_t* url_new(const char* url); +void url_free(URL_t* url); + +void url_unescape_string(char *outbuf, const char *inbuf); +void url_escape_string(char *outbuf, const char *inbuf); + +#ifdef __URL_DEBUG +void url_debug(const URL_t* url); +#endif // __URL_DEBUG + +#endif // __URL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/vcd_read.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,245 @@ +//=================== VideoCD ========================== +#if defined(linux) || defined(sun) || defined(__bsdi__) + +typedef struct mp_vcd_priv_st mp_vcd_priv_t; + +#if defined(linux) +#include <linux/cdrom.h> +#elif defined(sun) +#include <sys/cdio.h> +static int sun_vcd_read(mp_vcd_priv_t*, int*); +#elif defined(__bsdi__) +#include <dvd.h> +#endif + +struct mp_vcd_priv_st { + int fd; + struct cdrom_tocentry entry; + char buf[VCD_SECTOR_SIZE]; +}; + +static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect){ + vcd->entry.cdte_addr.msf.frame=sect%75; + sect=sect/75; + vcd->entry.cdte_addr.msf.second=sect%60; + sect=sect/60; + vcd->entry.cdte_addr.msf.minute=sect; +} + +static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd){ + return vcd->entry.cdte_addr.msf.frame + + (vcd->entry.cdte_addr.msf.second+ + vcd->entry.cdte_addr.msf.minute*60)*75; +} + +int vcd_seek_to_track(mp_vcd_priv_t* vcd,int track){ + vcd->entry.cdte_format = CDROM_MSF; + vcd->entry.cdte_track = track; + if (ioctl(vcd->fd, CDROMREADTOCENTRY, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); +} + +int vcd_get_track_end(mp_vcd_priv_t* vcd,int track){ + struct cdrom_tochdr tochdr; + if (ioctl(vcd->fd,CDROMREADTOCHDR,&tochdr)==-1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return -1; + } + vcd->entry.cdte_format = CDROM_MSF; + vcd->entry.cdte_track = track<tochdr.cdth_trk1?(track+1):CDROM_LEADOUT; + if (ioctl(vcd->fd, CDROMREADTOCENTRY, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); +} + +mp_vcd_priv_t* vcd_read_toc(int fd){ + struct cdrom_tochdr tochdr; + mp_vcd_priv_t* vcd; + int i, min = 0, sec = 0, frame = 0; + if (ioctl(fd,CDROMREADTOCHDR,&tochdr)==-1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return NULL; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.cdth_trk0); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.cdth_trk1); + for (i=tochdr.cdth_trk0 ; i<=tochdr.cdth_trk1 + 1; i++){ + struct cdrom_tocentry tocentry; + + tocentry.cdte_track = i<=tochdr.cdth_trk1 ? i : CDROM_LEADOUT; + tocentry.cdte_format = CDROM_MSF; + + if (ioctl(fd,CDROMREADTOCENTRY,&tocentry)==-1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); + return NULL; + } + + if (i<=tochdr.cdth_trk1) + mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d mode: %d\n", + (int)tocentry.cdte_track, + (int)tocentry.cdte_adr, + (int)tocentry.cdte_ctrl, + (int)tocentry.cdte_format, + (int)tocentry.cdte_addr.msf.minute, + (int)tocentry.cdte_addr.msf.second, + (int)tocentry.cdte_addr.msf.frame, + (int)tocentry.cdte_datamode + ); + + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + if (i > tochdr.cdth_trk0) + { + min = tocentry.cdte_addr.msf.minute - min; + sec = tocentry.cdte_addr.msf.second - sec; + frame = tocentry.cdte_addr.msf.frame - frame; + if ( frame < 0 ) + { + frame += 75; + sec --; + } + if ( sec < 0 ) + { + sec += 60; + min --; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); + } + min = tocentry.cdte_addr.msf.minute; + sec = tocentry.cdte_addr.msf.second; + frame = tocentry.cdte_addr.msf.frame; + } + } + vcd = malloc(sizeof(mp_vcd_priv_t)); + vcd->fd = fd; + return vcd; +} + +static int vcd_read(mp_vcd_priv_t* vcd,char *mem){ +#if defined(linux) || defined(__bsdi__) + memcpy(vcd->buf,&vcd->entry.cdte_addr.msf,sizeof(struct cdrom_msf)); + if(ioctl(vcd->fd,CDROMREADRAW,vcd->buf)==-1) return 0; // EOF? + memcpy(mem,&vcd->buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA); +#elif defined(sun) + { + int offset; + if (sun_vcd_read(vcd->fd, &offset) <= 0) return 0; + memcpy(mem,&vcd->buf[offset],VCD_SECTOR_DATA); + } +#endif + + vcd->entry.cdte_addr.msf.frame++; + if (vcd->entry.cdte_addr.msf.frame==75){ + vcd->entry.cdte_addr.msf.frame=0; + vcd->entry.cdte_addr.msf.second++; + if (vcd->entry.cdte_addr.msf.second==60){ + vcd->entry.cdte_addr.msf.second=0; + vcd->entry.cdte_addr.msf.minute++; + } + } + + return VCD_SECTOR_DATA; +} + + +#ifdef sun +#include <sys/scsi/generic/commands.h> +#include <sys/scsi/impl/uscsi.h> + +#define SUN_XAREAD 1 /*fails on atapi drives*/ +#define SUN_MODE2READ 2 /*fails on atapi drives*/ +#define SUN_SCSIREAD 3 +#define SUN_VCDREAD SUN_SCSIREAD + +static int sun_vcd_read(mp_vcd_priv_t* vcd, int *offset) +{ +#if SUN_VCDREAD == SUN_XAREAD + struct cdrom_cdxa cdxa; + cdxa.cdxa_addr = vcd_get_msf(vcd); + cdxa.cdxa_length = 1; + cdxa.cdxa_data = vcd->buf; + cdxa.cdxa_format = CDROM_XA_SECTOR_DATA; + + if(ioctl(vcd->fd,CDROMCDXA,&cdxa)==-1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"CDROMCDXA: %s\n",strerror(errno)); + return 0; + } + *offset = 0; +#elif SUN_VCDREAD == SUN_MODE2READ + struct cdrom_read cdread; + cdread.cdread_lba = 4*vcd_get_msf(vcd); + cdread.cdread_bufaddr = vcd->buf; + cdread.cdread_buflen = 2336; + + if(ioctl(vcd->fd,CDROMREADMODE2,&cdread)==-1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"CDROMREADMODE2: %s\n",strerror(errno)); + return 0; + } + *offset = 8; +#elif SUN_VCDREAD == SUN_SCSIREAD + struct uscsi_cmd sc; + union scsi_cdb cdb; + int lba = vcd_get_msf(vcd); + int blocks = 1; + int sector_type; + int sync, header_code, user_data, edc_ecc, error_field; + int sub_channel; + + /* sector_type = 3; *//* mode2 */ + sector_type = 5; /* mode2/form2 */ + sync = 0; + header_code = 0; + user_data = 1; + edc_ecc = 0; + error_field = 0; + sub_channel = 0; + + memset(&cdb, 0, sizeof(cdb)); + memset(&sc, 0, sizeof(sc)); + cdb.scc_cmd = 0xBE; + cdb.cdb_opaque[1] = (sector_type) << 2; + cdb.cdb_opaque[2] = (lba >> 24) & 0xff; + cdb.cdb_opaque[3] = (lba >> 16) & 0xff; + cdb.cdb_opaque[4] = (lba >> 8) & 0xff; + cdb.cdb_opaque[5] = lba & 0xff; + cdb.cdb_opaque[6] = (blocks >> 16) & 0xff; + cdb.cdb_opaque[7] = (blocks >> 8) & 0xff; + cdb.cdb_opaque[8] = blocks & 0xff; + cdb.cdb_opaque[9] = (sync << 7) | + (header_code << 5) | + (user_data << 4) | + (edc_ecc << 3) | + (error_field << 1); + cdb.cdb_opaque[10] = sub_channel; + + sc.uscsi_cdb = (caddr_t)&cdb; + sc.uscsi_cdblen = 12; + sc.uscsi_bufaddr = vcd->buf; + sc.uscsi_buflen = 2336; + sc.uscsi_flags = USCSI_ISOLATE | USCSI_READ; + sc.uscsi_timeout = 20; + if (ioctl(vcd->fd, USCSICMD, &sc)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"USCSICMD: READ CD: %s\n",strerror(errno)); + return -1; + } + if (sc.uscsi_status) { + mp_msg(MSGT_STREAM,MSGL_ERR,"scsi command failed with status %d\n", sc.uscsi_status); + return -1; + } + *offset = 0; + return 1; +#else +#error SUN_VCDREAD +#endif +} +#endif /*sun*/ + +#else /* linux || sun || __bsdi__ */ + +#error vcd is not yet supported on this arch... + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/vcd_read_darwin.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,212 @@ +#include <sys/types.h> +#include <CoreFoundation/CFBase.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/storage/IOCDTypes.h> +#include <IOKit/storage/IOCDMedia.h> +#include <IOKit/storage/IOCDMediaBSDClient.h> + +//=================== VideoCD ========================== +#define CDROM_LEADOUT 0xAA + +typedef struct +{ + uint8_t sync [12]; + uint8_t header [4]; + uint8_t subheader [8]; + uint8_t data [2324]; + uint8_t spare [4]; +} cdsector_t; + +typedef struct mp_vcd_priv_st +{ + int fd; + dk_cd_read_track_info_t entry; + CDMSF msf; + cdsector_t buf; +} mp_vcd_priv_t; + +static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect) +{ + vcd->msf.frame=sect%75; + sect=sect/75; + vcd->msf.second=sect%60; + sect=sect/60; + vcd->msf.minute=sect; +} + +static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd) +{ + return vcd->msf.frame + + (vcd->msf.second+ + vcd->msf.minute*60)*75; + +return 0; +} + +int vcd_seek_to_track(mp_vcd_priv_t* vcd, int track) +{ + dk_cd_read_track_info_t tocentry; + struct CDTrackInfo entry; + + memset( &vcd->entry, 0, sizeof(vcd->entry)); + vcd->entry.addressType = kCDTrackInfoAddressTypeTrackNumber; + vcd->entry.address = track; + vcd->entry.bufferLength = sizeof(entry); + vcd->entry.buffer = &entry; + + if (ioctl(vcd->fd, DKIOCCDREADTRACKINFO, &vcd->entry)) + { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); + +return -1; +} + +int vcd_get_track_end(mp_vcd_priv_t* vcd, int track) +{ + dk_cd_read_disc_info_t tochdr; + struct CDDiscInfo hdr; + + dk_cd_read_track_info_t tocentry; + struct CDTrackInfo entry; + + //read toc header + memset(&tochdr, 0, sizeof(tochdr)); + tochdr.buffer = &hdr; + tochdr.bufferLength = sizeof(hdr); + + if (ioctl(vcd->fd, DKIOCCDREADDISCINFO, &tochdr) < 0) + { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return NULL; + } + + //read track info + memset( &vcd->entry, 0, sizeof(vcd->entry)); + vcd->entry.addressType = kCDTrackInfoAddressTypeTrackNumber; + vcd->entry.address = track<(hdr.lastTrackNumberInLastSessionLSB+1)?(track):CDROM_LEADOUT; + vcd->entry.bufferLength = sizeof(entry); + vcd->entry.buffer = &entry; + + if (ioctl(vcd->fd, DKIOCCDREADTRACKINFO, &vcd->entry)) + { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); + +return -1; +} + +mp_vcd_priv_t* vcd_read_toc(int fd) +{ + dk_cd_read_disc_info_t tochdr; + struct CDDiscInfo hdr; + + dk_cd_read_track_info_t tocentry; + struct CDTrackInfo entry; + CDMSF trackMSF; + + mp_vcd_priv_t* vcd; + int i, min = 0, sec = 0, frame = 0; + + //read toc header + memset(&tochdr, 0, sizeof(tochdr)); + tochdr.buffer = &hdr; + tochdr.bufferLength = sizeof(hdr); + + if (ioctl(fd, DKIOCCDREADDISCINFO, &tochdr) < 0) + { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return NULL; + } + + //print all track info + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", hdr.firstTrackNumberInLastSessionLSB); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", hdr.lastTrackNumberInLastSessionLSB); + for (i=hdr.firstTrackNumberInLastSessionLSB ; i<=hdr.lastTrackNumberInLastSessionLSB + 1; i++) + { + memset( &tocentry, 0, sizeof(tocentry)); + tocentry.addressType = kCDTrackInfoAddressTypeTrackNumber; + tocentry.address = i<=hdr.lastTrackNumberInLastSessionLSB ? i : CDROM_LEADOUT; + tocentry.bufferLength = sizeof(entry); + tocentry.buffer = &entry; + + if (ioctl(fd,DKIOCCDREADTRACKINFO,&tocentry)==-1) + { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); + return NULL; + } + + trackMSF = CDConvertLBAToMSF(entry.trackStartAddress); + + //mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", + if (i<=hdr.lastTrackNumberInLastSessionLSB) + mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: format=%d %02d:%02d:%02d\n", + (int)tocentry.address, + //(int)tocentry.entry.addr_type, + //(int)tocentry.entry.control, + (int)tocentry.addressType, + (int)trackMSF.minute, + (int)trackMSF.second, + (int)trackMSF.frame + ); + + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + if (i > hdr.firstTrackNumberInLastSessionLSB) + { + min = trackMSF.minute - min; + sec = trackMSF.second - sec; + frame = trackMSF.frame - frame; + if ( frame < 0 ) + { + frame += 75; + sec --; + } + if ( sec < 0 ) + { + sec += 60; + min --; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); + } + min = trackMSF.minute; + sec = trackMSF.second; + frame = trackMSF.frame; + } + } + + vcd = malloc(sizeof(mp_vcd_priv_t)); + vcd->fd = fd; + vcd->msf = trackMSF; + return vcd; + + return NULL; +} + +static int vcd_read(mp_vcd_priv_t* vcd,char *mem) +{ + if (pread(vcd->fd,&vcd->buf,VCD_SECTOR_SIZE,vcd_get_msf(vcd)*VCD_SECTOR_SIZE) != VCD_SECTOR_SIZE) + return 0; // EOF? + + vcd->msf.frame++; + if (vcd->msf.frame==75) + { + vcd->msf.frame=0; + vcd->msf.second++; + + if (vcd->msf.second==60) + { + vcd->msf.second=0; + vcd->msf.minute++; + } + } + + memcpy(mem,vcd->buf.data,VCD_SECTOR_DATA); + return VCD_SECTOR_DATA; +return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/vcd_read_fbsd.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,138 @@ +#include <sys/cdio.h> +#include <sys/cdrio.h> + +//=================== VideoCD ========================== +#define CDROM_LEADOUT 0xAA + +typedef struct { + uint8_t sync [12]; + uint8_t header [4]; + uint8_t subheader [8]; + uint8_t data [2324]; + uint8_t spare [4]; +} cdsector_t; + +typedef struct mp_vcd_priv_st { + int fd; + struct ioc_read_toc_single_entry entry; + cdsector_t buf; +} mp_vcd_priv_t; + +static inline void vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect){ + vcd->entry.entry.addr.msf.frame=sect%75; + sect=sect/75; + vcd->entry.entry.addr.msf.second=sect%60; + sect=sect/60; + vcd->entry.entry.addr.msf.minute=sect; +} + +static inline unsigned int vcd_get_msf(mp_vcd_priv_t* vcd){ + return vcd->entry.entry.addr.msf.frame + + (vcd->entry.entry.addr.msf.second+ + vcd->entry.entry.addr.msf.minute*60)*75; +} + +int vcd_seek_to_track(mp_vcd_priv_t* vcd, int track){ + vcd->entry.address_format = CD_MSF_FORMAT; + vcd->entry.track = track; + if (ioctl(vcd->fd, CDIOREADTOCENTRY, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); +} + +int vcd_get_track_end(mp_vcd_priv_t* vcd, int track){ + struct ioc_toc_header tochdr; + if (ioctl(vcd->fd,CDIOREADTOCHEADER,&tochdr)==-1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return -1; + } + vcd->entry.address_format = CD_MSF_FORMAT; + vcd->entry.track = track<tochdr.ending_track?(track+1):CDROM_LEADOUT; + if (ioctl(vcd->fd, CDIOREADTOCENTRY, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA*vcd_get_msf(vcd); +} + +mp_vcd_priv_t* vcd_read_toc(int fd){ + struct ioc_toc_header tochdr; + mp_vcd_priv_t* vcd; + int i, min = 0, sec = 0, frame = 0; + if (ioctl(fd,CDIOREADTOCHEADER,&tochdr)==-1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return NULL; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.starting_track); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.ending_track); + for (i=tochdr.starting_track ; i<=tochdr.ending_track + 1; i++){ + struct ioc_read_toc_single_entry tocentry; + + tocentry.track = i<=tochdr.ending_track ? i : CDROM_LEADOUT; + tocentry.address_format = CD_MSF_FORMAT; + + if (ioctl(fd,CDIOREADTOCENTRY,&tocentry)==-1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); + return NULL; + } + + if (i<=tochdr.ending_track) + mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", + (int)tocentry.track, + (int)tocentry.entry.addr_type, + (int)tocentry.entry.control, + (int)tocentry.address_format, + (int)tocentry.entry.addr.msf.minute, + (int)tocentry.entry.addr.msf.second, + (int)tocentry.entry.addr.msf.frame + ); + + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + if (i > tochdr.starting_track) + { + min = tocentry.entry.addr.msf.minute - min; + sec = tocentry.entry.addr.msf.second - sec; + frame = tocentry.entry.addr.msf.frame - frame; + if ( frame < 0 ) + { + frame += 75; + sec --; + } + if ( sec < 0 ) + { + sec += 60; + min --; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); + } + min = tocentry.entry.addr.msf.minute; + sec = tocentry.entry.addr.msf.second; + frame = tocentry.entry.addr.msf.frame; + } + } + vcd = malloc(sizeof(mp_vcd_priv_t)); + vcd->fd = fd; + return vcd; +} + +static int vcd_read(mp_vcd_priv_t* vcd,char *mem){ + + if (pread(vcd->fd,&vcd->buf,VCD_SECTOR_SIZE,vcd_get_msf(vcd)*VCD_SECTOR_SIZE) + != VCD_SECTOR_SIZE) return 0; // EOF? + + vcd->entry.entry.addr.msf.frame++; + if (vcd->entry.entry.addr.msf.frame==75){ + vcd->entry.entry.addr.msf.frame=0; + vcd->entry.entry.addr.msf.second++; + if (vcd->entry.entry.addr.msf.second==60){ + vcd->entry.entry.addr.msf.second=0; + vcd->entry.entry.addr.msf.minute++; + } + } + memcpy(mem,vcd->buf.data,VCD_SECTOR_DATA); + return VCD_SECTOR_DATA; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stream/vcd_read_nbsd.h Mon Jul 31 17:39:17 2006 +0000 @@ -0,0 +1,199 @@ + +#include <sys/types.h> +#ifdef __NetBSD__ +#include <sys/inttypes.h> +#endif +#include <sys/cdio.h> +#include <sys/scsiio.h> + +#define CDROM_LEADOUT 0xAA + +typedef struct mp_vcd_priv_st { + int fd; + struct ioc_read_toc_entry entry; + struct cd_toc_entry entry_data; +} mp_vcd_priv_t; + +static inline void +vcd_set_msf(mp_vcd_priv_t* vcd, unsigned int sect) +{ + vcd->entry_data.addr.msf.frame = sect % 75; + sect = sect / 75; + vcd->entry_data.addr.msf.second = sect % 60; + sect = sect / 60; + vcd->entry_data.addr.msf.minute = sect; +} + +static inline void +vcd_inc_msf(mp_vcd_priv_t* vcd) +{ + vcd->entry_data.addr.msf.frame++; + if (vcd->entry_data.addr.msf.frame==75){ + vcd->entry_data.addr.msf.frame=0; + vcd->entry_data.addr.msf.second++; + if (vcd->entry_data.addr.msf.second==60){ + vcd->entry_data.addr.msf.second=0; + vcd->entry_data.addr.msf.minute++; + } + } +} + +static inline unsigned int +vcd_get_msf(mp_vcd_priv_t* vcd) +{ + return vcd->entry_data.addr.msf.frame + + (vcd->entry_data.addr.msf.second + + vcd->entry_data.addr.msf.minute * 60) * 75; +} + +int +vcd_seek_to_track(mp_vcd_priv_t* vcd, int track) +{ + vcd->entry.address_format = CD_MSF_FORMAT; + vcd->entry.starting_track = track; + vcd->entry.data_len = sizeof(struct cd_toc_entry); + vcd->entry.data = &vcd->entry_data; + if (ioctl(vcd->fd, CDIOREADTOCENTRIES, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif1: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA * vcd_get_msf(vcd); +} + +int +vcd_get_track_end(mp_vcd_priv_t* vcd, int track) +{ + struct ioc_toc_header tochdr; + if (ioctl(vcd->fd, CDIOREADTOCHEADER, &tochdr) == -1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return -1; + } + vcd->entry.address_format = CD_MSF_FORMAT; + vcd->entry.starting_track = track < tochdr.ending_track ? (track + 1) : CDROM_LEADOUT; + vcd->entry.data_len = sizeof(struct cd_toc_entry); + vcd->entry.data = &vcd->entry_data; + if (ioctl(vcd->fd, CDIOREADTOCENTRYS, &vcd->entry)) { + mp_msg(MSGT_STREAM,MSGL_ERR,"ioctl dif2: %s\n",strerror(errno)); + return -1; + } + return VCD_SECTOR_DATA * vcd_get_msf(vcd); +} + +mp_vcd_priv_t* +vcd_read_toc(int fd) +{ + struct ioc_toc_header tochdr; + mp_vcd_priv_t* vcd; + int i, min = 0, sec = 0, frame = 0; + if (ioctl(fd, CDIOREADTOCHEADER, &tochdr) == -1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc header: %s\n",strerror(errno)); + return; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_START_TRACK=%d\n", tochdr.starting_track); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_END_TRACK=%d\n", tochdr.ending_track); + for (i = tochdr.starting_track; i <= tochdr.ending_track + 1; i++) { + struct ioc_read_toc_entry tocentry; + struct cd_toc_entry tocentry_data; + + tocentry.starting_track = i<=tochdr.ending_track ? i : CDROM_LEADOUT; + tocentry.address_format = CD_MSF_FORMAT; + tocentry.data_len = sizeof(struct cd_toc_entry); + tocentry.data = &tocentry_data; + + if (ioctl(fd, CDIOREADTOCENTRYS, &tocentry) == -1) { + mp_msg(MSGT_OPEN,MSGL_ERR,"read CDROM toc entry: %s\n",strerror(errno)); + return NULL; + } + if (i <= tochdr.ending_track) + mp_msg(MSGT_OPEN,MSGL_INFO,"track %02d: adr=%d ctrl=%d format=%d %02d:%02d:%02d\n", + (int) tocentry.starting_track, + (int) tocentry.data->addr_type, + (int) tocentry.data->control, + (int) tocentry.address_format, + (int) tocentry.data->addr.msf.minute, + (int) tocentry.data->addr.msf.second, + (int) tocentry.data->addr.msf.frame + ); + + if (mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) + { + if (i > tochdr.starting_track) + { + min = tocentry.data->addr.msf.minute - min; + sec = tocentry.data->addr.msf.second - sec; + frame = tocentry.data->addr.msf.frame - frame; + if ( frame < 0 ) + { + frame += 75; + sec --; + } + if ( sec < 0 ) + { + sec += 60; + min --; + } + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VCD_TRACK_%d_MSF=%02d:%02d:%02d\n", i - 1, min, sec, frame); + } + min = tocentry.data->addr.msf.minute; + sec = tocentry.data->addr.msf.second; + frame = tocentry.data->addr.msf.frame; + } + } + vcd = malloc(sizeof(mp_vcd_priv_t)); + vcd->fd = fd; + return vcd; +} + +static int +vcd_read(mp_vcd_priv_t* vcd, char *mem) +{ + struct scsireq sc; + int lba = vcd_get_msf(vcd); + int blocks; + int sector_type; + int sync, header_code, user_data, edc_ecc, error_field; + int sub_channel; + int rc; + + blocks = 1; + sector_type = 5; /* mode2/form2 */ + sync = 0; + header_code = 0; + user_data = 1; + edc_ecc = 0; + error_field = 0; + sub_channel = 0; + + memset(&sc, 0, sizeof(sc)); + sc.cmd[0] = 0xBE; + sc.cmd[1] = (sector_type) << 2; + sc.cmd[2] = (lba >> 24) & 0xff; + sc.cmd[3] = (lba >> 16) & 0xff; + sc.cmd[4] = (lba >> 8) & 0xff; + sc.cmd[5] = lba & 0xff; + sc.cmd[6] = (blocks >> 16) & 0xff; + sc.cmd[7] = (blocks >> 8) & 0xff; + sc.cmd[8] = blocks & 0xff; + sc.cmd[9] = (sync << 7) | (header_code << 5) | (user_data << 4) | + (edc_ecc << 3) | (error_field << 1); + sc.cmd[10] = sub_channel; + sc.cmdlen = 12; + sc.databuf = (caddr_t) mem; + sc.datalen = 2328; + sc.senselen = sizeof(sc.sense); + sc.flags = SCCMD_READ; + sc.timeout = 10000; + rc = ioctl(vcd->fd, SCIOCCOMMAND, &sc); + if (rc == -1) { + mp_msg(MSGT_STREAM,MSGL_ERR,"SCIOCCOMMAND: %s\n",strerror(errno)); + return -1; + } + if (sc.retsts || sc.error) { + mp_msg(MSGT_STREAM,MSGL_ERR,"scsi command failed: status %d error %d\n", + sc.retsts,sc.error); + return -1; + } + vcd_inc_msf(vcd); + return VCD_SECTOR_DATA; +} +