Ogg optimizes
This commit is contained in:
parent
63913f361a
commit
d8b7a3ea1c
5 changed files with 314 additions and 66 deletions
|
@ -20,6 +20,7 @@
|
||||||
#include <mist/config.h>
|
#include <mist/config.h>
|
||||||
#include <mist/stream.h>
|
#include <mist/stream.h>
|
||||||
#include <mist/timing.h>
|
#include <mist/timing.h>
|
||||||
|
#include "../converters/oggconv.h"
|
||||||
|
|
||||||
///\brief Holds everything unique to HTTP Connectors.
|
///\brief Holds everything unique to HTTP Connectors.
|
||||||
namespace Connector_HTTP {
|
namespace Connector_HTTP {
|
||||||
|
@ -36,8 +37,9 @@ namespace Connector_HTTP {
|
||||||
std::string streamname;//Will contain the name of the stream.
|
std::string streamname;//Will contain the name of the stream.
|
||||||
|
|
||||||
//OGG specific variables
|
//OGG specific variables
|
||||||
OGG::headerPages oggMeta;
|
//OGG::headerPages oggMeta;
|
||||||
OGG::Page curOggPage;
|
//OGG::Page curOggPage;
|
||||||
|
OGG::converter oggConv;
|
||||||
std::map <long long unsigned int, std::vector<JSON::Value> > DTSCBuffer;
|
std::map <long long unsigned int, std::vector<JSON::Value> > DTSCBuffer;
|
||||||
std::set <long long unsigned int> sendReady;
|
std::set <long long unsigned int> sendReady;
|
||||||
//std::map <long long unsigned int, long long unsigned int> prevGran;
|
//std::map <long long unsigned int, long long unsigned int> prevGran;
|
||||||
|
@ -141,7 +143,7 @@ namespace Connector_HTTP {
|
||||||
if (audioID != -1){
|
if (audioID != -1){
|
||||||
cmd << " " << audioID;
|
cmd << " " << audioID;
|
||||||
}
|
}
|
||||||
cmd << "\ns " << seek_sec << "\np\n";
|
cmd << "\np\n";
|
||||||
ss.SendNow(cmd.str().c_str(), cmd.str().size());
|
ss.SendNow(cmd.str().c_str(), cmd.str().size());
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
@ -159,8 +161,8 @@ namespace Connector_HTTP {
|
||||||
HTTP_S.protocol = "HTTP/1.0";
|
HTTP_S.protocol = "HTTP/1.0";
|
||||||
conn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file
|
conn.SendNow(HTTP_S.BuildResponse("200", "OK")); //no SetBody = unknown length - this is intentional, we will stream the entire file
|
||||||
//Fill in ogg header here
|
//Fill in ogg header here
|
||||||
oggMeta.readDTSCHeader(Strm.metadata);
|
oggConv.readDTSCHeader(Strm.metadata);
|
||||||
conn.SendNow((char*)oggMeta.parsedPages.c_str(), oggMeta.parsedPages.size());
|
conn.SendNow((char*)oggConv.parsedPages.c_str(), oggConv.parsedPages.size());
|
||||||
progressive_has_sent_header = true;
|
progressive_has_sent_header = true;
|
||||||
//setting sendReady to not ready
|
//setting sendReady to not ready
|
||||||
sendReady.clear();
|
sendReady.clear();
|
||||||
|
@ -168,20 +170,11 @@ namespace Connector_HTTP {
|
||||||
//parse DTSC to Ogg here
|
//parse DTSC to Ogg here
|
||||||
if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){
|
if (Strm.lastType() == DTSC::AUDIO || Strm.lastType() == DTSC::VIDEO){
|
||||||
currID = Strm.getPacket()["trackid"].asInt();
|
currID = Strm.getPacket()["trackid"].asInt();
|
||||||
currGran = Strm.getPacket()["granule"].asInt();
|
|
||||||
if (DTSCBuffer.count(currID) && !DTSCBuffer[currID].empty()){
|
|
||||||
prevGran = DTSCBuffer[currID][0]["granule"].asInt();
|
|
||||||
}else{
|
|
||||||
prevGran = 0;
|
|
||||||
}
|
|
||||||
if ((prevGran != 0 && (prevGran == -1 || currGran != prevGran)) ){
|
|
||||||
curOggPage.readDTSCVector(DTSCBuffer[currID], oggMeta.DTSCID2OGGSerial[currID], oggMeta.DTSCID2seqNum[currID]);
|
|
||||||
conn.SendNow((char*)curOggPage.getPage(), curOggPage.getPageSize());
|
|
||||||
DTSCBuffer[currID].clear();
|
|
||||||
sendReady.insert(currID);
|
|
||||||
oggMeta.DTSCID2seqNum[currID]++;
|
|
||||||
}
|
|
||||||
DTSCBuffer[currID].push_back(Strm.getPacket());
|
DTSCBuffer[currID].push_back(Strm.getPacket());
|
||||||
|
std::string tmpString = oggConv.readDTSCVector(DTSCBuffer[currID]);
|
||||||
|
conn.SendNow((char*)tmpString.c_str(), tmpString.size());
|
||||||
|
DTSCBuffer[currID].clear();
|
||||||
|
sendReady.insert(currID);
|
||||||
}
|
}
|
||||||
if (Strm.lastType() == DTSC::PAUSEMARK){
|
if (Strm.lastType() == DTSC::PAUSEMARK){
|
||||||
conn.close();
|
conn.close();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include<vector>
|
#include<vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "oggconv.h"
|
||||||
|
|
||||||
#include <mist/timing.h>
|
#include <mist/timing.h>
|
||||||
#include <mist/dtsc.h>
|
#include <mist/dtsc.h>
|
||||||
|
@ -14,20 +15,13 @@
|
||||||
namespace Converters{
|
namespace Converters{
|
||||||
int DTSC2OGG(Util::Config & conf){
|
int DTSC2OGG(Util::Config & conf){
|
||||||
DTSC::File DTSCFile(conf.getString("filename"));
|
DTSC::File DTSCFile(conf.getString("filename"));
|
||||||
//JSON::Value meta = DTSCFile.getMeta();
|
|
||||||
srand (Util::getMS());//randomising with milliseconds from boot
|
srand (Util::getMS());//randomising with milliseconds from boot
|
||||||
std::vector<unsigned int> curSegTable;
|
std::vector<unsigned int> curSegTable;
|
||||||
OGG::headerPages oggMeta;
|
char* curNewPayload;
|
||||||
|
OGG::converter oggMeta;
|
||||||
//Creating ID headers for theora and vorbis
|
//Creating ID headers for theora and vorbis
|
||||||
DTSC::readOnlyMeta fileMeta = DTSCFile.getMeta();
|
DTSC::readOnlyMeta fileMeta = DTSCFile.getMeta();
|
||||||
DTSC::Meta giveMeta;
|
DTSC::Meta giveMeta(fileMeta);
|
||||||
for ( std::map<int,DTSC::readOnlyTrack>::iterator it = fileMeta.tracks.begin(); it != fileMeta.tracks.end(); it ++) {
|
|
||||||
std::cerr << "TrackID: " << it->first << std::endl;
|
|
||||||
giveMeta.tracks[it->first].trackID = fileMeta.tracks[it->first].trackID;
|
|
||||||
giveMeta.tracks[it->first].idHeader = fileMeta.tracks[it->first].idHeader;
|
|
||||||
giveMeta.tracks[it->first].init = fileMeta.tracks[it->first].init;
|
|
||||||
giveMeta.tracks[it->first].commentHeader = fileMeta.tracks[it->first].commentHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
oggMeta.readDTSCHeader(giveMeta);
|
oggMeta.readDTSCHeader(giveMeta);
|
||||||
std::cout << oggMeta.parsedPages;//outputting header pages
|
std::cout << oggMeta.parsedPages;//outputting header pages
|
||||||
|
@ -49,28 +43,20 @@ namespace Converters{
|
||||||
}else{
|
}else{
|
||||||
prevGran = 0;
|
prevGran = 0;
|
||||||
}
|
}
|
||||||
if (prevGran != 0 && (currGran != prevGran)){
|
if (!DTSCBuffer[currID].empty()){
|
||||||
curOggPage.readDTSCVector(DTSCBuffer[currID], oggMeta.DTSCID2OGGSerial[currID], oggMeta.DTSCID2seqNum[currID]);
|
std::cout << oggMeta.readDTSCVector(DTSCBuffer[currID]);
|
||||||
std::cout << std::string((char*)curOggPage.getPage(), curOggPage.getPageSize());
|
|
||||||
DTSCBuffer[currID].clear();
|
DTSCBuffer[currID].clear();
|
||||||
oggMeta.DTSCID2seqNum[currID]++;
|
|
||||||
}
|
}
|
||||||
DTSCBuffer[currID].push_back(DTSCFile.getJSON());
|
DTSCBuffer[currID].push_back(DTSCFile.getJSON());
|
||||||
|
|
||||||
DTSCFile.parseNext();
|
DTSCFile.parseNext();
|
||||||
}
|
}
|
||||||
//outputting end of stream pages
|
//outputting end of stream pages
|
||||||
for (
|
for (std::map< long long int, std::vector<JSON::Value> >::iterator it = DTSCBuffer.begin(); it != DTSCBuffer.end(); it++){
|
||||||
std::map< long long int, std::vector<JSON::Value> >::iterator it = DTSCBuffer.begin();
|
|
||||||
it != DTSCBuffer.end();
|
|
||||||
it++
|
|
||||||
){
|
|
||||||
if (!DTSCBuffer[it->first].empty() && DTSCBuffer[it->first][0]["data"].asString() != ""){
|
if (!DTSCBuffer[it->first].empty() && DTSCBuffer[it->first][0]["data"].asString() != ""){
|
||||||
curOggPage.readDTSCVector(DTSCBuffer[it->first], oggMeta.DTSCID2OGGSerial[it->first], oggMeta.DTSCID2seqNum[it->first]);
|
std::cout << oggMeta.readDTSCVector(DTSCBuffer[it->first]);
|
||||||
std::cout << std::string((char*)curOggPage.getPage(), curOggPage.getPageSize());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <mist/vorbis.h>
|
#include <mist/vorbis.h>
|
||||||
#include <mist/config.h>
|
#include <mist/config.h>
|
||||||
#include <mist/json.h>
|
#include <mist/json.h>
|
||||||
|
#include <mist/bitstream.h>
|
||||||
|
|
||||||
namespace Converters{
|
namespace Converters{
|
||||||
enum codecType {THEORA, VORBIS};
|
enum codecType {THEORA, VORBIS};
|
||||||
|
@ -19,11 +20,18 @@ namespace Converters{
|
||||||
oggTrack() : lastTime(0), parsedHeaders(false) { }
|
oggTrack() : lastTime(0), parsedHeaders(false) { }
|
||||||
codecType codec;
|
codecType codec;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::string contBuffer;//buffer for continuing pages
|
||||||
long long unsigned int dtscID;
|
long long unsigned int dtscID;
|
||||||
double lastTime;
|
double lastTime;
|
||||||
|
long long unsigned int lastGran;
|
||||||
bool parsedHeaders;
|
bool parsedHeaders;
|
||||||
//Codec specific elements
|
//Codec specific elements
|
||||||
|
//theora
|
||||||
theora::header idHeader;//needed to determine keyframe
|
theora::header idHeader;//needed to determine keyframe
|
||||||
|
//vorbis
|
||||||
|
std::deque<vorbis::mode> vModes;
|
||||||
|
char channels;
|
||||||
|
long long unsigned int blockSize[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
int OGG2DTSC(){
|
int OGG2DTSC(){
|
||||||
|
@ -64,7 +72,7 @@ namespace Converters{
|
||||||
trackData[sNum].codec = VORBIS;
|
trackData[sNum].codec = VORBIS;
|
||||||
vorbis::header tempHead;
|
vorbis::header tempHead;
|
||||||
tempHead.read(oggPage.getFullPayload(), oggPage.getPayloadSize());
|
tempHead.read(oggPage.getFullPayload(), oggPage.getPayloadSize());
|
||||||
mspfv = ntohl(tempHead.getAudioSampleRate()) / 1000;
|
mspfv = (double)1000 / ntohl(tempHead.getAudioSampleRate());
|
||||||
}else{
|
}else{
|
||||||
std::cerr << "Unknown Codec, " << std::string(oggPage.getFullPayload()+1, 6)<<" skipping" << std::endl;
|
std::cerr << "Unknown Codec, " << std::string(oggPage.getFullPayload()+1, 6)<<" skipping" << std::endl;
|
||||||
continue;
|
continue;
|
||||||
|
@ -79,34 +87,61 @@ namespace Converters{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (std::deque<unsigned int>::iterator it = oggPage.getSegmentTableDeque().begin(); it != oggPage.getSegmentTableDeque().end(); it++){
|
for (std::deque<unsigned int>::iterator it = oggPage.getSegmentTableDeque().begin(); it != oggPage.getSegmentTableDeque().end(); it++){
|
||||||
if (trackData[sNum].parsedHeaders){
|
if (trackData[sNum].parsedHeaders){
|
||||||
//output DTSC packet
|
//if we are dealing with the last segment which is a part of a later continued segment
|
||||||
DTSCOut.null();//clearing DTSC buffer
|
if (it == (oggPage.getSegmentTableDeque().end()-1) && oggPage.getPageSegments() == 255 && oggPage.getSegmentTable()[254] == 255 ){
|
||||||
DTSCOut["trackid"] = (long long)trackData[sNum].dtscID;
|
//put in buffer
|
||||||
long long unsigned int temp = oggPage.getGranulePosition();
|
trackData[sNum].contBuffer += std::string(oggPage.getFullPayload()+offset, (*it));
|
||||||
DTSCOut["granule"] = (long long)temp;
|
|
||||||
DTSCOut["time"] = (long long)trackData[sNum].lastTime;
|
|
||||||
if (trackData[sNum].codec == THEORA){
|
|
||||||
trackData[sNum].lastTime += (mspft / 4);
|
|
||||||
}else{
|
}else{
|
||||||
trackData[sNum].lastTime += (mspfv / 16);
|
//output DTSC packet
|
||||||
}
|
DTSCOut.null();//clearing DTSC buffer
|
||||||
DTSCOut["data"] = std::string(oggPage.getFullPayload()+offset, (*it)); //segment content put in JSON
|
DTSCOut["trackid"] = (long long)trackData[sNum].dtscID;
|
||||||
if (trackData[sNum].codec == THEORA){
|
long long unsigned int temp = oggPage.getGranulePosition();
|
||||||
if (trackData[sNum].idHeader.parseGranuleLower(temp) == 0){ //granule mask equals zero when on keyframe
|
DTSCOut["time"] = (long long)trackData[sNum].lastTime;
|
||||||
DTSCOut["keyframe"] = 1;
|
if (trackData[sNum].contBuffer != ""){
|
||||||
|
//if a big segment is ending on this page, output buffer
|
||||||
|
DTSCOut["data"] = trackData[sNum].contBuffer + std::string(oggPage.getFullPayload()+offset, (*it));
|
||||||
|
DTSCOut["comment"] = "Using buffer";
|
||||||
|
trackData[sNum].contBuffer = "";
|
||||||
}else{
|
}else{
|
||||||
DTSCOut["interframe"] = 1;
|
DTSCOut["data"] = std::string(oggPage.getFullPayload()+offset, (*it)); //segment content put in JSON
|
||||||
}
|
}
|
||||||
|
DTSCOut["time"] = (long long)trackData[sNum].lastTime;
|
||||||
|
if (trackData[sNum].codec == THEORA){
|
||||||
|
trackData[sNum].lastTime += mspft;
|
||||||
|
}else{
|
||||||
|
//Getting current blockSize
|
||||||
|
unsigned int blockSize = 0;
|
||||||
|
Utils::bitstreamLSBF packet;
|
||||||
|
packet.append(DTSCOut["data"].asString());
|
||||||
|
if (packet.get(1) == 0){
|
||||||
|
blockSize = trackData[sNum].blockSize[trackData[sNum].vModes[packet.get(vorbis::ilog(trackData[sNum].vModes.size()-1))].blockFlag];
|
||||||
|
}else{
|
||||||
|
std::cerr << "Warning! packet type != 0" << std::endl;
|
||||||
|
}
|
||||||
|
trackData[sNum].lastTime += mspfv * (blockSize/trackData[sNum].channels);
|
||||||
|
}
|
||||||
|
if (trackData[sNum].codec == THEORA){//marking keyframes
|
||||||
|
if (it == (oggPage.getSegmentTableDeque().end() - 1)){
|
||||||
|
//if we are in the vicinity of a new keyframe
|
||||||
|
if (trackData[sNum].idHeader.parseGranuleUpper(trackData[sNum].lastGran) != trackData[sNum].idHeader.parseGranuleUpper(temp)){
|
||||||
|
//try to mark right
|
||||||
|
long long unsigned int temper = trackData[sNum].idHeader.parseGranuleUpper(temp) - trackData[sNum].idHeader.parseGranuleUpper(trackData[sNum].lastGran);
|
||||||
|
DTSCOut["keyframe"] = 1;
|
||||||
|
trackData[sNum].lastGran = temp;
|
||||||
|
}else{
|
||||||
|
DTSCOut["interframe"] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ending packet
|
||||||
|
if (oggPage.typeContinue()){//Continuing page
|
||||||
|
DTSCOut["OggCont"] = 1;
|
||||||
|
}
|
||||||
|
if (oggPage.typeEOS()){//ending page of ogg stream
|
||||||
|
DTSCOut["OggEOS"] = 1;
|
||||||
|
}
|
||||||
|
std::cout << DTSCOut.toNetPacked();
|
||||||
}
|
}
|
||||||
// Ending packet
|
|
||||||
if (oggPage.typeContinue()){//Continuing page
|
|
||||||
DTSCOut["OggCont"] = 1;
|
|
||||||
}
|
|
||||||
if (oggPage.typeEOS()){//ending page
|
|
||||||
DTSCOut["OggEOS"] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << DTSCOut.toNetPacked();
|
|
||||||
}else{//if we ouput a header:
|
}else{//if we ouput a header:
|
||||||
//switch on codec
|
//switch on codec
|
||||||
switch(trackData[sNum].codec){
|
switch(trackData[sNum].codec){
|
||||||
|
@ -132,6 +167,7 @@ namespace Converters{
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["init"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
DTSCHeader["tracks"][trackData[sNum].name]["init"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||||
headerSeen --;
|
headerSeen --;
|
||||||
trackData[sNum].parsedHeaders = true;
|
trackData[sNum].parsedHeaders = true;
|
||||||
|
trackData[sNum].lastGran = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,6 +181,9 @@ namespace Converters{
|
||||||
case 1:{
|
case 1:{
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["channels"] = (long long)vHead.getAudioChannels();
|
DTSCHeader["tracks"][trackData[sNum].name]["channels"] = (long long)vHead.getAudioChannels();
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["idheader"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
DTSCHeader["tracks"][trackData[sNum].name]["idheader"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||||
|
trackData[sNum].channels = vHead.getAudioChannels();
|
||||||
|
trackData[sNum].blockSize[0] = 1 << vHead.getBlockSize0();
|
||||||
|
trackData[sNum].blockSize[1] = 1 << vHead.getBlockSize1();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3:{
|
case 3:{
|
||||||
|
@ -156,6 +195,8 @@ namespace Converters{
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["trackid"] = (long long)trackData[sNum].dtscID;
|
DTSCHeader["tracks"][trackData[sNum].name]["trackid"] = (long long)trackData[sNum].dtscID;
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["type"] = "audio";
|
DTSCHeader["tracks"][trackData[sNum].name]["type"] = "audio";
|
||||||
DTSCHeader["tracks"][trackData[sNum].name]["init"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
DTSCHeader["tracks"][trackData[sNum].name]["init"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||||
|
//saving modes into deque
|
||||||
|
trackData[sNum].vModes = vHead.readModeDeque(trackData[sNum].channels);
|
||||||
headerSeen --;
|
headerSeen --;
|
||||||
trackData[sNum].parsedHeaders = true;
|
trackData[sNum].parsedHeaders = true;
|
||||||
break;
|
break;
|
||||||
|
|
199
src/converters/oggconv.cpp
Normal file
199
src/converters/oggconv.cpp
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
#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();
|
||||||
|
//Creating ID headers for theora and vorbis
|
||||||
|
for ( std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||||
|
curOggPage.clear();
|
||||||
|
curOggPage.setVersion();
|
||||||
|
curOggPage.setHeaderType(2);//headertype 2 = Begin of Stream
|
||||||
|
curOggPage.setGranulePosition(0);
|
||||||
|
trackInf[it->second.trackID].OGGSerial = rand() % 0xFFFFFFFE +1; //initialising on a random not 0 number
|
||||||
|
curOggPage.setBitstreamSerialNumber(trackInf[it->second.trackID].OGGSerial);
|
||||||
|
trackInf[it->second.trackID].seqNum = 0;
|
||||||
|
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());
|
||||||
|
//pages.push_back(curOggPage);
|
||||||
|
parsedPages += std::string(curOggPage.getPage(), curOggPage.getPageSize());
|
||||||
|
trackInf[it->second.trackID].codec = it->second.codec;
|
||||||
|
if (it->second.codec == "theora"){
|
||||||
|
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();
|
||||||
|
}else if (it->second.codec == "vorbis"){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Creating remaining headers for theora and vorbis
|
||||||
|
//for tracks in header
|
||||||
|
//create standard page with comment (empty) en setup header(init)
|
||||||
|
for ( std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it ++) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string converter::readDTSCVector(std::vector <JSON::Value> DTSCVec){
|
||||||
|
Page retVal;
|
||||||
|
int typeFlag = 0;//flag to remember if the page has a continued segment
|
||||||
|
std::string pageBuffer = "";
|
||||||
|
long long int DTSCID = DTSCVec[0]["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 (DTSCVec[i]["data"].asString().size() >= (255-tempPage.getPageSegments())*255){//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 = DTSCVec[i]["data"].asString();
|
||||||
|
bool firstLoop;
|
||||||
|
typeFlag = 0;
|
||||||
|
while (remainingData.size() > 255*255){
|
||||||
|
//output part of the segment
|
||||||
|
//granule -1
|
||||||
|
curSegTable.clear();
|
||||||
|
curSegTable.push_back(255*255);///\TODO optimise this
|
||||||
|
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(DTSCVec[i]["data"].asString().size());
|
||||||
|
dataBuffer += DTSCVec[i]["data"].asString();
|
||||||
|
}
|
||||||
|
//lastGran = calcGranule(DTSCID, DTSCVec[i]["keyframe"].asBool());
|
||||||
|
//calculating granule position
|
||||||
|
if (trackInf[DTSCID].codec == "theora"){
|
||||||
|
if (DTSCVec[i]["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"){
|
||||||
|
//decode DTSCVec[i]["data"].asString() for mode index
|
||||||
|
Utils::bitstreamLSBF packet;
|
||||||
|
packet.append(DTSCVec[i]["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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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());
|
||||||
|
}
|
||||||
|
return pageBuffer;
|
||||||
|
}
|
||||||
|
}
|
29
src/converters/oggconv.h
Normal file
29
src/converters/oggconv.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <mist/ogg.h>
|
||||||
|
|
||||||
|
namespace OGG {
|
||||||
|
struct trackStats{
|
||||||
|
unsigned int OGGSerial;
|
||||||
|
unsigned int seqNum;
|
||||||
|
std::string codec;
|
||||||
|
//theora vars
|
||||||
|
unsigned int lastKeyFrame;
|
||||||
|
unsigned int sinceKeyFrame;
|
||||||
|
unsigned int significantValue;//KFGShift for theora and other video;
|
||||||
|
int prevBlockFlag;
|
||||||
|
//vorbis vars
|
||||||
|
bool hadFirst;
|
||||||
|
std::deque<vorbis::mode> vorbisModes;//modes for vorbis
|
||||||
|
char blockSize[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
class converter{
|
||||||
|
public:
|
||||||
|
void readDTSCHeader(DTSC::Meta & meta);
|
||||||
|
std::string readDTSCVector(std::vector <JSON::Value> DTSCVec);
|
||||||
|
std::string parsedPages;
|
||||||
|
private:
|
||||||
|
std::map <long long unsigned int, trackStats> trackInf;
|
||||||
|
//long long unsigned int calcGranule(long long unsigned int trackID, bool keyFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue