player: initial implementation

This commit is contained in:
Peter Wu 2012-08-26 00:05:23 +02:00
parent beca2400dd
commit 21f6a1fe9d
3 changed files with 152 additions and 1 deletions

View file

@ -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

124
src/player.cpp Normal file
View file

@ -0,0 +1,124 @@
#include <iostream>
#include <fstream>
#include <algorithm>
#include <sys/time.h>
#include <mist/dtsc.h>
#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;
}

25
src/player.h Normal file
View file

@ -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; ///<File handle of the input file.
std::string inBuffer; ///<Buffer of unprocessed bytes read from input.
DTSC::Stream * stream;
DTSC::Ring * ring;
bool nextPacket(); ///<Pulls the next packet into the queue.
bool getPacketFromInput(); ///<Attempts to retrieve a packet from input.
bool readCommand();
public:
File(std::string filename); ///<Attempts to open a DTSC file
void Play();
~File();
void seek(int position);
std::string * getPacket();
};
};