mistserver/src/converters/oggconv.cpp
2014-04-04 19:50:40 +02:00

251 lines
12 KiB
C++

#include "oggconv.h"
#include <stdlib.h>
#include <mist/bitstream.h>
namespace OGG{
void converter::readDTSCHeader(DTSC::Meta & meta){
//pages.clear();
parsedPages = "";
Page curOggPage;
srand (Util::getMS());//randomising with milliseconds from boot
std::vector<unsigned int> curSegTable;
//trackInf.clear();
/// \todo This is utter rubbish right now.
/// \todo We shouldn't assume all possible tracks are selected.
/// \todo We shouldn't be buffering, but sending.
/// \todo Especially not in a std::string. (Why, god, why?!)
//Creating headers
for ( std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
trackInf[it->second.trackID].codec = it->second.codec;
trackInf[it->second.trackID].OGGSerial = rand() % 0xFFFFFFFE +1; //initialising on a random not 0 number
trackInf[it->second.trackID].seqNum = 0;
if (it->second.codec == "theora"){
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(it->second.idHeader.size());
curOggPage.setSegmentTable(curSegTable);
curOggPage.setPayload((char*)it->second.idHeader.c_str(), it->second.idHeader.size());
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
trackInf[it->second.trackID].lastKeyFrame = 1;
trackInf[it->second.trackID].sinceKeyFrame = 0;
theora::header tempHead;
std::string tempString = it->second.idHeader;
tempHead.read((char*)tempString.c_str(),42);
trackInf[it->second.trackID].significantValue = tempHead.getKFGShift();
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(0);//headertype 0 = normal
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(it->second.commentHeader.size());
curSegTable.push_back(it->second.init.size());
curOggPage.setSegmentTable(curSegTable);
std::string fullHeader = it->second.commentHeader + it->second.init;
curOggPage.setPayload((char*)fullHeader.c_str(),fullHeader.size());
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
}else if (it->second.codec == "vorbis"){
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(it->second.idHeader.size());
curOggPage.setSegmentTable(curSegTable);
curOggPage.setPayload((char*)it->second.idHeader.c_str(), it->second.idHeader.size());
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
trackInf[it->second.trackID].lastKeyFrame = 0;
trackInf[it->second.trackID].sinceKeyFrame = 0;
trackInf[it->second.trackID].prevBlockFlag = -1;
vorbis::header tempHead;
std::string tempString = it->second.idHeader;
tempHead.read((char*)tempString.c_str(),tempString.size());
trackInf[it->second.trackID].significantValue = tempHead.getAudioSampleRate() / tempHead.getAudioChannels();
if (tempHead.getBlockSize0() <= tempHead.getBlockSize1()){
trackInf[it->second.trackID].blockSize[0] = tempHead.getBlockSize0();
trackInf[it->second.trackID].blockSize[1] = tempHead.getBlockSize1();
}else{
trackInf[it->second.trackID].blockSize[0] = tempHead.getBlockSize1();
trackInf[it->second.trackID].blockSize[1] = tempHead.getBlockSize0();
}
char audioChannels = tempHead.getAudioChannels();
//getting modes
tempString = it->second.init;
tempHead.read((char*)tempString.c_str(),tempString.size());
trackInf[it->second.trackID].vorbisModes = tempHead.readModeDeque(audioChannels);
trackInf[it->second.trackID].hadFirst = false;
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(0);//headertype 0 = normal
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(it->second.commentHeader.size());
curSegTable.push_back(it->second.init.size());
curOggPage.setSegmentTable(curSegTable);
std::string fullHeader = it->second.commentHeader + it->second.init;
curOggPage.setPayload((char*)fullHeader.c_str(),fullHeader.size());
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
}else if (it->second.codec == "opus"){
//OpusHead page
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(19);
curOggPage.setSegmentTable(curSegTable);
//version = 1, channels = 2, preskip=0x138, origRate=48k, gain=0, channelmap=0
//we can safely hard-code these as everything is already overridden elsewhere anyway
// (except preskip - but this seems to be 0x138 for all files, and doesn't hurt much if it's wrong anyway)
curOggPage.setPayload((char*)"OpusHead\001\002\070\001\200\273\000\000\000\000\000", 19);
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
//end of OpusHead, now moving on to OpusTags
curOggPage.clear();
curOggPage.setVersion();
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
curOggPage.setGranulePosition(0);
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
curOggPage.setPageSequenceNumber(trackInf[it->second.trackID].seqNum++);
curSegTable.clear();
curSegTable.push_back(26);
curOggPage.setSegmentTable(curSegTable);
//we send an encoder value of "MistServer" and no further tags
curOggPage.setPayload((char*)"OpusTags\012\000\000\000MistServer\000\000\000\000", 26);
curOggPage.setCRCChecksum(curOggPage.calcChecksum());
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
}
}
}
void converter::readDTSCVector(JSON::Value & DTSCPart, std::string & pageBuffer){
Page retVal;
int typeFlag = 0;//flag to remember if the page has a continued segment
long long int DTSCID = DTSCPart["trackid"].asInt();
std::vector<unsigned int> curSegTable;
std::string dataBuffer;
long long unsigned int lastGran = 0;
//for (unsigned int i = 0; i < DTSCVec.size(); i++){
OGG::Page tempPage;
tempPage.setSegmentTable(curSegTable);
if (DTSCPart["data"].asString().size() >= (255-tempPage.getPageSegments())*255u){//if segment is too big
//Put page in Buffer and start next page
if (!curSegTable.empty()){
//output page
retVal.clear();
retVal.setVersion();
retVal.setHeaderType(typeFlag);//headertype 0 = normal
retVal.setGranulePosition(lastGran);
retVal.setBitstreamSerialNumber(trackInf[DTSCID].OGGSerial);
retVal.setPageSequenceNumber(trackInf[DTSCID].seqNum);
retVal.setSegmentTable(curSegTable);
retVal.setPayload((char*)dataBuffer.c_str(), dataBuffer.size());
retVal.setCRCChecksum(retVal.calcChecksum());
trackInf[DTSCID].seqNum++;
pageBuffer += std::string((char*)retVal.getPage(), retVal.getPageSize());
curSegTable.clear();
dataBuffer = "";
}
std::string remainingData = DTSCPart["data"].asString();
typeFlag = 0;
while (remainingData.size() > 255*255){
//output part of the segment
//granule -1
curSegTable.clear();
curSegTable.push_back(255*255);
retVal.clear();
retVal.setVersion();
retVal.setHeaderType(typeFlag);//normal Page
retVal.setGranulePosition(-1);
retVal.setBitstreamSerialNumber(trackInf[DTSCID].OGGSerial);
retVal.setPageSequenceNumber(trackInf[DTSCID].seqNum);
retVal.setSegmentTable(curSegTable);
retVal.setPayload((char*)remainingData.substr(0,255*255).c_str(), 255*255);
retVal.setCRCChecksum(retVal.calcChecksum());
trackInf[DTSCID].seqNum++;
pageBuffer += std::string((char*)retVal.getPage(), retVal.getPageSize());
remainingData = remainingData.substr(255*255);
typeFlag = 1;//1 = continued page
}
//output last remaining data
curSegTable.clear();
curSegTable.push_back(remainingData.size());
dataBuffer += remainingData;
}else{//build data for page
curSegTable.push_back(DTSCPart["data"].asString().size());
dataBuffer += DTSCPart["data"].asString();
}
//calculating granule position
if (trackInf[DTSCID].codec == "theora"){
if (DTSCPart["keyframe"].asBool()){
trackInf[DTSCID].lastKeyFrame += trackInf[DTSCID].sinceKeyFrame + 1;
trackInf[DTSCID].sinceKeyFrame = 0;
}else{
trackInf[DTSCID].sinceKeyFrame ++;
}
lastGran = (trackInf[DTSCID].lastKeyFrame << trackInf[DTSCID].significantValue) + trackInf[DTSCID].sinceKeyFrame;
} else if (trackInf[DTSCID].codec == "vorbis"){
Utils::bitstreamLSBF packet;
packet.append(DTSCPart["data"].asString());
//calculate amount of samples associated with that block (from ID header)
//check mode block in deque for index
int curPCMSamples = 0;
if (packet.get(1) == 0){
int tempModes = vorbis::ilog(trackInf[DTSCID].vorbisModes.size()-1);
int tempPacket = packet.get(tempModes);
int curBlockFlag = trackInf[DTSCID].vorbisModes[tempPacket].blockFlag;
curPCMSamples = (1 << trackInf[DTSCID].blockSize[curBlockFlag]);
if (trackInf[DTSCID].prevBlockFlag!= -1){
if (curBlockFlag == trackInf[DTSCID].prevBlockFlag){
curPCMSamples /= 2;
}else{
curPCMSamples -= (1 << trackInf[DTSCID].blockSize[0]) / 4 + (1 << trackInf[DTSCID].blockSize[1]) / 4;
}
}
trackInf[DTSCID].sinceKeyFrame = (1 << trackInf[DTSCID].blockSize[curBlockFlag]);
trackInf[DTSCID].prevBlockFlag = curBlockFlag;
}else{
std::cerr << "Error, Vorbis packet type !=0" << std::endl;
}
//add to granule position
trackInf[DTSCID].lastKeyFrame += curPCMSamples;
lastGran = trackInf[DTSCID].lastKeyFrame;
} else if (trackInf[DTSCID].codec == "opus"){
lastGran = (int)((DTSCPart["time"].asInt() * 48.0) / 120.0 + 0.5) * 120;
}
//}
//last parts of page put out
if (!curSegTable.empty()){
retVal.clear();
retVal.setVersion();
retVal.setHeaderType(typeFlag);//headertype 0 = normal
retVal.setGranulePosition(lastGran);
retVal.setBitstreamSerialNumber(trackInf[DTSCID].OGGSerial);
retVal.setPageSequenceNumber(trackInf[DTSCID].seqNum);
retVal.setSegmentTable(curSegTable);
retVal.setPayload((char*)dataBuffer.c_str(), dataBuffer.size());
retVal.setCRCChecksum(retVal.calcChecksum());
trackInf[DTSCID].seqNum++;
pageBuffer += std::string((char*)retVal.getPage(), retVal.getPageSize());
}
}
}