0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00

applied live.com streaming patch (-sdp and rtsp:// support) by Ross Finlayson <finlayson@live.com>

see <http://www.live.com/mplayer/> for details.


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@6911 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
arpi 2002-08-05 00:39:07 +00:00
parent 11bc29e6cc
commit fa788640e2
10 changed files with 618 additions and 9 deletions

View File

@ -80,6 +80,10 @@ extern int vo_zr_parseoption(struct config * conf, char *opt, char * param);
extern void vo_zr_revertoption(config_t* opt,char* pram); extern void vo_zr_revertoption(config_t* opt,char* pram);
#endif #endif
#ifdef STREAMING_LIVE_DOT_COM
extern int isSDPFile;
#endif
#ifdef HAVE_NEW_GUI #ifdef HAVE_NEW_GUI
extern char * skinName; extern char * skinName;
#endif #endif
@ -276,6 +280,13 @@ static config_t mplayer_opts[]={
{"zr*", vo_zr_parseoption, CONF_TYPE_FUNC_FULL, 0, 0, 0, &vo_zr_revertoption }, {"zr*", vo_zr_parseoption, CONF_TYPE_FUNC_FULL, 0, 0, 0, &vo_zr_revertoption },
#endif #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 ------------------------ //---------------------- mplayer-only options ------------------------
{"osdlevel", &osd_level, CONF_TYPE_INT, CONF_RANGE, 0, 2 , NULL}, {"osdlevel", &osd_level, CONF_TYPE_INT, CONF_RANGE, 0, 2 , NULL},

52
configure vendored
View File

@ -154,6 +154,7 @@ Optional features:
--disable-libdv disable libdv 0.9.5 support [autodetect] --disable-libdv disable libdv 0.9.5 support [autodetect]
--disable-streaming disable network streaming support --disable-streaming disable network streaming support
(support for: http/mms/rtp) [enable] (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-vidix disable VIDIX stuff [enable on x86 *nix]
--disable-new-input disable new input system [enable] --disable-new-input disable new input system [enable]
--enable-joystick enable joystick support in new input [disable] --enable-joystick enable joystick support in new input [disable]
@ -241,6 +242,7 @@ Use these options if autodetection fails:
--with-gtk-config=PATH path to gtk*-config (e.g. /opt/bin/gtk-config) --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-glib-config=PATH path to glib*-config (e.g. /opt/bin/glib-config)
--with-dvdnav-config=PATH path to dvdnav-config --with-dvdnav-config=PATH path to dvdnav-config
--with-livelibdir=DIR path to LIVE.COM Streaming Media libraries
EOF EOF
exit 0 exit 0
@ -929,6 +931,7 @@ _dvdread=auto
_dvdkit=auto _dvdkit=auto
_xanim=auto _xanim=auto
_real=auto _real=auto
_live=no
_xinerama=auto _xinerama=auto
_mga=auto _mga=auto
_xmga=auto _xmga=auto
@ -1052,6 +1055,8 @@ for ac_option do
--disable-xanim) _xanim=no ;; --disable-xanim) _xanim=no ;;
--enable-real) _real=yes ;; --enable-real) _real=yes ;;
--disable-real) _real=no ;; --disable-real) _real=no ;;
--enable-live) _live=yes ;;
--disable-live) _live=no ;;
--enable-xinerama) _xinerama=yes ;; --enable-xinerama) _xinerama=yes ;;
--disable-xinerama) _xinerama=no ;; --disable-xinerama) _xinerama=no ;;
--enable-mga) _mga=yes ;; --enable-mga) _mga=yes ;;
@ -1149,6 +1154,10 @@ for ac_option do
_reallibdir=`echo $ac_option | cut -d '=' -f 2` _reallibdir=`echo $ac_option | cut -d '=' -f 2`
_real=yes _real=yes
;; ;;
--with-livelibdir=*)
_livelibdir=`echo $ac_option | cut -d '=' -f 2`
_live=yes
;;
--with-csslibdir=*) --with-csslibdir=*)
_csslibdir=`echo $ac_option | cut -d '=' -f 2` _csslibdir=`echo $ac_option | cut -d '=' -f 2`
_css=yes _css=yes
@ -3397,6 +3406,41 @@ else
fi 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" echocheck "iconv"
if test "$_iconv" = auto ; then if test "$_iconv" = auto ; then
if freebsd ; then if freebsd ; then
@ -4069,8 +4113,11 @@ EXTRA_INC = $_inc_extra $_inc_gtk
WIN32_PATH = -DWIN32_PATH=\\"$_win32libdir\\" WIN32_PATH = -DWIN32_PATH=\\"$_win32libdir\\"
STRIPBINARIES = $_stripbinaries STRIPBINARIES = $_stripbinaries
$_live_libs_def
STREAMING = $_streaming STREAMING = $_streaming
STREAMING_LIB = $_ld_streaming STREAMING_LIVE_DOT_COM = $_live
STREAMING_LIB = $_ld_streaming $_ld_live
VIDIX = $_vidix VIDIX = $_vidix
OPENDIVX = $_opendivx OPENDIVX = $_opendivx
@ -4376,6 +4423,9 @@ $_def_real
/* Default search path */ /* Default search path */
$_def_real_path $_def_real_path
/* LIVE.COM Streaming Media library support */
$_def_live
/* Use 3dnow/mmxext/sse/mmx optimized fast memcpy() [maybe buggy... signal 4]*/ /* Use 3dnow/mmxext/sse/mmx optimized fast memcpy() [maybe buggy... signal 4]*/
$_def_fastmemcpy $_def_fastmemcpy

