void AFeed::threadMethod()
{
- int alen;
+ bool alen;
while(1)
{
virtual int mute()=0;
virtual int unMute()=0;
-#ifndef NEW_DEMUXER
- virtual int write(UCHAR* buffer, ULONG length)=0;
-#endif
-
int volumeUp();
int volumeDown();
int getVolume();
}
#endif
-
-#ifdef NEW_DEMUXER
-
-UINT AudioMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos)
+void AudioMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
{
- return 0;
+ packet = mplist.front();
}
-void AudioMVP::ResetTimeOffsets()
+UINT AudioMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos)
{
+ int written = ::write(fdAudio, buffer + packet.pos_buffer + *samplepos,
+ packet.length - *samplepos);
+ if (written == (int)(packet.length - *samplepos)) {*samplepos = 0; return 1;}
+ if (written > 0) *samplepos += written;
+ return 0;
}
-#else
-
-int AudioMVP::write(UCHAR* buffer, ULONG length)
+void AudioMVP::ResetTimeOffsets()
{
- return ::write(fdAudio, buffer, length);
}
-
-#endif
int mute();
int unMute();
-#ifdef NEW_DEMUXER
- //Writing Data to Audiodevice -- unused in MVP code so far
- virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos);
+ //Writing Data to Audiodevice
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
+ virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos);
virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; };
virtual void ResetTimeOffsets();
-#else
- int write(UCHAR* buffer, ULONG length);
-#endif
#ifdef DEV
int test();
int initAllParams();
UCHAR streamType;
int fdAudio;
+
+ MediaPacket packet;
+ UINT packetpos;
};
#endif
return 1;\r
}\r
\r
-UINT AudioWin::DeliverMediaSample(MediaPacket packet,\r
- UCHAR* buffer,\r
+void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)\r
+{\r
+ mediapacket = mplist.front();\r
+}\r
+\r
+UINT AudioWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)\r
+{\r
+ DeliverMediaPacket(mediapacket, buffer, samplepos);\r
+ if (*samplepos == mediapacket.length) {\r
+ *samplepos = 0;\r
+ return 1;\r
+ }\r
+ else return 0;\r
+}\r
+\r
+UINT AudioWin::DeliverMediaPacket(MediaPacket packet,\r
+ const UCHAR* buffer,\r
UINT *samplepos)\r
{\r
/*First Check, if we have an audio sample*/\r
int write(char *buf, int len);\r
\r
// Writing Data to Audiodevice\r
- virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos);\r
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+ virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos);\r
+ UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos);\r
+ private:\r
+ MediaPacket mediapacket;\r
+ public:\r
virtual long long SetStartOffset(long long curreftime, bool *rsync);\r
virtual void ResetTimeOffsets();\r
\r
#ifndef DEFINES_H
#define DEFINES_H
-//#define NEW_DEMUXER //Switch for the new demuxer code
-//At the beginning the changed code will be switchable
-//in order to apply the changes also to the mvp code
-
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned int UINT;
arcnt = 0;
}
-int Demuxer::writeAudio()
+bool Demuxer::writeAudio()
{
return audiostream.drain();
}
-int Demuxer::writeVideo()
+bool Demuxer::writeVideo()
{
return videostream.drain();
}
void seek();
void setVideoStream(int id);
void setAudioStream(int id);
- int writeAudio();
- int writeVideo();
+ bool writeAudio();
+ bool writeVideo();
virtual int scan(UCHAR* buf, int len) = 0;
virtual int findVideoPTS(UCHAR* buf, int len, ULLONG* dest) = 0;
#include "defines.h"
#include <list>
-
-#ifdef NEW_DEMUXER
-
struct MediaPacket
{
- ULLONG recording_byte_pos; //position in recording
- ULLONG pts;
ULONG pos_buffer; //position in stream buffer
ULONG length; //length of the packet
- //The last to are only needed on windows, for memory reasons they can be excluded in mvp
+ // The fields below are not needed by the MVP
+#ifdef WIN32
+ ULLONG recording_byte_pos; //position in recording
+ ULLONG pts;
long long presentation_time;/* in 100 ns units*/
bool synched;
bool disconti;
+#endif
};
using namespace std;
-
typedef list<MediaPacket> MediaPacketList;
-#endif
-
class DrainTarget
{
public:
DrainTarget();
virtual ~DrainTarget();
-#ifdef NEW_DEMUXER
-
- virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos)=0;
-
- /* This function behaviour should be:
- Try to deliver the Data from packet.pos_buffer+samplepos to packet.pos_buffer+packet.length,
- with considering the bufferwraparound according to buffersize.
- Then increasing samplepos, so that on the next call delivering can proceed. So if writebytes are
- writen samplepos=samplepos+writebytes!
- If samplepos>=packet.length is returned, the next packet can be used for the next call.*/
-
virtual long long SetStartOffset(long long curreftime, bool *rsync)=0;
virtual void ResetTimeOffsets()=0;
-#else
- virtual int write(UCHAR* buffer, ULONG length)=0;
-#endif
-
+// The following two functions are used by the Stream
+// to deliver media packets to the front end (DrainTarget).
+//
+// First, the Stream calls PrepareMediaSample, which gives the front end
+// read-only access to the Stream's MediaPacketList. PrepareMediaSample should
+// examine the list to determine how much it wishes to consume, and
+// should copy any data it requires from the MediaPacket objects into
+// local storage.
+// This function call takes place under a mutex lock to ensure integrity
+// of the list structure. It should be fast and must not contain any
+// cancellation points, such as I/O calls for logging.
+//
+// Second, the Stream releases the mutex and calls DeliverMediaSample.
+// This function delivers data from the Stream buffer to the presentation
+// device and returns information to the Stream regarding how many MediaPackets
+// were consumed. Any data copied from the MediaPackets objects during
+// PrepareMediaSample is guaranteed by the Stream still to be valid
+// during the following DeliverMediaSample call.
+
+ // samplepos is equal to the number of bytes from the first MediaPacket
+ // in the list that have already been consumed in a previous call.
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0;
+
+ // The Stream guarantees that the value of *samplepos passed to
+ // DeliverMediaSample will be equal to the value of samplepos passed to
+ // PrepareMediaSample in the previous call.
+ // This function should consume data from the buffer according to the
+ // decisions made in PrepareMediaSample. Its return value and *samplepos
+ // tell the Stream how much data it consumed.
+ // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1
+ // (inclusive) from the list before the next call.
+ // DeliverMediaSample must also set *samplepos equal to the number of bytes
+ // processed from packet X (usually zero).
+ virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)=0;
};
-
-
-
#endif
-
else // do prebuffering
{
logger->log("Player", Log::DEBUG, "Prebuffering...");
+// afeed.start();
+// vfeed.start();
preBuffering = true;
}
/*
- Copyright 2005 Mark Calderbank
+ Copyright 2005-2006 Mark Calderbank
This file is part of VOMP.
*/
#include "stream.h"
+#include "log.h"
Stream::Stream()
{
initted = 0;
- draintarget=NULL;
-#ifdef NEW_DEMUXER
- cur_packet_pos=0;
-#endif
+ draintarget = NULL;
+ cur_packet_pos = 0;
}
Stream::~Stream()
void Stream::shutdown()
{
- if (initted) {
- free(outbuf);
-#ifdef NEW_DEMUXER
+ if (initted)
+ {
+ free(outbuf);
#ifdef WIN32
- CloseHandle(mutex);
-#endif
+ CloseHandle(mutex);
#endif
}
initted = 0;
-
}
int Stream::init(DrainTarget* tdt, int bufsize)
if (!outbuf) return 0;
draintarget = tdt;
bufferSize = bufsize;
- bufferHead = 0;
- bufferTail = 0;
- bufferMark = -1;
initted = 1;
-#ifdef NEW_DEMUXER
#ifndef WIN32
pthread_mutex_init(&mutex, NULL);
#else
mutex=CreateMutex(NULL,FALSE,NULL);
-#endif
#endif
return 1;
}
void Stream::flush()
{
-#ifdef NEW_DEMUXER
lock();
mediapackets.clear();
unLock();
if (draintarget) draintarget->ResetTimeOffsets();
-#endif
- bufferHead = 0;
- bufferTail = 0;
- bufferMark = -1;
}
-#ifndef NEW_DEMUXER
-int Stream::put(UCHAR* inbuf, int len)
+int Stream::put(const UCHAR* inbuf, int len)
{
int ret = 0;
- int tail = bufferTail;
- int head = bufferHead;
- if (tail == 0) tail = bufferSize;
-
- if (head < tail)
- {
- // The free space is in one continuous chunk.
- if (len < tail - head)
- {
- memcpy(outbuf + head, inbuf, len);
- bufferHead += len;
- ret = len;
- }
- }
- else if (len <= bufferSize - head)
- {
- // There is enough space above the Head.
- memcpy(outbuf + head, inbuf, len);
- if (head + len == bufferSize)
- bufferHead = 0;
- else
- bufferHead += len;
- ret = len;
- }
- else if (len < tail)
- {
- bufferMark = head;
- memcpy(outbuf, inbuf, len);
- bufferHead = len;
- ret = len;
- }
- return ret;
-}
-#else
-int Stream::put(UCHAR* inbuf, int len)
-{
- int ret = 0;
- int tail = bufferTail;
- int head = bufferHead;
- if (tail == 0) tail = bufferSize;
-
if (!draintarget) return 0;
MediaPacket newPacket;
- newPacket.length=len;
- newPacket.pos_buffer=0;
+ newPacket.length = len;
+ newPacket.pos_buffer = 0;
+#ifdef WIN32
newPacket.synched=false;
newPacket.disconti=false;
newPacket.pts=0;
newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti);
}
+#endif
- if (head < tail)
+ lock();
+ int front, back;
+ if (mediapackets.empty())
{
- // The free space is in one continuous chunk.
- if (len < tail - head)
- {
- memcpy(outbuf + head, inbuf, len);
- bufferHead += len;
- ret = len;
- newPacket.pos_buffer=head;
- lock();
- mediapackets.push_front(newPacket);
- unLock();
- }
+ back = 0; front = bufferSize;
}
- else if (len <= bufferSize - head)
+ else
{
- // There is enough space above the Head.
- memcpy(outbuf + head, inbuf, len);
- if (head + len == bufferSize)
- bufferHead = 0;
- else
- bufferHead += len;
-
- newPacket.pos_buffer=head;
- lock();
- mediapackets.push_front(newPacket);
- unLock();
+ front = mediapackets.front().pos_buffer;
+ back = mediapackets.back().pos_buffer + mediapackets.back().length;
+ if (back == bufferSize) back = 0;
+ }
+ unLock();
+ if (back <= front)
+ {
+ // The free space (if any) is in one continuous chunk.
+ if (len <= front - back) ret = len; // Is there enough of it?
+ }
+ else if (len <= bufferSize - back)
+ {
+ // There is enough space at the end of the buffer
ret = len;
}
- else if (len < tail)
+ else if (len <= front)
{
- bufferMark = head;
- memcpy(outbuf, inbuf, len);
- bufferHead = len;
+ // There is enough space at the start of the buffer
+ back = 0;
ret = len;
- newPacket.pos_buffer=0;
- lock();
- mediapackets.push_front(newPacket);
- unLock();
}
- return ret;
-}
-#endif
-
-#ifndef NEW_DEMUXER
-
-int Stream::drain()
-{
- int ret = 0;
- int head = bufferHead;
- int tail = bufferTail;
- int mark = bufferMark;
- int written;
- if (mark == -1 && tail > head) mark = bufferSize;
-
- if (mark >= 0)
+ if (ret) // Nonzero if we managed to find room for the packet
{
- // Drain up to the marker.
-#ifndef WIN32
- written = draintarget->write(outbuf + tail, (mark - tail));
-#else
- written=mark-tail;
- MILLISLEEP(1);
-#endif
- if (written < 0) return ret;
- ret += written;
- if (written == (mark - tail))
- {
- bufferMark = -1;
- bufferTail = tail = 0;
- }
- else
- {
- bufferTail += written;
- return ret;
- }
+ memcpy(outbuf + back, inbuf, len);
+ newPacket.pos_buffer = back;
+ lock();
+ mediapackets.push_back(newPacket);
+ unLock();
}
-
- if (tail == head) return ret; // Empty
-#ifndef WIN32
- written = draintarget->write(outbuf + tail, (head - tail));
-#else
- written=(head - tail);
- MILLISLEEP(1);
-#endif
- if (written < 0) return ret;
- ret += written;
- bufferTail = tail + written;
return ret;
}
-#else
-
-int Stream::drain()
+bool Stream::drain()
{
- int ret = 0;
- int written=1;
-// draintarget=dt; // this is now set in init, is this ok?
-
-
-
- if (mediapackets.empty()) {
- return 0;
- }
- // using mediapackets, may be this is slower but it is more flexible
- // while (!mediapackets.empty() && written) {
-
- int head = bufferHead;
- int tail = bufferTail;
- int mark = bufferMark;
- if (mark == -1 && tail > head) mark = bufferSize;
+ bool ret = false;
lock();
- MediaPacket cur_mp=mediapackets.back();
- unLock();
- written=0;
- written=draintarget->DeliverMediaSample(cur_mp,outbuf,&cur_packet_pos);
-
- ret+=written;
-
- if (cur_packet_pos==cur_mp.length) {
- cur_packet_pos=0;
- lock();
- mediapackets.pop_back();
- unLock();
- if ((((ULONG)tail)+cur_mp.length) < ((ULONG)mark)) {
- bufferTail=tail+cur_mp.length;
- } else {
- bufferTail=0;
- bufferMark=-1;
- }
-
+ UINT listlength = mediapackets.size();
+ if (listlength != 0)
+ {
+ draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
+ unLock();
+ UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
+ lock();
+ if (consumed != 0) ret = true;
+ if (consumed > listlength) consumed = listlength;
+ while (consumed--) mediapackets.pop_front();
}
-
+ unLock();
return ret;
}
{
#ifndef WIN32
pthread_mutex_lock(&mutex);
- logger->log("Player", Log::DEBUG, "LOCKED");
+ //logger->log("Player", Log::DEBUG, "LOCKED");
#else
WaitForSingleObject(mutex, INFINITE );
void Stream::unLock()
{
#ifndef WIN32
- logger->log("Player", Log::DEBUG, "UNLOCKING");
+ //logger->log("Player", Log::DEBUG, "UNLOCKING");
pthread_mutex_unlock(&mutex);
#else
ReleaseMutex(mutex);
#endif
}
-
-#endif
#ifndef STREAM_H
#define STREAM_H
+#ifndef WIN32
+#include <pthread.h>
+#endif
+
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#include "defines.h"
#include "draintarget.h"
-
-
class Stream
{
public:
int init(DrainTarget* tdt, int bufsize);
void shutdown();
void flush();
- int put(UCHAR* inbuf, int len);
- int drain();
+ int put(const UCHAR* inbuf, int len);
+ bool drain();
private:
-#ifdef NEW_DEMUXER
MediaPacketList mediapackets;
UINT cur_packet_pos;
#ifndef WIN32
#endif
void lock();
void unLock();
-#endif
DrainTarget* draintarget;
int initted;
UCHAR* outbuf;
int bufferSize;
- volatile int bufferHead;
- volatile int bufferTail;
- volatile int bufferMark;
};
#endif
void VFeed::threadMethod()
{
- int vlen;
+ bool vlen;
threadWaitForSignal(); // Don't feed video until audio has started
virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0;
virtual ULLONG getCurrentTimestamp()=0;
-#ifndef NEW_DEMUXER
- virtual int write(UCHAR* buffer, ULONG length)=0;
-#endif
-
virtual void turnVideoOn(){};
virtual void turnVideoOff(){};
virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; };
}
#endif
-
-
-#ifdef NEW_DEMUXER
-
-UINT VideoMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos)
-{
- return 0;
+void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
+{
+ MediaPacketList::const_iterator iter = mplist.begin();
+ deliver_start = iter->pos_buffer + samplepos;
+ mediapacket_len[0] = deliver_length = iter->length;
+ deliver_count = 1;
+ while (++iter != mplist.end() &&
+ iter->pos_buffer == deliver_start + deliver_length)
+ {
+ deliver_length += iter->length;
+ mediapacket_len[deliver_count] = iter->length;
+ ++deliver_count;
+ if (deliver_length >= WRITE_LENGTH ||
+ deliver_count == WRITE_PACKETS) break;
+ }
}
-void VideoMVP::ResetTimeOffsets()
+UINT VideoMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos)
{
+ int written = ::write(fdVideo, buffer + deliver_start, deliver_length);
+ if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;}
+ if (written <= 0) return 0;
+ // Handle a partial write. Is this possible? Should we bother?
+ UINT i = 0;
+ while ((written -= mediapacket_len[i]) >= 0) i++;
+ *samplepos = mediapacket_len[i] + written;
+ return i;
}
-#else
-
-int VideoMVP::write(UCHAR* buffer, ULONG length)
+void VideoMVP::ResetTimeOffsets()
{
- return ::write(fdVideo, buffer, length);
}
-
-#endif
-
#include "video.h"
#include "stb.h"
+#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream
+#define WRITE_PACKETS 16 // But no more than 16 packets
+
class VideoMVP : public Video
{
public:
ULONG timecodeToFrameNumber(ULLONG timecode);
ULLONG getCurrentTimestamp();
-#ifdef NEW_DEMUXER
- //Writing Data to Videodevice
- virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos);
- virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; };
+ // Writing Data to Videodevice
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);
+ virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT* samplepos);
+ virtual long long SetStartOffset(long long curreftime, bool *rsync)
+ { return 0; };
virtual void ResetTimeOffsets();
-#else
- int write(UCHAR* buffer, ULONG length);
-#endif
#ifdef DEV
int test();
private:
int checkSCART();
void setLetterboxBorder(char* border);
+
+ UINT deliver_start, deliver_length, deliver_count;
+ UINT mediapacket_len[WRITE_PACKETS];
};
#endif
\r
}\r
\r
+void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,\r
+ UINT samplepos)\r
+{\r
+ mediapacket = mplist.front();\r
+}\r
+\r
+UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)\r
+{\r
+ DeliverMediaPacket(mediapacket, buffer, samplepos);\r
+ if (*samplepos == mediapacket.length) {\r
+ *samplepos = 0;\r
+ return 1;\r
+ }\r
+ else return 0;\r
+}\r
\r
-UINT VideoWin::DeliverMediaSample(MediaPacket packet,\r
- UCHAR* buffer,\r
+UINT VideoWin::DeliverMediaPacket(MediaPacket packet,\r
+ const UCHAR* buffer,\r
UINT *samplepos)\r
{\r
/*First Check, if we have an audio sample*/\r
ULLONG getCurrentTimestamp();\r
\r
//Writing Data to Videodevice\r
- virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos);\r
+ virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos);\r
+ virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos);\r
+ UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos);\r
+ private:\r
+ MediaPacket mediapacket;\r
+ public:\r
\r
int getCurrentAudioMediaSample(IMediaSample** ms);\r
int DeliverAudioMediaSample();\r