Seek WIP in player
This commit is contained in:
parent
21f6a1fe9d
commit
923d116afa
2 changed files with 102 additions and 23 deletions
114
src/player.cpp
114
src/player.cpp
|
@ -2,7 +2,9 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cstdio>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <mist/dtsc.h>
|
#include <mist/dtsc.h>
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
@ -16,10 +18,21 @@ namespace Player{
|
||||||
return t.tv_sec * 1000 + t.tv_usec/1000;
|
return t.tv_sec * 1000 + t.tv_usec/1000;
|
||||||
}//getNowMS
|
}//getNowMS
|
||||||
|
|
||||||
|
void setBlocking(int fd, bool blocking){
|
||||||
|
int flags = fcntl(fd, F_GETFL);
|
||||||
|
if (blocking){
|
||||||
|
flags &= ~O_NONBLOCK;
|
||||||
|
}else{
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
}
|
||||||
|
fcntl(fd, F_SETFL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
File::File(std::string filename){
|
File::File(std::string filename){
|
||||||
stream = new DTSC::Stream(5);
|
stream = new DTSC::Stream(5);
|
||||||
ring = NULL;// ring will be initialized when necessary
|
ring = NULL;// ring will be initialized when necessary
|
||||||
fileSrc.open(filename.c_str(), std::ifstream::in | std::ifstream::binary);
|
fileSrc.open(filename.c_str(), std::ifstream::in | std::ifstream::binary);
|
||||||
|
setBlocking(STDIN_FILENO, false);//prevent reading from stdin from blocking
|
||||||
std::cout.setf(std::ios::unitbuf);//do not choke
|
std::cout.setf(std::ios::unitbuf);//do not choke
|
||||||
nextPacket();// initial read always returns nothing
|
nextPacket();// initial read always returns nothing
|
||||||
if (!nextPacket()){//parse metadata
|
if (!nextPacket()){//parse metadata
|
||||||
|
@ -35,40 +48,89 @@ namespace Player{
|
||||||
}
|
}
|
||||||
delete stream;
|
delete stream;
|
||||||
}
|
}
|
||||||
|
/// \returns Number of read bytes or -1 on EOF
|
||||||
|
int File::fillBuffer(std::string & buffer){
|
||||||
|
char buff[1024 * 10];
|
||||||
|
if (fileSrc.good()){
|
||||||
|
fileSrc.read(buff, sizeof(buff));
|
||||||
|
inBuffer.append(buff, fileSrc.gcount());
|
||||||
|
return fileSrc.gcount();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// \returns True if there is a packet available for pull.
|
// \returns True if there is a packet available for pull.
|
||||||
bool File::nextPacket(){
|
bool File::nextPacket(){
|
||||||
if (fileSrc.good()){
|
|
||||||
if (stream->parsePacket(inBuffer)){
|
if (stream->parsePacket(inBuffer)){
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
char buffer[1024 * 10];
|
fillBuffer(inBuffer);
|
||||||
fileSrc.read(buffer, sizeof(buffer));
|
|
||||||
inBuffer.append(buffer, fileSrc.gcount());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void File::seek(int position){
|
void File::seek(unsigned int miliseconds){
|
||||||
// XXX: implement seek.
|
DTSC::Stream * tmpStream = new DTSC::Stream(1);
|
||||||
|
int leftByte = 1, rightByte = INT_MAX;
|
||||||
|
int leftMS = 0, rightMS = INT_MAX;
|
||||||
|
/// \todo set last packet as last byte, consider metadata
|
||||||
|
while (rightMS - leftMS >= 100){
|
||||||
|
std::string buffer;
|
||||||
|
// binary search: pick the first packet on the right
|
||||||
|
unsigned int medByte = leftByte + (rightByte - leftByte) / 2;
|
||||||
|
fileSrc.clear();// clear previous IO errors
|
||||||
|
fileSrc.seekg(medByte);
|
||||||
|
|
||||||
|
do{ // find first occurrence of packet
|
||||||
|
unsigned int header_pos, read_bytes;
|
||||||
|
read_bytes = fillBuffer(buffer);
|
||||||
|
/// \todo handle EOF
|
||||||
|
header_pos = buffer.find(DTSC::Magic_Packet);
|
||||||
|
if (header_pos == std::string::npos){
|
||||||
|
// it is possible that the magic packet is partially shown, e.g. "DTP"
|
||||||
|
if (read_bytes > strlen(DTSC::Magic_Packet) - 1){
|
||||||
|
read_bytes -= strlen(DTSC::Magic_Packet) - 1;
|
||||||
|
buffer.erase(0, read_bytes);
|
||||||
|
medByte += read_bytes;
|
||||||
|
}
|
||||||
|
continue;// continue filling the buffer without parsing packet
|
||||||
|
}
|
||||||
|
}while (!tmpStream->parsePacket(buffer));
|
||||||
|
JSON::Value & medPacket = tmpStream->getPacket(0);
|
||||||
|
/// \todo What if time does not exist? Currently it just crashes.
|
||||||
|
// assumes that the time does not get over 49 days (on a 32-bit system)
|
||||||
|
unsigned int medMS = (unsigned int)medPacket["time"].asInt();
|
||||||
|
|
||||||
|
if (medMS > miliseconds){
|
||||||
|
rightByte = medByte;
|
||||||
|
rightMS = medMS;
|
||||||
|
}else if (medMS < miliseconds){
|
||||||
|
leftByte = medByte;
|
||||||
|
leftMS = medMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear the buffer and adjust file pointer
|
||||||
|
inBuffer.clear();
|
||||||
|
fileSrc.seekg(leftByte);
|
||||||
|
delete tmpStream;
|
||||||
};
|
};
|
||||||
std::string * File::getPacket(){
|
std::string & File::getPacket(){
|
||||||
|
static std::string emptystring;
|
||||||
if (ring->waiting){
|
if (ring->waiting){
|
||||||
return NULL;
|
return emptystring;
|
||||||
}//still waiting for next buffer?
|
}//still waiting for next buffer?
|
||||||
if (ring->starved){
|
if (ring->starved){
|
||||||
//if corrupt data, warn and get new DTSC::Ring
|
//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;
|
std::cerr << "Warning: User was send corrupt video data and send to the next keyframe!" << std::endl;
|
||||||
stream->dropRing(ring);
|
stream->dropRing(ring);
|
||||||
ring = stream->getRing();
|
ring = stream->getRing();
|
||||||
return NULL;
|
return emptystring;
|
||||||
}
|
}
|
||||||
//switch to next buffer
|
//switch to next buffer
|
||||||
if (ring->b < 0){
|
if (ring->b < 0){
|
||||||
ring->waiting = true;
|
ring->waiting = true;
|
||||||
return NULL;
|
return emptystring;
|
||||||
}//no next buffer? go in waiting mode.
|
}//no next buffer? go in waiting mode.
|
||||||
// get current packet
|
// get current packet
|
||||||
std::string * packet = &stream->outPacket(ring->b);
|
std::string & packet = stream->outPacket(ring->b);
|
||||||
// make next request take a different packet
|
// make next request take a different packet
|
||||||
ring->b--;
|
ring->b--;
|
||||||
return packet;
|
return packet;
|
||||||
|
@ -76,7 +138,24 @@ namespace Player{
|
||||||
|
|
||||||
/// Reads a command from stdin. Returns true if a command was read.
|
/// Reads a command from stdin. Returns true if a command was read.
|
||||||
bool File::readCommand() {
|
bool File::readCommand() {
|
||||||
// XXX: implement seek.
|
char line[512];
|
||||||
|
if (fgets(line, sizeof(line), stdin) == NULL){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int position = INT_MAX;// special value that says "invalid"
|
||||||
|
if (!strncmp("seek ", line, sizeof("seek ") - 1)){
|
||||||
|
position = atoi(line + sizeof("seek ") - 1);
|
||||||
|
}
|
||||||
|
if (!strncmp("relseek ", line, sizeof("relseek " - 1))){
|
||||||
|
/// \todo implement relseek in a smart way
|
||||||
|
//position = atoi(line + sizeof("relseek "));
|
||||||
|
}
|
||||||
|
if (position != INT_MAX){
|
||||||
|
File::seek(position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,17 +168,16 @@ namespace Player{
|
||||||
now = getNowMS();
|
now = getNowMS();
|
||||||
if (now - timeDiff >= lastTime || lastTime - (now - timeDiff) > 5000) {
|
if (now - timeDiff >= lastTime || lastTime - (now - timeDiff) > 5000) {
|
||||||
if (nextPacket()) {
|
if (nextPacket()) {
|
||||||
std::string * packet;
|
|
||||||
if (!ring){ring = stream->getRing();}//get ring after reading first non-metadata
|
if (!ring){ring = stream->getRing();}//get ring after reading first non-metadata
|
||||||
packet = getPacket();
|
std::string & packet = getPacket();
|
||||||
if (!packet){
|
if (packet.empty()){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
lastTime = stream->getTime();
|
lastTime = stream->getTime();
|
||||||
if (std::abs(now - timeDiff - lastTime) > 5000) {
|
if (std::abs(now - timeDiff - lastTime) > 5000) {
|
||||||
timeDiff = now - lastTime;
|
timeDiff = now - lastTime;
|
||||||
}
|
}
|
||||||
std::cout.write(packet->c_str(), packet->length());
|
std::cout.write(packet.c_str(), packet.length());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
usleep(std::min(999LL, lastTime - (now - timeDiff)) * 1000);
|
usleep(std::min(999LL, lastTime - (now - timeDiff)) * 1000);
|
||||||
|
|
|
@ -15,11 +15,12 @@ namespace Player{
|
||||||
bool nextPacket(); ///<Pulls the next packet into the queue.
|
bool nextPacket(); ///<Pulls the next packet into the queue.
|
||||||
bool getPacketFromInput(); ///<Attempts to retrieve a packet from input.
|
bool getPacketFromInput(); ///<Attempts to retrieve a packet from input.
|
||||||
bool readCommand();
|
bool readCommand();
|
||||||
|
int fillBuffer(std::string & buffer);
|
||||||
public:
|
public:
|
||||||
File(std::string filename); ///<Attempts to open a DTSC file
|
File(std::string filename); ///<Attempts to open a DTSC file
|
||||||
void Play();
|
void Play();
|
||||||
~File();
|
~File();
|
||||||
void seek(int position);
|
void seek(unsigned int miliseconds);
|
||||||
std::string * getPacket();
|
std::string & getPacket();
|
||||||
};
|
};
|
||||||
};
|
};
|
Loading…
Add table
Reference in a new issue