View File

@ -5,14 +5,26 @@ include ../config.mak
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 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) 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 endif
OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o)
OBJS += $(CPLUSPLUSSRCS:.cpp=.o)
INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC) INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC)
CFLAGS = $(OPTFLAGS) $(INCLUDE) CFLAGS = $(OPTFLAGS) $(INCLUDE)
CPLUSPLUSFLAGS = $(CFLAGS) $(CPLUSPLUSINCLUDE)
CPLUSPLUS = c++
.SUFFIXES: .c .o .SUFFIXES: .c .cpp .o
# .PHONY: all clean # .PHONY: all clean
@ -20,6 +32,8 @@ all: $(LIBNAME)
.c.o: .c.o:
$(CC) -c $(CFLAGS) -o $@ $< $(CC) -c $(CFLAGS) -o $@ $<
.cpp.o:
$(CPLUSPLUS) -c $(CPLUSPLUSFLAGS) -o $@ $<
$(LIBNAME): $(OBJS) $(LIBNAME): $(OBJS)
$(AR) r $(LIBNAME) $(OBJS) $(AR) r $(LIBNAME) $(OBJS)

431
libmpdemux/demux_rtp.cpp Normal file
View File

@ -0,0 +1,431 @@
extern "C" {
#include "demux_rtp.h"
#include "stheader.h"
}
#include "BasicUsageEnvironment.hh"
#include "liveMedia.hh"
#include <unistd.h>
////////// 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;
}

33
libmpdemux/demux_rtp.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef _DEMUX_RTP_H
#define _DEMUX_RTP_H
#include <stdlib.h>
#include <stdio.h>
#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

View File

