Ogg support fixed and re-added. Squash of various commits made by Wouter Spruit.

This commit is contained in:
Thulinma 2014-12-23 13:10:28 +01:00
parent 142ef73f6c
commit a47504b5cb
17 changed files with 944 additions and 456 deletions

View file

@ -163,7 +163,7 @@ namespace Mist {
void Output::negotiatePushTracks() {
int i = 0;
for (std::map<int, DTSC::Track>::iterator it = meta_out.tracks.begin(); it != meta_out.tracks.end() && i < 5; it++){
for (std::map<unsigned int, DTSC::Track>::iterator it = meta_out.tracks.begin(); it != meta_out.tracks.end() && i < 5; it++){
negotiateWithBuffer(it->first);
i++;
}
@ -286,7 +286,7 @@ namespace Mist {
}
}
if (!found){
for (std::map<int,DTSC::Track>::iterator trit = myMeta.tracks.begin(); trit != myMeta.tracks.end(); trit++){
for (std::map<unsigned int,DTSC::Track>::iterator trit = myMeta.tracks.begin(); trit != myMeta.tracks.end(); trit++){
if (trit->second.codec == (*itc).asStringRef()){
genCounter++;
found = true;
@ -326,7 +326,7 @@ namespace Mist {
}
}
if (!found){
for (std::map<int,DTSC::Track>::iterator trit = myMeta.tracks.begin(); trit != myMeta.tracks.end(); trit++){
for (std::map<unsigned int,DTSC::Track>::iterator trit = myMeta.tracks.begin(); trit != myMeta.tracks.end(); trit++){
if (trit->second.codec == (*itc).asStringRef()){
selectedTracks.insert(trit->first);
found = true;
@ -438,8 +438,8 @@ namespace Mist {
return;
}
char id[100];
sprintf(id, "%s%lu_%d", streamName.c_str(), trackId, pageNum);
curPages[trackId].init(std::string(id),26 * 1024 * 1024);
snprintf(id, 100, "%s%lu_%d", streamName.c_str(), trackId, pageNum);
curPages[trackId].init(id, 26 * 1024 * 1024);
if (!(curPages[trackId].mapped)){
DEBUG_MSG(DLVL_FAIL, "Initializing page %s failed", curPages[trackId].name.c_str());
return;
@ -448,7 +448,7 @@ namespace Mist {
}
/// Prepares all tracks from selectedTracks for seeking to the specified ms position.
void Output::seek(long long pos){
void Output::seek(unsigned long long pos){
sought = true;
firstTime = Util::getMS() - pos;
if (!isInitialized){
@ -457,16 +457,16 @@ namespace Mist {
buffer.clear();
currentPacket.null();
updateMeta();
DEBUG_MSG(DLVL_MEDIUM, "Seeking to %llims", pos);
DEBUG_MSG(DLVL_MEDIUM, "Seeking to %llums", pos);
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
seek(*it, pos);
}
}
bool Output::seek(int tid, long long pos, bool getNextKey){
bool Output::seek(unsigned int tid, unsigned long long pos, bool getNextKey){
loadPageForKey(tid, getKeyForTime(tid, pos) + (getNextKey?1:0));
if (!curPages.count(tid) || !curPages[tid].mapped){
DEBUG_MSG(DLVL_DEVEL, "Aborting seek to %llims in track %d, not available.", pos, tid);
DEBUG_MSG(DLVL_DEVEL, "Aborting seek to %llums in track %u, not available.", pos, tid);
return false;
}
sortedPageInfo tmp;
@ -724,7 +724,7 @@ namespace Mist {
}
if (trackMap.size()){
for (std::map<int, int>::iterator it = trackMap.begin(); it != trackMap.end() && tNum < 5; it++){
int tId = it->second;
unsigned int tId = it->second;
char * thisData = playerConn.getData() + (6 * tNum);
thisData[0] = ((tId >> 24) & 0xFF);
thisData[1] = ((tId >> 16) & 0xFF);
@ -736,7 +736,7 @@ namespace Mist {
}
}else{
for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end() && tNum < 5; it++){
int tId = *it;
unsigned int tId = *it;
char * thisData = playerConn.getData() + (6 * tNum);
thisData[0] = ((tId >> 24) & 0xFF);
thisData[1] = ((tId >> 16) & 0xFF);

View file

@ -20,7 +20,7 @@ namespace Mist {
}
return (time == rhs.time && tid < rhs.tid);
}
int tid;
unsigned int tid;
long long unsigned int time;
unsigned int offset;
};
@ -53,8 +53,8 @@ namespace Mist {
//non-virtual generic functions
int run();
void stats();
void seek(long long pos);
bool seek(int tid, long long pos, bool getNextKey = false);
void seek(unsigned long long pos);
bool seek(unsigned int tid, unsigned long long pos, bool getNextKey = false);
void stop();
void setBlocking(bool blocking);
long unsigned int getMainSelectedTrack();

View file

@ -12,7 +12,7 @@ namespace Mist {
audioTrack = 0;
JSON::Value & vidCapa = capa["codecs"][0u][0u];
JSON::Value & audCapa = capa["codecs"][0u][1u];
for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (JSON::ArrIter itb = vidCapa.ArrBegin(); itb != vidCapa.ArrEnd(); itb++){
if (it->second.codec == (*itb).asStringRef()){
videoTracks.insert(it->first);

View file

@ -10,14 +10,14 @@ namespace Mist {
result << "#EXTM3U\r\n";
int audioId = -1;
std::string audioName;
for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
if (it->second.codec == "AAC"){
audioId = it->first;
audioName = it->second.getIdentifier();
break;
}
}
for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
if (it->second.codec == "H264"){
int bWidth = it->second.bps * 2;
if (audioId != -1){
@ -266,7 +266,7 @@ namespace Mist {
return 1;
}
//loop trough all the tracks
for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
//return "too late" if one track is past this point
if (ms < it->second.firstms){
return -1;

View file

@ -295,13 +295,13 @@ namespace Mist {
"MajorVersion=\"2\" "
"MinorVersion=\"0\" "
"TimeScale=\"10000000\" ";
std::deque<std::map<int, DTSC::Track>::iterator> audioIters;
std::deque<std::map<int, DTSC::Track>::iterator> videoIters;
std::deque<std::map<unsigned int, DTSC::Track>::iterator> audioIters;
std::deque<std::map<unsigned int, DTSC::Track>::iterator> videoIters;
long long int maxWidth = 0;
long long int maxHeight = 0;
long long int minWidth = 99999999;
long long int minHeight = 99999999;
for (std::map<int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
if (it->second.codec == "AAC") {
audioIters.push_back(it);
}
@ -343,7 +343,7 @@ namespace Mist {
"Chunks=\"" << (*audioIters.begin())->second.keys.size() << "\" "
"Url=\"Q({bitrate},{CustomAttributes})/A({start time})\">\n";
int index = 0;
for (std::deque<std::map<int, DTSC::Track>::iterator>::iterator it = audioIters.begin(); it != audioIters.end(); it++) {
for (std::deque<std::map<unsigned int, DTSC::Track>::iterator>::iterator it = audioIters.begin(); it != audioIters.end(); it++) {
Result << "<QualityLevel "
"Index=\"" << index << "\" "
"Bitrate=\"" << (*it)->second.bps * 8 << "\" "
@ -388,7 +388,7 @@ namespace Mist {
"DisplayWidth=\"" << maxWidth << "\" "
"DisplayHeight=\"" << maxHeight << "\">\n";
int index = 0;
for (std::deque<std::map<int, DTSC::Track>::iterator>::iterator it = videoIters.begin(); it != videoIters.end(); it++) {
for (std::deque<std::map<unsigned int, DTSC::Track>::iterator>::iterator it = videoIters.begin(); it != videoIters.end(); it++) {
//Add video qualities
Result << "<QualityLevel "
"Index=\"" << index << "\" "
@ -450,7 +450,7 @@ namespace Mist {
void OutHSS::initialize() {
Output::initialize();
for (std::map<int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
for (std::deque<DTSC::Key>::iterator it2 = it->second.keys.begin(); it2 != it->second.keys.end(); it2++) {
keyTimes[it->first].insert(it2->getTime());
}

View file

@ -51,7 +51,7 @@ namespace Mist {
if (H.GetVar("callback") != ""){jsonp = H.GetVar("callback");}
if (H.GetVar("jsonp") != ""){jsonp = H.GetVar("jsonp");}
initialize();
for (std::map<int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
for (std::map<unsigned int,DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
if (it->second.type == "meta" ){
selectedTracks.insert(it->first);
}

View file

@ -0,0 +1,208 @@
#include "output_progressive_ogg.h"
#include <mist/bitstream.h>
#include <mist/defines.h>
#include <algorithm>
namespace Mist {
OutProgressiveOGG::OutProgressiveOGG(Socket::Connection & conn) : HTTPOutput(conn){
realTime = 0;
}
OutProgressiveOGG::~OutProgressiveOGG(){}
void OutProgressiveOGG::init(Util::Config * cfg){
HTTPOutput::init(cfg);
capa["name"] = "OGG";
capa["desc"] = "Enables HTTP protocol progressive streaming.";
capa["deps"] = "HTTP";
capa["url_rel"] = "/$.ogg";
capa["url_match"] = "/$.ogg";
capa["codecs"][0u][0u].append("theora");
capa["codecs"][0u][1u].append("vorbis");
capa["codecs"][0u][1u].append("opus");
capa["methods"][0u]["handler"] = "http";
capa["methods"][0u]["type"] = "html5/video/ogg";
capa["methods"][0u]["priority"] = 8ll;
capa["methods"][0u]["nolive"] = 1;
}
void OutProgressiveOGG::sendNext(){
unsigned int track = currentPacket.getTrackId();
OGG::oggSegment newSegment;
currentPacket.getString("data", newSegment.dataString);
// if (currentPacket.getTime() > 315800){// && currentPacket.getTime() < 316200){
//INFO_MSG("Found a packet of time %llu, size: %d", currentPacket.getTime(), newSegment.dataString.size());
//}
pageBuffer[track].totalFrames = ((double)currentPacket.getTime() / (1000000.0f / myMeta.tracks[track].fpks)) + 1.5; //should start at 1. added .5 for rounding.
// INFO_MSG("track: %u totalFrames %llu timestamp: %llu totalframe value: %f", track, pageBuffer[track].totalFrames, currentPacket.getTime(), ((double)currentPacket.getTime() / (1000000.0f / myMeta.tracks[track].fpks)) + 1);
if (pageBuffer[track].codec == OGG::THEORA){
newSegment.isKeyframe = currentPacket.getFlag("keyframe");
if (newSegment.isKeyframe == true){
pageBuffer[track].sendTo(myConn);//send data remaining in buffer (expected to fit on a page), keyframe will allways start on new page
// INFO_MSG("segments left in buffer: %d", pageBuffer[track].oggSegments.size());
pageBuffer[track].lastKeyFrame = pageBuffer[track].totalFrames;
}
newSegment.framesSinceKeyFrame = pageBuffer[track].totalFrames - pageBuffer[track].lastKeyFrame;
newSegment.lastKeyFrameSeen = pageBuffer[track].lastKeyFrame;
// theora::frame tmpFrame;
// tmpFrame.read(newSegment.dataString.data(),newSegment.dataString.size());
// INFO_MSG("FTYPE: %d ISKEYFRAME: %d",tmpFrame.getFTYPE(),newSegment.isKeyframe );
}
newSegment.frameNumber = pageBuffer[track].totalFrames;
newSegment.timeStamp = currentPacket.getTime();
pageBuffer[track].oggSegments.push_back(newSegment);
if (pageBuffer[track].codec == OGG::VORBIS){
pageBuffer[track].vorbisStuff();//this updates lastKeyFrame
}
// while (pageBuffer[track].oggSegments.size()){
//pageBuffer[track].sendTo(myConn);
//}
while (pageBuffer[track].shouldSend()){
pageBuffer[track].sendTo(myConn);
}
}
bool OutProgressiveOGG::onFinish(){
for (std::map<long long unsigned int, OGG::Page>::iterator it = pageBuffer.begin(); it != pageBuffer.end(); it++){
it->second.setHeaderType(OGG::EndOfStream);
it->second.sendTo(myConn);
}
return false;
}
bool OutProgressiveOGG::parseInit(std::string & initData, std::deque<std::string> & output){
std::string temp;
unsigned int index = 0;
if (initData[0] == 0x02){ //"special" case, requires interpretation similar to table
if (initData.size() < 7){
FAIL_MSG("initData size too tiny (size: %lu)", initData.size());
return false;
}
unsigned int len1 = 0 ;
unsigned int len2 = 0 ;
index = 1;
while (initData[index] == 255){ //get len 1
len1 += initData[index++];
}
len1 += initData[index++];
while (initData[index] == 255){ //get len 1
len2 += initData[index++];
}
len2 += initData[index++];
if (initData.size() < (len1 + len2 + 4)){
FAIL_MSG("initData size too tiny (size: %lu)", initData.size());
return false;
}
temp = initData.substr(index, len1);
output.push_back(temp);
index += len1;
temp = initData.substr(index, len2);
output.push_back(temp);
index += len2;
temp = initData.substr(index); //remainder of string:
output.push_back(temp); //add data to output deque
} else {
if (initData.size() < 7){
FAIL_MSG("initData size too tiny (size: %lu)", initData.size());
return false;
}
unsigned int len = 0;
for (unsigned int i = 0; i < 3; i++){
temp = initData.substr(index, 2);
len = (((unsigned int)temp[0]) << 8) | (temp[1]); //2 bytes len
index += 2; //start of data
if (index + len > initData.size()){
FAIL_MSG("index+len > initData size");
return false;
}
temp = initData.substr(index, len);
output.push_back(temp); //add data to output deque
index += len;
INFO_MSG("init data len[%d]: %d ", i, len);
}
}
return true;
}
void OutProgressiveOGG::sendHeader(){
HTTP_S.Clean(); //make sure no parts of old requests are left in any buffers
HTTP_S.SetHeader("Content-Type", "video/ogg");
HTTP_S.protocol = "HTTP/1.0";
myConn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file
std::map<int, std::deque<std::string> > initData;
OGG::oggSegment newSegment;
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
parseInit(myMeta.tracks[*it].init, initData[*it]);
if (myMeta.tracks[*it].codec == "theora"){ //get size and position of init data for this page.
pageBuffer[*it].codec = OGG::THEORA;
pageBuffer[*it].totalFrames = 1; //starts at frame number 1, according to weird offDetectMeta function.
std::string tempStr = initData[*it][0];
theora::header tempHead((char *)tempStr.c_str(), 42);
pageBuffer[*it].split = tempHead.getKFGShift();
INFO_MSG("got theora KFG shift: %d", pageBuffer[*it].split); //looks OK.
} else if (myMeta.tracks[*it].codec == "vorbis"){
pageBuffer[*it].codec = OGG::VORBIS;
pageBuffer[*it].totalFrames = 0;
pageBuffer[*it].sampleRate = myMeta.tracks[*it].rate;
pageBuffer[*it].prevBlockFlag = -1;
vorbis::header tempHead((char *)initData[*it][0].data(), initData[*it][0].size());
pageBuffer[*it].blockSize[0] = std::min(tempHead.getBlockSize0(), tempHead.getBlockSize1());
pageBuffer[*it].blockSize[1] = std::max(tempHead.getBlockSize0(), tempHead.getBlockSize1());
char audioChannels = tempHead.getAudioChannels(); //?
vorbis::header tempHead2((char *)initData[*it][2].data(), initData[*it][2].size());
pageBuffer[*it].vorbisModes = tempHead2.readModeDeque(audioChannels);//getting modes
} else if (myMeta.tracks[*it].codec == "opus"){
pageBuffer[*it].totalFrames = 0; //?
pageBuffer[*it].codec = OGG::OPUS;
}
pageBuffer[*it].clear(OGG::BeginOfStream, 0, *it, 0); //CREATES a (map)pageBuffer object, *it = id, pagetype=BOS
newSegment.dataString = initData[*it][0];
pageBuffer[*it].oggSegments.push_back(newSegment);
pageBuffer[*it].sendTo(myConn, 0); //granule position of 0
}
for (std::set<long unsigned int>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++){
newSegment.dataString = initData[*it][1];
pageBuffer[*it].oggSegments.push_back(newSegment);
newSegment.dataString = initData[*it][2];
pageBuffer[*it].oggSegments.push_back(newSegment);
while (pageBuffer[*it].oggSegments.size()){
pageBuffer[*it].sendTo(myConn, 0); //granule position of 0
}
}
sentHeader = true;
}
void OutProgressiveOGG::onRequest(){
if (HTTP_R.Read(myConn)){
DEBUG_MSG(DLVL_DEVEL, "Received request %s", HTTP_R.getUrl().c_str());
if (HTTP_R.GetVar("audio") != ""){
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("audio")).asInt());
}
if (HTTP_R.GetVar("video") != ""){
selectedTracks.insert(JSON::Value(HTTP_R.GetVar("video")).asInt());
}
parseData = true;
wantRequest = false;
HTTP_R.Clean();
}
}
}

View file

@ -0,0 +1,28 @@
#include "output_http.h"
#include <mist/ogg.h>
#include <mist/http_parser.h>
namespace Mist {
class OutProgressiveOGG : public HTTPOutput {
public:
OutProgressiveOGG(Socket::Connection & conn);
~OutProgressiveOGG();
static void init(Util::Config * cfg);
void onRequest();
void sendNext();
void sendHeader();
bool onFinish();
bool parseInit(std::string & initData, std::deque<std::string> & output);
protected:
HTTP::Parser HTTP_R;//Received HTTP
HTTP::Parser HTTP_S;//Sent HTTP
std::map <long long unsigned int, OGG::Page > pageBuffer; //OGG specific variables
};
}
typedef Mist::OutProgressiveOGG mistOut;