From 21f6a1fe9d2b0346ee5b218d4815d6f622cc294a Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Sun, 26 Aug 2012 00:05:23 +0200 Subject: [PATCH] player: initial implementation --- src/Makefile.am | 4 +- src/player.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ src/player.h | 25 ++++++++++ 3 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/player.cpp create mode 100644 src/player.h diff --git a/src/Makefile.am b/src/Makefile.am index a0c9a638..be9d6a23 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ EXTRA_DIST=server.html server.html.h embed.js.h AM_CPPFLAGS = $(MIST_CFLAGS) LDADD = $(MIST_LIBS) SUBDIRS=converters analysers -bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic +bin_PROGRAMS=MistBuffer MistController MistConnRAW MistConnRTMP MistConnHTTP MistConnHTTPProgressive MistConnHTTPDynamic MistPlayer MistBuffer_SOURCES=buffer.cpp buffer_user.h buffer_user.cpp buffer_stream.h buffer_stream.cpp tinythread.cpp tinythread.h ../VERSION MistBuffer_LDADD=$(MIST_LIBS) -lpthread MistController_SOURCES=controller.cpp ../VERSION ./server.html.h @@ -18,6 +18,8 @@ MistConnHTTP_SOURCES=conn_http.cpp tinythread.cpp tinythread.h ../VERSION ./embe MistConnHTTP_LDADD=$(MIST_LIBS) -lpthread MistConnHTTPProgressive_SOURCES=conn_http_progressive.cpp ../VERSION MistConnHTTPDynamic_SOURCES=conn_http_dynamic.cpp ../VERSION +MistPlayer_SOURCES=player.h player.cpp +MistPlayer_LDADD=$(MIST_LIBS) lspSOURCES=$(lspdir)/jquery.js $(lspdir)/placeholder.js $(lspdir)/md5.js $(lspdir)/main.js $(lspdir)/functions.js lspDATA=$(lspdir)/header.html $(lspdir)/style.css $(lspdir)/footer.html diff --git a/src/player.cpp b/src/player.cpp new file mode 100644 index 00000000..d0ab4155 --- /dev/null +++ b/src/player.cpp @@ -0,0 +1,124 @@ + +#include +#include +#include + +#include +#include +#include "player.h" + +namespace Player{ + ///\todo Make getNowMS available in a library + /// Gets the current system time in milliseconds. + long long int getNowMS(){ + timeval t; + gettimeofday(&t, 0); + return t.tv_sec * 1000 + t.tv_usec/1000; + }//getNowMS + + File::File(std::string filename){ + stream = new DTSC::Stream(5); + ring = NULL;// ring will be initialized when necessary + fileSrc.open(filename.c_str(), std::ifstream::in | std::ifstream::binary); + std::cout.setf(std::ios::unitbuf);//do not choke + nextPacket();// initial read always returns nothing + if (!nextPacket()){//parse metadata + std::cout << stream->outHeader(); + } else { + std::cerr << "Error: Expected metadata!" << std::endl; + } + }; + File::~File() { + if (ring) { + stream->dropRing(ring); + ring = NULL; + } + delete stream; + } + // \returns True if there is a packet available for pull. + bool File::nextPacket(){ + if (fileSrc.good()){ + if (stream->parsePacket(inBuffer)){ + return true; + } else { + char buffer[1024 * 10]; + fileSrc.read(buffer, sizeof(buffer)); + inBuffer.append(buffer, fileSrc.gcount()); + } + } + return false; + } + void File::seek(int position){ + // XXX: implement seek. + }; + std::string * File::getPacket(){ + if (ring->waiting){ + return NULL; + }//still waiting for next buffer? + if (ring->starved){ + //if corrupt data, warn and get new DTSC::Ring + std::cerr << "Warning: User was send corrupt video data and send to the next keyframe!" << std::endl; + stream->dropRing(ring); + ring = stream->getRing(); + return NULL; + } + //switch to next buffer + if (ring->b < 0){ + ring->waiting = true; + return NULL; + }//no next buffer? go in waiting mode. + // get current packet + std::string * packet = &stream->outPacket(ring->b); + // make next request take a different packet + ring->b--; + return packet; + } + + /// Reads a command from stdin. Returns true if a command was read. + bool File::readCommand() { + // XXX: implement seek. + return false; + } + + void File::Play() { + long long now, timeDiff = 0, lastTime = 0; + while (fileSrc.good()) { + if (readCommand()) { + continue; + } + now = getNowMS(); + if (now - timeDiff >= lastTime || lastTime - (now - timeDiff) > 5000) { + if (nextPacket()) { + std::string * packet; + if (!ring){ring = stream->getRing();}//get ring after reading first non-metadata + packet = getPacket(); + if (!packet){ + continue; + } + lastTime = stream->getTime(); + if (std::abs(now - timeDiff - lastTime) > 5000) { + timeDiff = now - lastTime; + } + std::cout.write(packet->c_str(), packet->length()); + } + } else { + usleep(std::min(999LL, lastTime - (now - timeDiff)) * 1000); + } + } + } +}; + +int main(int argc, char** argv){ + if (argc < 2){ + std::cerr << "Usage: " << argv[0] << " filename.dtsc" << std::endl; + return 1; + } + std::string filename = argv[1]; + #if DEBUG >= 3 + std::cerr << "VoD " << filename << std::endl; + #endif + Player::File file(filename); + file.Play(); + return 0; +} + diff --git a/src/player.h b/src/player.h new file mode 100644 index 00000000..ebcd5176 --- /dev/null +++ b/src/player.h @@ -0,0 +1,25 @@ +/// \file player.h +/// Provides functionality for playing files for Video on Demand + +#pragma once + +#include "buffer_stream.h" + +namespace Player{ + class File{ + private: + std::ifstream fileSrc; ///