@ -150,6 +150,7 @@ extern void demux_close_fli(demuxer_t* demuxer);
extern void demux_close_nuv(demuxer_t* demuxer); extern void demux_close_nuv(demuxer_t* demuxer);
extern void demux_close_audio(demuxer_t* demuxer); extern void demux_close_audio(demuxer_t* demuxer);
extern void demux_close_ogg(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_demuxers(demuxer_t* demuxer);
extern void demux_close_avi(demuxer_t *demuxer); extern void demux_close_avi(demuxer_t *demuxer);
@ -179,6 +180,10 @@ void free_demuxer(demuxer_t *demuxer){
demux_close_audio(demuxer); break; demux_close_audio(demuxer); break;
case DEMUXER_TYPE_OGG: case DEMUXER_TYPE_OGG:
demux_close_ogg(demuxer); break; demux_close_ogg(demuxer); break;
#ifdef STREAMING_LIVE_DOT_COM
case DEMUXER_TYPE_RTP:
demux_close_rtp(demuxer); break;
#endif
case DEMUXER_TYPE_DEMUXERS: case DEMUXER_TYPE_DEMUXERS:
demux_close_demuxers(demuxer); return; demux_close_demuxers(demuxer); return;
case DEMUXER_TYPE_AVI: case DEMUXER_TYPE_AVI:
@ -255,6 +260,7 @@ int demux_mov_fill_buffer(demuxer_t *demux,demux_stream_t* ds);
int demux_vivo_fill_buffer(demuxer_t *demux); int demux_vivo_fill_buffer(demuxer_t *demux);
int demux_real_fill_buffer(demuxer_t *demuxer); int demux_real_fill_buffer(demuxer_t *demuxer);
int demux_nuv_fill_buffer(demuxer_t *demux); int demux_nuv_fill_buffer(demuxer_t *demux);
int demux_rtp_fill_buffer(demuxer_t *demux, demux_stream_t* ds);
#ifdef USE_TV #ifdef USE_TV
#include "tv.h" #include "tv.h"
extern tvi_handle_t *tv_handler; extern tvi_handle_t *tv_handler;
@ -296,6 +302,9 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
case DEMUXER_TYPE_DEMUXERS: return demux_demuxers_fill_buffer(demux,ds); case DEMUXER_TYPE_DEMUXERS: return demux_demuxers_fill_buffer(demux,ds);
case DEMUXER_TYPE_OGG: return demux_ogg_fill_buffer(demux); case DEMUXER_TYPE_OGG: return demux_ogg_fill_buffer(demux);
case DEMUXER_TYPE_RAWAUDIO: return demux_rawaudio_fill_buffer(demux,ds); 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; return 0;
} }
@ -793,6 +802,11 @@ if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_AUDIO){
demuxer = NULL; 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... =========================== //=============== Unknown, exiting... ===========================
if(file_format==DEMUXER_TYPE_UNKNOWN || demuxer == NULL){ if(file_format==DEMUXER_TYPE_UNKNOWN || demuxer == NULL){
mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_FormatNotRecognized); mp_msg(MSGT_DEMUXER,MSGL_ERR,MSGTR_FormatNotRecognized);
@ -949,6 +963,12 @@ switch(file_format){
break; break;
} }
#endif #endif
#ifdef STREAMING_LIVE_DOT_COM
case DEMUXER_TYPE_RTP: {
demux_open_rtp(demuxer);
break;
}
#endif
} // switch(file_format) } // switch(file_format)
pts_from_bps=0; // !!! pts_from_bps=0; // !!!
return demuxer; return demuxer;

View File

@ -29,10 +29,11 @@
#define DEMUXER_TYPE_OGG 18 #define DEMUXER_TYPE_OGG 18
#define DEMUXER_TYPE_BMP 19 #define DEMUXER_TYPE_BMP 19
#define DEMUXER_TYPE_RAWAUDIO 20 #define DEMUXER_TYPE_RAWAUDIO 20
#define DEMUXER_TYPE_RTP 21
// This should always match the higest demuxer type number. // This should always match the higest demuxer type number.
// Unless you want to disallow users to force the demuxer to some types // Unless you want to disallow users to force the demuxer to some types
#define DEMUXER_TYPE_MIN 0 #define DEMUXER_TYPE_MIN 0
#define DEMUXER_TYPE_MAX 20 #define DEMUXER_TYPE_MAX 21
#define DEMUXER_TYPE_DEMUXERS (1<<16) #define DEMUXER_TYPE_DEMUXERS (1<<16)
// A virtual demuxer type for the network code // A virtual demuxer type for the network code
@ -123,9 +124,9 @@ typedef struct demuxer_st {
} demuxer_t; } demuxer_t;
inline static demux_packet_t* new_demux_packet(int len){ 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->len=len;
dp->buffer=len?malloc(len+8):NULL; dp->buffer=len?(unsigned char*)malloc(len+8):NULL;
dp->next=NULL; dp->next=NULL;
dp->pts=0; dp->pts=0;
dp->pos=0; dp->pos=0;
@ -136,7 +137,7 @@ inline static demux_packet_t* new_demux_packet(int len){
} }
inline static demux_packet_t* clone_demux_packet(demux_packet_t* pack){ 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 while(pack->master) pack=pack->master; // find the master
memcpy(dp,pack,sizeof(demux_packet_t)); memcpy(dp,pack,sizeof(demux_packet_t));
dp->next=NULL; dp->next=NULL;

View File

@ -25,7 +25,9 @@
#include "http.h" #include "http.h"
#include "url.h" #include "url.h"
#include "asf.h" #include "asf.h"
#ifndef STREAMING_LIVE_DOT_COM
#include "rtp.h" #include "rtp.h"
#endif
#include "../version.h" #include "../version.h"
@ -113,6 +115,7 @@ streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl ) {
free( streaming_ctrl ); free( streaming_ctrl );
} }
#ifndef STREAMING_LIVE_DOT_COM
int int
read_rtp_from_server(int fd, char *buffer, int length) { read_rtp_from_server(int fd, char *buffer, int length) {
struct rtpheader rh; struct rtpheader rh;
@ -132,6 +135,7 @@ read_rtp_from_server(int fd, char *buffer, int length) {
memcpy(buffer, data, len); memcpy(buffer, data, len);
return(len); return(len);
} }
#endif
// Connect to a server using a TCP connection // Connect to a server using a TCP connection
int int
@ -454,10 +458,18 @@ extension=NULL;
// Checking for RTSP // Checking for RTSP
if( !strcasecmp(url->protocol, "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; return -1;
#endif
} }
#ifndef STREAMING_LIVE_DOT_COM
// Old, hacked RTP support, which works for MPEG Program Streams
// RTP streams only:
// Checking for RTP // Checking for RTP
if( !strcasecmp(url->protocol, "rtp") ) { if( !strcasecmp(url->protocol, "rtp") ) {
if( url->port==0 ) { if( url->port==0 ) {
@ -466,6 +478,7 @@ extension=NULL;
} }
return 0; return 0;
} }
#endif
// Checking for ASF // Checking for ASF
if( !strncasecmp(url->protocol, "mms", 3) ) { if( !strncasecmp(url->protocol, "mms", 3) ) {
@ -688,6 +701,7 @@ nop_streaming_start( stream_t *stream ) {
return 0; return 0;
} }
#ifndef STREAMING_LIVE_DOT_COM
// Start listening on a UDP port. If multicast, join the group. // Start listening on a UDP port. If multicast, join the group.
int int
rtp_open_socket( URL_t *url ) { rtp_open_socket( URL_t *url ) {
@ -789,6 +803,7 @@ rtp_streaming_start( stream_t *stream ) {
streaming_ctrl->status = streaming_playing_e; streaming_ctrl->status = streaming_playing_e;
return 0; return 0;
} }
#endif
int int
streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) { streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) {
@ -820,6 +835,7 @@ streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) {
} }
} }
#ifndef STREAMING_LIVE_DOT_COM
// For RTP streams, we usually don't know the stream type until we open it. // For RTP streams, we usually don't know the stream type until we open it.
if( !strcasecmp( stream->streaming_ctrl->url->protocol, "rtp")) { if( !strcasecmp( stream->streaming_ctrl->url->protocol, "rtp")) {
if(stream->fd >= 0) { if(stream->fd >= 0) {
@ -829,6 +845,7 @@ streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) {
stream->fd = -1; stream->fd = -1;
ret = rtp_streaming_start( stream ); ret = rtp_streaming_start( stream );
} else } else
#endif
// For connection-oriented streams, we can usually determine the streaming type. // For connection-oriented streams, we can usually determine the streaming type.
switch( *demuxer_type ) { switch( *demuxer_type ) {
case DEMUXER_TYPE_ASF: case DEMUXER_TYPE_ASF:
@ -840,6 +857,15 @@ streaming_start(stream_t *stream, int *demuxer_type, URL_t *url) {
mp_msg(MSGT_NETWORK,MSGL_ERR,"asf_streaming_start failed\n"); mp_msg(MSGT_NETWORK,MSGL_ERR,"asf_streaming_start failed\n");
} }
break; 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_ES:
case DEMUXER_TYPE_MPEG_PS: case DEMUXER_TYPE_MPEG_PS:
case DEMUXER_TYPE_AVI: case DEMUXER_TYPE_AVI:

View File

@ -22,6 +22,10 @@
#ifdef STREAMING #ifdef STREAMING
#include "url.h" #include "url.h"
#include "network.h" #include "network.h"
#ifdef STREAMING_LIVE_DOT_COM
#include "demux_rtp.h"
int isSDPFile = 0;
#endif
static URL_t* url; static URL_t* url;
#endif #endif
@ -471,6 +475,14 @@ tv_err:
#else #else
mp_msg(MSGT_OPEN,MSGL_V,"File size is %u bytes\n", (unsigned int)len); mp_msg(MSGT_OPEN,MSGL_V,"File size is %u bytes\n", (unsigned int)len);
#endif #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=new_stream(f,STREAMTYPE_FILE);
stream->end_pos=len; stream->end_pos=len;
return stream; return stream;

View File

@ -79,6 +79,13 @@ switch(d_video->demuxer->file_format){
#endif #endif
break; 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_ES:
case DEMUXER_TYPE_MPEG_PS: { case DEMUXER_TYPE_MPEG_PS: {
//mpeg_header_parser: //mpeg_header_parser:
@ -211,7 +218,11 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
*start=NULL; *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; int in_frame=0;
//float newfps; //float newfps;
//videobuf_len=0; //videobuf_len=0;