# HG changeset patch # User arpi # Date 1028507947 0 # Node ID 1a747aee653beacfc2896663d421beb3b1e7c666 # Parent db5e0161f021668225787437f1b0571463964da8 applied live.com streaming patch (-sdp and rtsp:// support) by Ross Finlayson see for details. diff -r db5e0161f021 -r 1a747aee653b cfg-mplayer.h --- a/cfg-mplayer.h Mon Aug 05 00:27:26 2002 +0000 +++ b/cfg-mplayer.h Mon Aug 05 00:39:07 2002 +0000 @@ -80,6 +80,10 @@ extern void vo_zr_revertoption(config_t* opt,char* pram); #endif +#ifdef STREAMING_LIVE_DOT_COM +extern int isSDPFile; +#endif + #ifdef HAVE_NEW_GUI extern char * skinName; #endif @@ -276,6 +280,13 @@ {"zr*", vo_zr_parseoption, CONF_TYPE_FUNC_FULL, 0, 0, 0, &vo_zr_revertoption }, #endif +#ifdef STREAMING_LIVE_DOT_COM + // -sdp option, specifying that the source is a SDP file + {"sdp", &isSDPFile, CONF_TYPE_FLAG, 0, 0, 1, NULL}, +#else + {"sdp", "MPlayer was compiled WITHOUT the \"LIVE.COM Streaming Media\" libraries!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, +#endif + //---------------------- mplayer-only options ------------------------ {"osdlevel", &osd_level, CONF_TYPE_INT, CONF_RANGE, 0, 2 , NULL}, diff -r db5e0161f021 -r 1a747aee653b configure --- a/configure Mon Aug 05 00:27:26 2002 +0000 +++ b/configure Mon Aug 05 00:39:07 2002 +0000 @@ -154,6 +154,7 @@ --disable-libdv disable libdv 0.9.5 support [autodetect] --disable-streaming disable network streaming support (support for: http/mms/rtp) [enable] + --disable-live disable LIVE.COM Streaming Media support [disable] --disable-vidix disable VIDIX stuff [enable on x86 *nix] --disable-new-input disable new input system [enable] --enable-joystick enable joystick support in new input [disable] @@ -241,6 +242,7 @@ --with-gtk-config=PATH path to gtk*-config (e.g. /opt/bin/gtk-config) --with-glib-config=PATH path to glib*-config (e.g. /opt/bin/glib-config) --with-dvdnav-config=PATH path to dvdnav-config + --with-livelibdir=DIR path to LIVE.COM Streaming Media libraries EOF exit 0 @@ -929,6 +931,7 @@ _dvdkit=auto _xanim=auto _real=auto +_live=no _xinerama=auto _mga=auto _xmga=auto @@ -1052,6 +1055,8 @@ --disable-xanim) _xanim=no ;; --enable-real) _real=yes ;; --disable-real) _real=no ;; + --enable-live) _live=yes ;; + --disable-live) _live=no ;; --enable-xinerama) _xinerama=yes ;; --disable-xinerama) _xinerama=no ;; --enable-mga) _mga=yes ;; @@ -1149,6 +1154,10 @@ _reallibdir=`echo $ac_option | cut -d '=' -f 2` _real=yes ;; + --with-livelibdir=*) + _livelibdir=`echo $ac_option | cut -d '=' -f 2` + _live=yes + ;; --with-csslibdir=*) _csslibdir=`echo $ac_option | cut -d '=' -f 2` _css=yes @@ -3397,6 +3406,41 @@ fi +if test -z "$_livelibdir" ; then + for I in $_libdir/live /usr/lib/live /usr/local/lib/live; do + if test -d "$I" ; then + _livelibdir="$I" + break; + fi; + done +fi + +echocheck "LIVE.COM Streaming Media libraries" +if test "$_live" = auto ; then + _live=yes + test "$_livelibdir" || _live=no + # TODO: deeper, more reliable test of libs, and version! + # (users may have empty live/ dir or something different there, for + # example 'live config files', or they may have old, incompatibel version) +fi +if test "$_live" = yes ; then + echores "yes (using $_livelibdir)" + _streaming=yes + _def_live='#define STREAMING_LIVE_DOT_COM 1' + _live_libs_def="# LIVE.COM Streaming Media libraries: +LIVE_LIB_DIR = $_livelibdir +LIVE_LIBS = \$(LIVE_LIB_DIR)/liveMedia/libliveMedia.a +LIVE_LIBS += \$(LIVE_LIB_DIR)/groupsock/libgroupsock.a +LIVE_LIBS += \$(LIVE_LIB_DIR)/UsageEnvironment/libUsageEnvironment.a +LIVE_LIBS += \$(LIVE_LIB_DIR)/BasicUsageEnvironment/libBasicUsageEnvironment.a +LIVE_LIBS += -lstdc++" + _ld_live='$(LIVE_LIBS)' +else + echores "no" + _def_live='#undef STREAMING_LIVE_DOT_COM' +fi + + echocheck "iconv" if test "$_iconv" = auto ; then if freebsd ; then @@ -4069,8 +4113,11 @@ WIN32_PATH = -DWIN32_PATH=\\"$_win32libdir\\" STRIPBINARIES = $_stripbinaries +$_live_libs_def + STREAMING = $_streaming -STREAMING_LIB = $_ld_streaming +STREAMING_LIVE_DOT_COM = $_live +STREAMING_LIB = $_ld_streaming $_ld_live VIDIX = $_vidix OPENDIVX = $_opendivx @@ -4376,6 +4423,9 @@ /* Default search path */ $_def_real_path +/* LIVE.COM Streaming Media library support */ +$_def_live + /* Use 3dnow/mmxext/sse/mmx optimized fast memcpy() [maybe buggy... signal 4]*/ $_def_fastmemcpy diff -r db5e0161f021 -r 1a747aee653b libmpdemux/Makefile --- a/libmpdemux/Makefile Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/Makefile Mon Aug 05 00:39:07 2002 +0000 @@ -5,14 +5,26 @@ SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c opt-reg.c mpdemux.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c ifeq ($(STREAMING),yes) -SRCS += asf_streaming.c url.c http.c network.c rtp.c asf_mmst_streaming.c +SRCS += asf_streaming.c url.c http.c network.c asf_mmst_streaming.c +ifeq ($(STREAMING_LIVE_DOT_COM),yes) +CPLUSPLUSSRCS = demux_rtp.cpp +CPLUSPLUSINCLUDE = -I$(LIVE_LIB_DIR)/liveMedia/include +CPLUSPLUSINCLUDE += -I$(LIVE_LIB_DIR)/UsageEnvironment/include +CPLUSPLUSINCLUDE += -I$(LIVE_LIB_DIR)/BasicUsageEnvironment/include +CPLUSPLUSINCLUDE += -I$(LIVE_LIB_DIR)/groupsock/include +else +SRCS += rtp.c +endif endif OBJS = $(SRCS:.c=.o) +OBJS += $(CPLUSPLUSSRCS:.cpp=.o) INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC) CFLAGS = $(OPTFLAGS) $(INCLUDE) +CPLUSPLUSFLAGS = $(CFLAGS) $(CPLUSPLUSINCLUDE) +CPLUSPLUS = c++ -.SUFFIXES: .c .o +.SUFFIXES: .c .cpp .o # .PHONY: all clean @@ -20,6 +32,8 @@ .c.o: $(CC) -c $(CFLAGS) -o $@ $< +.cpp.o: + $(CPLUSPLUS) -c $(CPLUSPLUSFLAGS) -o $@ $< $(LIBNAME): $(OBJS) $(AR) r $(LIBNAME) $(OBJS) diff -r db5e0161f021 -r 1a747aee653b libmpdemux/demux_rtp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/demux_rtp.cpp Mon Aug 05 00:39:07 2002 +0000 @@ -0,0 +1,431 @@ +extern "C" { +#include "demux_rtp.h" +#include "stheader.h" +} + +#include "BasicUsageEnvironment.hh" +#include "liveMedia.hh" +#include + +////////// Routines (with C-linkage) that interface between "mplayer" +////////// and the "LIVE.COM Streaming Media" libraries: + +extern "C" stream_t* stream_open_sdp(int fd, off_t fileSize, + int* file_format) { + *file_format = DEMUXER_TYPE_RTP; + stream_t* newStream = NULL; + do { + char* sdpDescription = (char*)malloc(fileSize+1); + if (sdpDescription == NULL) break; + + ssize_t numBytesRead = read(fd, sdpDescription, fileSize); + if (numBytesRead != fileSize) break; + sdpDescription[fileSize] = '\0'; // to be safe + + newStream = (stream_t*)calloc(sizeof (stream_t), 1); + if (newStream == NULL) break; + + // Store the SDP description in the 'priv' field, for later use: + newStream->priv = sdpDescription; + } while (0); + return newStream; +} + +extern "C" 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 +} + +extern "C" int rtsp_streaming_start(stream_t* stream) { + stream->streaming_ctrl->streaming_seek = _rtsp_streaming_seek; + + return 0; +} + +// A data structure representing a buffer being read: +class ReadBufferQueue; // forward +class ReadBuffer { +public: + ReadBuffer(ReadBufferQueue* ourQueue, demux_packet_t* dp); + virtual ~ReadBuffer(); + Boolean enqueue(); + + demux_packet_t* dp() const { return fDP; } + ReadBufferQueue* ourQueue() { return fOurQueue; } + + ReadBuffer* next; +private: + demux_packet_t* fDP; + ReadBufferQueue* fOurQueue; +}; + +class ReadBufferQueue { +public: + ReadBufferQueue(MediaSubsession* subsession, demuxer_t* demuxer, + char const* tag); + virtual ~ReadBufferQueue(); + + ReadBuffer* dequeue(); + + FramedSource* readSource() const { return fReadSource; } + demuxer_t* ourDemuxer() const { return fOurDemuxer; } + char const* tag() const { return fTag; } + + ReadBuffer* head; + ReadBuffer* tail; + char blockingFlag; // used to implement synchronous reads + unsigned counter; // used for debugging +private: + FramedSource* fReadSource; + demuxer_t* fOurDemuxer; + char const* fTag; // used for debugging +}; + +// A structure of RTP-specific state, kept so that we can cleanly +// reclaim it: +typedef struct RTPState { + char const* sdpDescription; + RTSPClient* rtspClient; + MediaSession* mediaSession; + ReadBufferQueue* audioBufferQueue; + ReadBufferQueue* videoBufferQueue; + int isMPEG; // TRUE for MPEG audio, video, or transport streams +}; + +extern "C" void demux_open_rtp(demuxer_t* demuxer) { + do { + TaskScheduler* scheduler = BasicTaskScheduler::createNew(); + if (scheduler == NULL) break; + UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler); + if (env == NULL) break; + + RTSPClient* rtspClient = NULL; + int isMPEG = 0; + + // Look at the stream's 'priv' field to see if we were initiated + // via a SDP description: + char* sdpDescription = (char*)(demuxer->stream->priv); + if (sdpDescription == NULL) { + // We weren't given a SDP description directly, so assume that + // we were give a RTSP URL + char const* url = demuxer->stream->streaming_ctrl->url->url; + + extern int verbose; + rtspClient = RTSPClient::createNew(*env, verbose); + if (rtspClient == NULL) { + fprintf(stderr, "Failed to create RTSP client: %s\n", + env->getResultMsg()); + break; + } + + sdpDescription = rtspClient->describeURL(url); + if (sdpDescription == NULL) { + fprintf(stderr, "Failed to get a SDP description from URL \"%s\": %s\n", + url, env->getResultMsg()); + break; + } + } + + // Now that we have a SDP description, create a MediaSession from it: + MediaSession* mediaSession = MediaSession::createNew(*env, sdpDescription); + if (mediaSession == NULL) break; + + // Create RTP receivers (sources) for each subsession: + MediaSubsessionIterator iter(*mediaSession); + MediaSubsession* subsession; + MediaSubsession* audioSubsession = NULL; + MediaSubsession* videoSubsession = NULL; + while ((subsession = iter.next()) != NULL) { + // Ignore any subsession that's not audio or video: + if (strcmp(subsession->mediumName(), "audio") == 0) { + audioSubsession = subsession; + } else if (strcmp(subsession->mediumName(), "video") == 0) { + videoSubsession = subsession; + } else { + continue; + } + + if (!subsession->initiate()) { + fprintf(stderr, "Failed to initiate \"%s/%s\" RTP subsession: %s\n", subsession->mediumName(), subsession->codecName(), env->getResultMsg()); + } else { + fprintf(stderr, "Initiated \"%s/%s\" RTP subsession\n", subsession->mediumName(), subsession->codecName()); + + if (rtspClient != NULL) { + // Issue RTSP "SETUP" and "PLAY" commands on the chosen subsession: + if (!rtspClient->setupMediaSubsession(*subsession)) break; + if (!rtspClient->playMediaSubsession(*subsession)) break; + } + + // Now that the subsession is ready to be read, do additional + // mplayer-specific initialization on it: + if (subsession == videoSubsession) { + // Create a dummy video stream header + // to make the main mplayer code happy: + sh_video_t* sh_video = new_sh_video(demuxer,0); + demux_stream_t* d_video = demuxer->video; + d_video->sh = sh_video; sh_video->ds = d_video; + + // Map known video MIME types to the format code that this prog uses: + if (strcmp(subsession->codecName(), "MPV") == 0 || + strcmp(subsession->codecName(), "MP1S") == 0 || + strcmp(subsession->codecName(), "MP2T") == 0) { + isMPEG = 1; + } else if (strcmp(subsession->codecName(), "H263") == 0 || + strcmp(subsession->codecName(), "H263-1998") == 0) { + sh_video->format = mmioFOURCC('H','2','6','3'); + } else if (strcmp(subsession->codecName(), "H261") == 0) { + sh_video->format = mmioFOURCC('H','2','6','1'); + } else if (strcmp(subsession->codecName(), "JPEG") == 0) { + sh_video->format = mmioFOURCC('M','J','P','G'); + } else { + fprintf(stderr, + "Unknown mplayer format code for MIME type \"video/%s\"\n", + subsession->codecName()); + } + } else if (subsession == audioSubsession) { + // Create a dummy audio stream header + // to make the main mplayer code happy: + sh_audio_t* sh_audio = new_sh_audio(demuxer,0); + sh_audio->wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)); + demux_stream_t* d_audio = demuxer->audio; + d_audio->sh = sh_audio; sh_audio->ds = d_audio; + + // Map known audio MIME types to the format code that this prog uses: + if (strcmp(subsession->codecName(), "MPA") == 0 || + strcmp(subsession->codecName(), "MPA-ROBUST") == 0 || + strcmp(subsession->codecName(), "X-MP3-DRAFT-00") == 0) { + sh_audio->format = 0x50; + } else if (strcmp(subsession->codecName(), "AC3") == 0) { + sh_audio->format = 0x2000; + } else if (strcmp(subsession->codecName(), "PCMU") == 0) { + sh_audio->format = 0x7; + } else if (strcmp(subsession->codecName(), "PCMA") == 0) { + sh_audio->format = 0x6; + } else if (strcmp(subsession->codecName(), "GSM") == 0) { + sh_audio->format = 0x31; + } else { + fprintf(stderr, + "Unknown mplayer format code for MIME type \"audio/%s\"\n", + subsession->codecName()); + } + } + } + } + + // Hack: Create a 'RTPState' structure containing the state that + // we just created, and store it in the demuxer's 'priv' field: + RTPState* rtpState = new RTPState; + rtpState->sdpDescription = sdpDescription; + rtpState->rtspClient = rtspClient; + rtpState->mediaSession = mediaSession; + rtpState->audioBufferQueue + = new ReadBufferQueue(audioSubsession, demuxer, "audio"); + rtpState->videoBufferQueue + = new ReadBufferQueue(videoSubsession, demuxer, "video"); + rtpState->isMPEG = isMPEG; + + demuxer->priv = rtpState; + } while (0); +} + +extern "C" int demux_is_mpeg_rtp_stream(demuxer_t* demuxer) { + // Get the RTP state that was stored in the demuxer's 'priv' field: + RTPState* rtpState = (RTPState*)(demuxer->priv); + return rtpState->isMPEG; +} + +static Boolean deliverBufferIfAvailable(ReadBufferQueue* bufferQueue, + demux_stream_t* ds); // forward + +extern "C" int demux_rtp_fill_buffer(demuxer_t* demuxer, demux_stream_t* ds) { + // Get a filled-in "demux_packet" from the RTP source, and deliver it. + // Note that this is called as a synchronous read operation, so it needs + // to block in the (hopefully infrequent) case where no packet is + // immediately available. + + // Begin by finding the buffer queue that we want to read from: + // (Get this from the RTP state, which we stored in + // the demuxer's 'priv' field) + RTPState* rtpState = (RTPState*)(demuxer->priv); + ReadBufferQueue* bufferQueue = NULL; + if (ds == demuxer->video) { + bufferQueue = rtpState->videoBufferQueue; + } else if (ds == demuxer->audio) { + bufferQueue = rtpState->audioBufferQueue; + } else { + fprintf(stderr, "demux_rtp_fill_buffer: internal error: unknown stream\n"); + return 0; + } + + if (bufferQueue == NULL || bufferQueue->readSource() == NULL) { + fprintf(stderr, "demux_rtp_fill_buffer failed: no appropriate RTP subsession has been set up\n"); + return 0; + } + + // Check whether there's a full buffer to deliver to the client: + bufferQueue->blockingFlag = 0; + while (!deliverBufferIfAvailable(bufferQueue, ds)) { + // Because we weren't able to deliver a buffer to the client immediately, + // block myself until one comes available: + TaskScheduler& scheduler + = bufferQueue->readSource()->envir().taskScheduler(); + scheduler.blockMyself(&bufferQueue->blockingFlag); + } + + if (demuxer->stream->eof) return 0; // source stream has closed down + return 1; +} + +extern "C" void demux_close_rtp(demuxer_t* demuxer) { + // Reclaim all RTP-related state: + + // Get the RTP state that was stored in the demuxer's 'priv' field: + RTPState* rtpState = (RTPState*)(demuxer->priv); + UsageEnvironment* env = NULL; + TaskScheduler* scheduler = NULL; + if (rtpState->mediaSession != NULL) { + env = &(rtpState->mediaSession->envir()); + scheduler = &(env->taskScheduler()); + } + Medium::close(rtpState->mediaSession); + Medium::close(rtpState->rtspClient); + delete rtpState->audioBufferQueue; + delete rtpState->videoBufferQueue; + delete rtpState->sdpDescription; + delete rtpState; + + delete env; delete scheduler; +} + +////////// Extra routines that help implement the above interface functions: + +static void scheduleNewBufferRead(ReadBufferQueue* bufferQueue); // forward + +static Boolean deliverBufferIfAvailable(ReadBufferQueue* bufferQueue, + demux_stream_t* ds) { + Boolean deliveredBuffer = False; + ReadBuffer* readBuffer = bufferQueue->dequeue(); + if (readBuffer != NULL) { + // Append the packet to the reader's DS stream: + ds_add_packet(ds, readBuffer->dp()); + deliveredBuffer = True; + } + + // Arrange to read a new packet into this queue: + scheduleNewBufferRead(bufferQueue); + + return deliveredBuffer; +} + +static void afterReading(void* clientData, unsigned frameSize, + struct timeval presentationTime); // forward +static void onSourceClosure(void* clientData); // forward + +static void scheduleNewBufferRead(ReadBufferQueue* bufferQueue) { + if (bufferQueue->readSource()->isCurrentlyAwaitingData()) return; + // a read from this source is already in progress + + // Allocate a new packet buffer, and arrange to read into it: + unsigned const bufferSize = 30000; // >= the largest conceivable RTP packet + demux_packet_t* dp = new_demux_packet(bufferSize); + if (dp == NULL) return; + ReadBuffer* readBuffer = new ReadBuffer(bufferQueue, dp); + + // Schedule the read operation: + bufferQueue->readSource()->getNextFrame(dp->buffer, bufferSize, + afterReading, readBuffer, + onSourceClosure, readBuffer); +} + +static void afterReading(void* clientData, unsigned frameSize, + struct timeval /*presentationTime*/) { + ReadBuffer* readBuffer = (ReadBuffer*)clientData; + ReadBufferQueue* bufferQueue = readBuffer->ourQueue(); + demuxer_t* demuxer = bufferQueue->ourDemuxer(); + + if (frameSize > 0) demuxer->stream->eof = 0; + + demux_packet_t* dp = readBuffer->dp(); + dp->len = frameSize; + dp->pts = 0; + dp->pos = demuxer->filepos; + demuxer->filepos += frameSize; + if (!readBuffer->enqueue()) { + // The queue is full, so discard the buffer: + delete readBuffer; + } + + // Signal any pending 'blockMyself()' call on this queue: + bufferQueue->blockingFlag = ~0; + + // Finally, arrange to do another read, if appropriate + scheduleNewBufferRead(bufferQueue); +} + +static void onSourceClosure(void* clientData) { + ReadBuffer* readBuffer = (ReadBuffer*)clientData; + ReadBufferQueue* bufferQueue = readBuffer->ourQueue(); + demuxer_t* demuxer = bufferQueue->ourDemuxer(); + + demuxer->stream->eof = 1; + + // Signal any pending 'blockMyself()' call on this queue: + bufferQueue->blockingFlag = ~0; +} + +////////// "ReadBuffer" and "ReadBufferQueue" implementation: + +#define MAX_QUEUE_SIZE 5 + +ReadBuffer::ReadBuffer(ReadBufferQueue* ourQueue, demux_packet_t* dp) + : next(NULL), fDP(dp), fOurQueue(ourQueue) { +} + +Boolean ReadBuffer::enqueue() { + if (fOurQueue->counter >= MAX_QUEUE_SIZE) { + // This queue is full. Clear out an old entry from it, so that + // this new one will fit: + while (fOurQueue->counter >= MAX_QUEUE_SIZE) { + delete fOurQueue->dequeue(); + } + } + + // Add ourselves to the tail of our queue: + if (fOurQueue->tail == NULL) { + fOurQueue->head = this; + } else { + fOurQueue->tail->next = this; + } + fOurQueue->tail = this; + ++fOurQueue->counter; + + return True; +} + +ReadBuffer::~ReadBuffer() { + free_demux_packet(fDP); + delete next; +} + +ReadBufferQueue::ReadBufferQueue(MediaSubsession* subsession, + demuxer_t* demuxer, char const* tag) + : head(NULL), tail(NULL), counter(0), + fReadSource(subsession == NULL ? NULL : subsession->readSource()), + fOurDemuxer(demuxer), fTag(strdup(tag)) { +} + +ReadBufferQueue::~ReadBufferQueue() { + delete head; + delete fTag; +} + +ReadBuffer* ReadBufferQueue::dequeue() { + ReadBuffer* readBuffer = head; + if (readBuffer != NULL) { + head = readBuffer->next; + if (head == NULL) tail = NULL; + --counter; + readBuffer->next = NULL; + } + return readBuffer; +} diff -r db5e0161f021 -r 1a747aee653b libmpdemux/demux_rtp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpdemux/demux_rtp.h Mon Aug 05 00:39:07 2002 +0000 @@ -0,0 +1,33 @@ +#ifndef _DEMUX_RTP_H +#define _DEMUX_RTP_H + +#include +#include + +#ifndef __STREAM_H +#include "stream.h" +#endif +#ifndef __DEMUXER_H +#include "demuxer.h" +#endif + +// Open a SDP file: +stream_t* stream_open_sdp(int fd, off_t fileSize, int* file_format); + +// Open a RTSP URL: +int rtsp_streaming_start(stream_t* stream); + +// Open a RTP demuxer (which was initiated either from a SDP file, +// or from a RTSP URL): +void demux_open_rtp(demuxer_t* demuxer); + +// Test whether a RTP demuxer is for a MPEG stream: +int demux_is_mpeg_rtp_stream(demuxer_t* demuxer); + +// Read from a RTP demuxer: +int demux_rtp_fill_buffer(demuxer_t *demux, demux_stream_t* ds); + +// Close a RTP demuxer +void demux_close_rtp(demuxer_t* demuxer); + +#endif diff -r db5e0161f021 -r 1a747aee653b libmpdemux/demuxer.c --- a/libmpdemux/demuxer.c Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/demuxer.c Mon Aug 05 00:39:07 2002 +0000 @@ -150,6 +150,7 @@ extern void demux_close_nuv(demuxer_t* demuxer); extern void demux_close_audio(demuxer_t* demuxer); extern void demux_close_ogg(demuxer_t* demuxer); +extern void demux_close_rtp(demuxer_t* demuxer); extern void demux_close_demuxers(demuxer_t* demuxer); extern void demux_close_avi(demuxer_t *demuxer); @@ -179,6 +180,10 @@ demux_close_audio(demuxer); break; case DEMUXER_TYPE_OGG: demux_close_ogg(demuxer); break; +#ifdef STREAMING_LIVE_DOT_COM + case DEMUXER_TYPE_RTP: + demux_close_rtp(demuxer); break; +#endif case DEMUXER_TYPE_DEMUXERS: demux_close_demuxers(demuxer); return; case DEMUXER_TYPE_AVI: @@ -255,6 +260,7 @@ int demux_vivo_fill_buffer(demuxer_t *demux); int demux_real_fill_buffer(demuxer_t *demuxer); int demux_nuv_fill_buffer(demuxer_t *demux); +int demux_rtp_fill_buffer(demuxer_t *demux, demux_stream_t* ds); #ifdef USE_TV #include "tv.h" extern tvi_handle_t *tv_handler; @@ -296,6 +302,9 @@ case DEMUXER_TYPE_DEMUXERS: return demux_demuxers_fill_buffer(demux,ds); case DEMUXER_TYPE_OGG: return demux_ogg_fill_buffer(demux); case DEMUXER_TYPE_RAWAUDIO: return demux_rawaudio_fill_buffer(demux,ds); +#ifdef STREAMING_LIVE_DOT_COM + case DEMUXER_TYPE_RTP: return demux_rtp_fill_buffer(demux, ds); +#endif } return 0; } @@ -793,6 +802,11 @@ demuxer = NULL; } } +//=============== Try to open as a RTP stream): =========== + if(file_format==DEMUXER_TYPE_RTP) { + demuxer=new_demuxer(stream,DEMUXER_TYPE_RTP,audio_id,video_id,dvdsub_id); + } + //=============== Unknown, exiting... =========================== if(file_format==DEMUXER_TYPE_UNKNOWN || demuxer == NULL){ mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_FormatNotRecognized); @@ -949,6 +963,12 @@ break; } #endif +#ifdef STREAMING_LIVE_DOT_COM + case DEMUXER_TYPE_RTP: { + demux_open_rtp(demuxer); + break; + } +#endif } // switch(file_format) pts_from_bps=0; // !!! return demuxer; diff -r db5e0161f021 -r 1a747aee653b libmpdemux/demuxer.h --- a/libmpdemux/demuxer.h Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/demuxer.h Mon Aug 05 00:39:07 2002 +0000 @@ -29,10 +29,11 @@ #define DEMUXER_TYPE_OGG 18 #define DEMUXER_TYPE_BMP 19 #define DEMUXER_TYPE_RAWAUDIO 20 +#define DEMUXER_TYPE_RTP 21 // This should always match the higest demuxer type number. // Unless you want to disallow users to force the demuxer to some types #define DEMUXER_TYPE_MIN 0 -#define DEMUXER_TYPE_MAX 20 +#define DEMUXER_TYPE_MAX 21 #define DEMUXER_TYPE_DEMUXERS (1<<16) // A virtual demuxer type for the network code @@ -123,9 +124,9 @@ } demuxer_t; inline static demux_packet_t* new_demux_packet(int len){ - demux_packet_t* dp=malloc(sizeof(demux_packet_t)); + demux_packet_t* dp=(demux_packet_t*)malloc(sizeof(demux_packet_t)); dp->len=len; - dp->buffer=len?malloc(len+8):NULL; + dp->buffer=len?(unsigned char*)malloc(len+8):NULL; dp->next=NULL; dp->pts=0; dp->pos=0; @@ -136,7 +137,7 @@ } inline static demux_packet_t* clone_demux_packet(demux_packet_t* pack){ - demux_packet_t* dp=malloc(sizeof(demux_packet_t)); + demux_packet_t* dp=(demux_packet_t*)malloc(sizeof(demux_packet_t)); while(pack->master) pack=pack->master; // find the master memcpy(dp,pack,sizeof(demux_packet_t)); dp->next=NULL; diff -r db5e0161f021 -r 1a747aee653b libmpdemux/network.c --- a/libmpdemux/network.c Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/network.c Mon Aug 05 00:39:07 2002 +0000 @@ -25,7 +25,9 @@ #include "http.h" #include "url.h" #include "asf.h" +#ifndef STREAMING_LIVE_DOT_COM #include "rtp.h" +#endif #include "../version.h" @@ -113,6 +115,7 @@ free( streaming_ctrl ); } +#ifndef STREAMING_LIVE_DOT_COM int read_rtp_from_server(int fd, char *buffer, int length) { struct rtpheader rh; @@ -132,6 +135,7 @@ memcpy(buffer, data, len); return(len); } +#endif // Connect to a server using a TCP connection int @@ -454,10 +458,18 @@ // Checking for RTSP if( !strcasecmp(url->protocol, "rtsp") ) { - mp_msg(MSGT_NETWORK,MSGL_ERR,"RTSP protocol not yet implemented!\n"); +#ifdef STREAMING_LIVE_DOT_COM + *file_format = DEMUXER_TYPE_RTP; + return 0; +#else + mp_msg(MSGT_NETWORK,MSGL_ERR,"RTSP protocol support requires the \"LIVE.COM Streaming Media\" libraries!\n"); return -1; +#endif } +#ifndef STREAMING_LIVE_DOT_COM + // Old, hacked RTP support, which works for MPEG Program Streams + // RTP streams only: // Checking for RTP if( !strcasecmp(url->protocol, "rtp") ) { if( url->port==0 ) { @@ -466,6 +478,7 @@ } return 0; } +#endif // Checking for ASF if( !strncasecmp(url->protocol, "mms", 3) ) { @@ -688,6 +701,7 @@ return 0; } +#ifndef STREAMING_LIVE_DOT_COM // Start listening on a UDP port. If multicast, join the group. int rtp_open_socket( URL_t *url ) { @@ -789,6 +803,7 @@ streaming_ctrl->status = streaming_playing_e; return 0; } +#endif int streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) { @@ -820,6 +835,7 @@ } } +#ifndef STREAMING_LIVE_DOT_COM // For RTP streams, we usually don't know the stream type until we open it. if( !strcasecmp( stream->streaming_ctrl->url->protocol, "rtp")) { if(stream->fd >= 0) { @@ -829,6 +845,7 @@ stream->fd = -1; ret = rtp_streaming_start( stream ); } else +#endif // For connection-oriented streams, we can usually determine the streaming type. switch( *demuxer_type ) { case DEMUXER_TYPE_ASF: @@ -840,6 +857,15 @@ mp_msg(MSGT_NETWORK,MSGL_ERR,"asf_streaming_start failed\n"); } break; +#ifdef STREAMING_LIVE_DOT_COM + case DEMUXER_TYPE_RTP: + // RTSP/RTP streaming is handled separately: + ret = rtsp_streaming_start( stream ); + if( ret<0 ) { + mp_msg(MSGT_NETWORK,MSGL_ERR,"rtsp_rtp_streaming_start failed\n"); + } + break; +#endif case DEMUXER_TYPE_MPEG_ES: case DEMUXER_TYPE_MPEG_PS: case DEMUXER_TYPE_AVI: diff -r db5e0161f021 -r 1a747aee653b libmpdemux/open.c --- a/libmpdemux/open.c Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/open.c Mon Aug 05 00:39:07 2002 +0000 @@ -22,6 +22,10 @@ #ifdef STREAMING #include "url.h" #include "network.h" +#ifdef STREAMING_LIVE_DOT_COM +#include "demux_rtp.h" +int isSDPFile = 0; +#endif static URL_t* url; #endif @@ -471,6 +475,14 @@ #else mp_msg(MSGT_OPEN,MSGL_V,"File size is %u bytes\n", (unsigned int)len); #endif + +#ifdef STREAMING_LIVE_DOT_COM + // Check for a special case: a SDP file: + if (isSDPFile) { + return stream_open_sdp(f, len, file_format); + } +#endif + stream=new_stream(f,STREAMTYPE_FILE); stream->end_pos=len; return stream; diff -r db5e0161f021 -r 1a747aee653b libmpdemux/video.c --- a/libmpdemux/video.c Mon Aug 05 00:27:26 2002 +0000 +++ b/libmpdemux/video.c Mon Aug 05 00:39:07 2002 +0000 @@ -79,6 +79,13 @@ #endif break; } +#ifdef STREAMING_LIVE_DOT_COM + case DEMUXER_TYPE_RTP: + // If the RTP stream is a MPEG stream, then we use this code to check + // for MPEG headers: + if (!demux_is_mpeg_rtp_stream(d_video->demuxer)) break; + // otherwise fall through to... +#endif case DEMUXER_TYPE_MPEG_ES: case DEMUXER_TYPE_MPEG_PS: { //mpeg_header_parser: @@ -211,7 +218,11 @@ *start=NULL; - if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS){ + if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS +#ifdef STREAMING_LIVE_DOT_COM + || (demuxer->file_format==DEMUXER_TYPE_RTP && demux_is_mpeg_rtp_stream(demuxer)) +#endif + ){ int in_frame=0; //float newfps; //videobuf_len=0;