Removed outdated converters from codebase.
This commit is contained in:
parent
87583dae49
commit
43d20268ac
11 changed files with 0 additions and 1230 deletions
|
@ -1,80 +0,0 @@
|
|||
/// \file dtsc2flv.cpp
|
||||
/// Contains the code that will transform any valid DTSC input into valid FLVs.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <mist/flv_tag.h> //FLV support
|
||||
#include <mist/dtsc.h> //DTSC support
|
||||
#include <mist/amf.h> //AMF support
|
||||
#include <mist/config.h>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
|
||||
///\brief Converts DTSC from stdin to FLV on stdout.
|
||||
///\return The return code for the converter.
|
||||
int DTSC2FLV(){
|
||||
FLV::Tag FLV_out; // Temporary storage for outgoing FLV data.
|
||||
DTSC::Stream Strm;
|
||||
std::string inBuffer;
|
||||
char charBuffer[1024 * 10];
|
||||
unsigned int charCount;
|
||||
bool doneheader = false;
|
||||
int videoID = -1, audioID = -1;
|
||||
|
||||
while (std::cin.good()){
|
||||
if (Strm.parsePacket(inBuffer)){
|
||||
if ( !doneheader){
|
||||
//find first audio and video tracks
|
||||
for (std::map<int,DTSC::Track>::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){
|
||||
if (videoID == -1 && it->second.type == "video"){
|
||||
videoID = it->first;
|
||||
}
|
||||
if (audioID == -1 && it->second.type == "audio"){
|
||||
audioID = it->first;
|
||||
}
|
||||
}
|
||||
|
||||
doneheader = true;
|
||||
std::cout.write(FLV::Header, 13);
|
||||
FLV_out.DTSCMetaInit(Strm, Strm.metadata.tracks[videoID], Strm.metadata.tracks[audioID]);
|
||||
std::cout.write(FLV_out.data, FLV_out.len);
|
||||
if (videoID != -1){
|
||||
FLV_out.DTSCVideoInit(Strm.metadata.tracks[videoID]);
|
||||
std::cout.write(FLV_out.data, FLV_out.len);
|
||||
}
|
||||
if (audioID != -1){
|
||||
FLV_out.DTSCAudioInit(Strm.metadata.tracks[audioID]);
|
||||
std::cout.write(FLV_out.data, FLV_out.len);
|
||||
}
|
||||
}
|
||||
if (FLV_out.DTSCLoader(Strm)){
|
||||
std::cout.write(FLV_out.data, FLV_out.len);
|
||||
}
|
||||
}else{
|
||||
std::cin.read(charBuffer, 1024 * 10);
|
||||
charCount = std::cin.gcount();
|
||||
inBuffer.append(charBuffer, charCount);
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "Done!" << std::endl;
|
||||
|
||||
return 0;
|
||||
} //FLV2DTSC
|
||||
|
||||
} //Converter namespace
|
||||
|
||||
/// Entry point for DTSC2FLV, simply calls Converters::DTSC2FLV().
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::DTSC2FLV();
|
||||
} //main
|
|
@ -1,47 +0,0 @@
|
|||
#include<iostream>
|
||||
#include<vector>
|
||||
#include <queue>
|
||||
#include <stdlib.h>
|
||||
#include "oggconv.h"
|
||||
|
||||
#include <mist/timing.h>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/ogg.h>
|
||||
#include <mist/theora.h>
|
||||
#include <mist/vorbis.h>
|
||||
#include <mist/config.h>
|
||||
#include <mist/json.h>
|
||||
|
||||
namespace Converters{
|
||||
int DTSC2OGG(Util::Config & conf){
|
||||
DTSC::File DTSCFile(conf.getString("filename"));
|
||||
srand (Util::getMS());//randomising with milliseconds from boot
|
||||
std::vector<unsigned int> curSegTable;
|
||||
OGG::converter oggMeta;
|
||||
//Creating ID headers for theora and vorbis
|
||||
DTSC::readOnlyMeta fileMeta = DTSCFile.getMeta();
|
||||
DTSC::Meta giveMeta(fileMeta);
|
||||
|
||||
oggMeta.readDTSCHeader(giveMeta);
|
||||
std::cout << oggMeta.parsedPages;//outputting header pages
|
||||
|
||||
//create DTSC in OGG pages
|
||||
DTSCFile.parseNext();
|
||||
std::map< long long int, std::vector<JSON::Value> > DTSCBuffer;
|
||||
OGG::Page curOggPage;
|
||||
while(DTSCFile.getJSON()){
|
||||
std::string tmpString;
|
||||
oggMeta.readDTSCVector(DTSCFile.getJSON(), tmpString);
|
||||
std::cout << tmpString;
|
||||
DTSCFile.parseNext();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("filename", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the DTSC file to analyse.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::DTSC2OGG(conf);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/// \file dtscfix.cpp
|
||||
/// Contains the code that will attempt to fix the metadata contained in an DTSC file.
|
||||
|
||||
#include <string>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/json.h>
|
||||
#include <mist/config.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
///\brief Reads a DTSC file and attempts to fix the metadata in it.
|
||||
///\param conf The current configuration of the program.
|
||||
///\return The return code for the fixed program.
|
||||
int DTSCFix(Util::Config & conf){
|
||||
DTSC::File F(conf.getString("filename"));
|
||||
|
||||
int curIndex = 1;
|
||||
|
||||
F.parseNext();
|
||||
std::string tmp;
|
||||
while (F.getPacket()){
|
||||
std::cout << curIndex++ << std::endl;
|
||||
long long unsigned int time = F.getPacket().getTime();
|
||||
std::cout << std::setfill('0') << std::setw(2) << (time / 3600000) << ":";
|
||||
std::cout << std::setfill('0') << std::setw(2) << ((time % 3600000) / 60000) << ":";
|
||||
std::cout << std::setfill('0') << std::setw(2) << (((time % 3600000) % 60000) / 1000) << ",";
|
||||
std::cout << std::setfill('0') << std::setw(3) << time % 1000 << " --> ";
|
||||
time += F.getPacket().getInt("duration");
|
||||
std::cout << std::setfill('0') << std::setw(2) << (time / 3600000) << ":";
|
||||
std::cout << std::setfill('0') << std::setw(2) << ((time % 3600000) / 60000) << ":";
|
||||
std::cout << std::setfill('0') << std::setw(2) << (((time % 3600000) % 60000) / 1000) << ",";
|
||||
std::cout << std::setfill('0') << std::setw(3) << time % 1000 << std::endl;
|
||||
F.getPacket().getString("data", tmp);
|
||||
std::cout << tmp << std::endl;
|
||||
F.parseNext();
|
||||
}
|
||||
return 0;
|
||||
|
||||
} //DTSCFix
|
||||
|
||||
}
|
||||
|
||||
/// Entry point for DTSCFix, simply calls Converters::DTSCFix().
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("filename", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the file to attempt to fix.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::DTSCFix(conf);
|
||||
} //main
|
|
@ -1,148 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <mist/ts_packet.h> //TS support
|
||||
#include <mist/dtsc.h> //DTSC support
|
||||
#include <mist/mp4.h> //For initdata conversion
|
||||
#include <mist/mp4_generic.h> //For initdata conversion
|
||||
#include <mist/config.h>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
///\brief Converts DTSC from stdin to TS on stdout.
|
||||
///\return The return code for the converter.
|
||||
int DTSC2TS(){
|
||||
char charBuffer[1024 * 10];
|
||||
unsigned int charCount;
|
||||
std::string StrData;
|
||||
TS::Packet PackData;
|
||||
DTSC::Stream Strm;
|
||||
int PacketNumber = 0;
|
||||
long long unsigned int TimeStamp = 0;
|
||||
unsigned int ThisNaluSize;
|
||||
char VideoCounter = 0;
|
||||
char AudioCounter = 0;
|
||||
bool IsKeyFrame = false;
|
||||
MP4::AVCC avccbox;
|
||||
bool haveAvcc = false;
|
||||
std::stringstream TSBuf;
|
||||
int videoID = -1;
|
||||
int audioID = -1;
|
||||
|
||||
|
||||
while (std::cin.good()){
|
||||
if (Strm.parsePacket(StrData)){
|
||||
if ((videoID == -1 || audioID == -1) && Strm.metadata){
|
||||
for (std::map<int,DTSC::Track>::iterator it = Strm.metadata.tracks.begin(); it != Strm.metadata.tracks.end(); it++){
|
||||
if (videoID == -1 && it->second.type == "video"){
|
||||
videoID = it->first;
|
||||
}
|
||||
if (audioID == -1 && it->second.type == "audio"){
|
||||
audioID = it->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Strm.lastType() == DTSC::PAUSEMARK){
|
||||
TSBuf.flush();
|
||||
if (TSBuf.str().size()){
|
||||
std::cout << TSBuf.str();
|
||||
TSBuf.str("");
|
||||
PacketNumber = 0;
|
||||
}
|
||||
TSBuf.str("");
|
||||
}
|
||||
if ( !haveAvcc){
|
||||
avccbox.setPayload(Strm.metadata.tracks[videoID].init);
|
||||
haveAvcc = true;
|
||||
}
|
||||
if (Strm.lastType() == DTSC::VIDEO || Strm.lastType() == DTSC::AUDIO){
|
||||
Socket::Buffer ToPack;
|
||||
//write PAT and PMT TS packets
|
||||
if (PacketNumber == 0){
|
||||
PackData.DefaultPAT();
|
||||
TSBuf.write(PackData.ToString(), 188);
|
||||
PackData.DefaultPMT();
|
||||
TSBuf.write(PackData.ToString(), 188);
|
||||
PacketNumber += 2;
|
||||
}
|
||||
|
||||
int PIDno = 0;
|
||||
char * ContCounter = 0;
|
||||
if (Strm.lastType() == DTSC::VIDEO){
|
||||
IsKeyFrame = Strm.getPacket().isMember("keyframe");
|
||||
if (IsKeyFrame){
|
||||
TimeStamp = (Strm.getPacket()["time"].asInt() * 27000);
|
||||
}
|
||||
ToPack.append(avccbox.asAnnexB());
|
||||
while (Strm.lastData().size()){
|
||||
ThisNaluSize = (Strm.lastData()[0] << 24) + (Strm.lastData()[1] << 16) + (Strm.lastData()[2] << 8) + Strm.lastData()[3];
|
||||
Strm.lastData().replace(0, 4, "\000\000\000\001", 4);
|
||||
if (ThisNaluSize + 4 == Strm.lastData().size()){
|
||||
ToPack.append(Strm.lastData());
|
||||
break;
|
||||
}else{
|
||||
ToPack.append(Strm.lastData().c_str(), ThisNaluSize + 4);
|
||||
Strm.lastData().erase(0, ThisNaluSize + 4);
|
||||
}
|
||||
}
|
||||
ToPack.prepend(TS::Packet::getPESVideoLeadIn(0ul, Strm.getPacket()["time"].asInt() * 90));
|
||||
PIDno = 0x100;
|
||||
ContCounter = &VideoCounter;
|
||||
}else if (Strm.lastType() == DTSC::AUDIO){
|
||||
ToPack.append(TS::GetAudioHeader(Strm.lastData().size(), Strm.metadata.tracks[audioID].init));
|
||||
ToPack.append(Strm.lastData());
|
||||
ToPack.prepend(TS::Packet::getPESAudioLeadIn(ToPack.bytes(1073741824ul), Strm.getPacket()["time"].asInt() * 90));
|
||||
PIDno = 0x101;
|
||||
ContCounter = &AudioCounter;
|
||||
}
|
||||
|
||||
//initial packet
|
||||
PackData.Clear();
|
||||
PackData.PID(PIDno);
|
||||
PackData.ContinuityCounter(( *ContCounter)++);
|
||||
PackData.UnitStart(1);
|
||||
if (IsKeyFrame){
|
||||
PackData.RandomAccess(1);
|
||||
PackData.PCR(TimeStamp);
|
||||
}
|
||||
unsigned int toSend = PackData.AddStuffing(ToPack.bytes(184));
|
||||
std::string gonnaSend = ToPack.remove(toSend);
|
||||
PackData.FillFree(gonnaSend);
|
||||
TSBuf.write(PackData.ToString(), 188);
|
||||
PacketNumber++;
|
||||
|
||||
//rest of packets
|
||||
while (ToPack.size()){
|
||||
PackData.Clear();
|
||||
PackData.PID(PIDno);
|
||||
PackData.ContinuityCounter(( *ContCounter)++);
|
||||
toSend = PackData.AddStuffing(ToPack.bytes(184));
|
||||
gonnaSend = ToPack.remove(toSend);
|
||||
PackData.FillFree(gonnaSend);
|
||||
TSBuf.write(PackData.ToString(), 188);
|
||||
PacketNumber++;
|
||||
}
|
||||
|
||||
}
|
||||
}else{
|
||||
std::cin.read(charBuffer, 1024 * 10);
|
||||
charCount = std::cin.gcount();
|
||||
StrData.append(charBuffer, charCount);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
///\brief Entry point for DTSC2TS, simply calls Converters::DTSC2TS().
|
||||
int main(int argc, char* argv[]){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::DTSC2TS();
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/// \file dtscfix.cpp
|
||||
/// Contains the code that will attempt to fix the metadata contained in an DTSC file.
|
||||
|
||||
#include <string>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/json.h>
|
||||
#include <mist/config.h>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
///\brief Reads a DTSC file and attempts to fix the metadata in it.
|
||||
///\param conf The current configuration of the program.
|
||||
///\return The return code for the fixed program.
|
||||
int DTSCFix(Util::Config & conf){
|
||||
DTSC::File F(conf.getString("filename"));
|
||||
F.seek_bpos(0);
|
||||
F.parseNext();
|
||||
JSON::Value oriheader = F.getPacket().toJSON();
|
||||
DTSC::Meta meta(F.getMeta());
|
||||
|
||||
if (meta.isFixed() && !conf.getBool("force")){
|
||||
std::cerr << "This file was already fixed or doesn't need fixing - cancelling." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
meta.reset();
|
||||
int bPos = F.getBytePos();
|
||||
F.parseNext();
|
||||
JSON::Value newPack;
|
||||
while ( F.getPacket()){
|
||||
newPack = F.getPacket().toJSON();
|
||||
newPack["bpos"] = bPos;
|
||||
meta.update(newPack);
|
||||
bPos = F.getBytePos();
|
||||
F.parseNext();
|
||||
}
|
||||
int temp = 0;
|
||||
for (std::map<int,DTSC::Track>::iterator it = meta.tracks.begin(); it != meta.tracks.end(); it++){
|
||||
temp++;
|
||||
if (it->second.fragments.size()){
|
||||
it->second.fragments.rbegin()->setDuration(it->second.fragments.rbegin()->getDuration() - it->second.lastms);
|
||||
}
|
||||
}
|
||||
|
||||
//append the revised header
|
||||
std::string loader = meta.toJSON().toPacked();
|
||||
oriheader["moreheader"] = F.addHeader(loader);
|
||||
if ( !oriheader["moreheader"].asInt()){
|
||||
std::cerr << "Failure appending new header." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
//re-write the original header with information about the location of the new one
|
||||
loader = oriheader.toPacked();
|
||||
if (F.writeHeader(loader)){
|
||||
return 0;
|
||||
}else{
|
||||
std::cerr << "Failure rewriting header." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
} //DTSCFix
|
||||
}
|
||||
|
||||
/// Entry point for DTSCFix, simply calls Converters::DTSCFix().
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("filename", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the file to attempt to fix.\"}"));
|
||||
conf.addOption("force", JSON::fromString("{\"short\":\"f\", \"long\":\"force\", \"default\":0, \"help\":\"Force fixing.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::DTSCFix(conf);
|
||||
} //main
|
|
@ -1,157 +0,0 @@
|
|||
/// \file dtscmerge.cpp
|
||||
/// Contains the code that will attempt to merge multiple files into a single DTSC file.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mist/config.h>
|
||||
#include <mist/dtsc.h>
|
||||
|
||||
namespace Converters {
|
||||
int getNextFree( std::map<std::string,std::map<int,int> > mapping ){
|
||||
int result = 1;
|
||||
std::map<std::string,std::map<int,int> >::iterator mapIt;
|
||||
std::map<int,int>::iterator subIt;
|
||||
if (mapping.size()){
|
||||
for (mapIt = mapping.begin(); mapIt != mapping.end(); mapIt++){
|
||||
if (mapIt->second.size()){
|
||||
for (subIt = mapIt->second.begin(); subIt != mapIt->second.end(); subIt++){
|
||||
if (subIt->second >= result){
|
||||
result = subIt->second + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct keyframeInfo{
|
||||
std::string fileName;
|
||||
int trackID;
|
||||
int keyTime;
|
||||
int keyBPos;
|
||||
int keyNum;
|
||||
int keyLen;
|
||||
int endBPos;
|
||||
};//keyframeInfo struct
|
||||
|
||||
int DTSCMerge(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("output", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the output file.\"}"));
|
||||
conf.addOption("input", JSON::fromString("{\"arg_num\":2, \"arg\":\"string\", \"help\":\"Filename of the first input file.\"}"));
|
||||
conf.addOption("[additional_inputs ...]", JSON::fromString("{\"arg_num\":3, \"default\":\"\", \"arg\":\"string\", \"help\":\"Filenames of any number of aditional inputs.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
|
||||
DTSC::File outFile;
|
||||
JSON::Value meta;
|
||||
DTSC::Meta newMeta;
|
||||
std::map<std::string,std::map<int, int> > trackMapping;
|
||||
|
||||
bool fullSort = true;
|
||||
std::map<std::string, DTSC::File> inFiles;
|
||||
std::map<std::string, DTSC::Meta> metaData;
|
||||
std::string outFileName = argv[1];
|
||||
std::string tmpFileName;
|
||||
for (int i = 2; i < argc; i++){
|
||||
tmpFileName = argv[i];
|
||||
if (tmpFileName == outFileName){
|
||||
fullSort = false;
|
||||
}else{
|
||||
DTSC::File F(tmpFileName);
|
||||
if (!F.getMeta().isFixed()){
|
||||
std::cerr << tmpFileName << " has not been run through DTSCFix yet." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
inFiles[tmpFileName] = F;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullSort){
|
||||
outFile = DTSC::File(outFileName, true);
|
||||
}else{
|
||||
outFile = DTSC::File(outFileName);
|
||||
if ( !outFile.getMeta().isFixed()){
|
||||
std::cerr << outFileName << " has not been run through DTSCFix yet." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
meta = outFile.getMeta().toJSON();
|
||||
newMeta = DTSC::Meta(meta);
|
||||
if (meta.isMember("tracks") && meta["tracks"].size() > 0){
|
||||
for (JSON::ObjIter trackIt = meta["tracks"].ObjBegin(); trackIt != meta["tracks"].ObjEnd(); trackIt++){
|
||||
int nxtMap = getNextFree(trackMapping);
|
||||
trackMapping[argv[1]].insert(std::pair<int,int>(trackIt->second["trackid"].asInt(),nxtMap));
|
||||
newMeta.tracks[nxtMap].trackID = nxtMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::multimap<int,keyframeInfo> allSorted;
|
||||
|
||||
for (std::map<std::string,DTSC::File>::iterator it = inFiles.begin(); it != inFiles.end(); it++){
|
||||
DTSC::Meta tmpMeta(it->second.getMeta());
|
||||
for (std::map<int,DTSC::Track>::iterator trackIt = tmpMeta.tracks.begin(); trackIt != tmpMeta.tracks.end(); trackIt++){
|
||||
long long int oldID = trackIt->first;
|
||||
long long int mappedID = getNextFree(trackMapping);
|
||||
trackMapping[it->first].insert(std::pair<int,int>(oldID,mappedID));
|
||||
for (std::deque<DTSC::Key>::iterator keyIt = trackIt->second.keys.begin(); keyIt != trackIt->second.keys.end(); keyIt++){
|
||||
keyframeInfo tmpInfo;
|
||||
tmpInfo.fileName = it->first;
|
||||
tmpInfo.trackID = oldID;
|
||||
tmpInfo.keyTime = keyIt->getTime();
|
||||
tmpInfo.keyBPos = keyIt->getBpos();
|
||||
tmpInfo.keyNum = keyIt->getNumber();
|
||||
tmpInfo.keyLen = keyIt->getLength();
|
||||
if ((keyIt + 1) != trackIt->second.keys.end()){
|
||||
tmpInfo.endBPos = (keyIt + 1)->getBpos();
|
||||
}else{
|
||||
tmpInfo.endBPos = it->second.getBytePosEOF();
|
||||
}
|
||||
allSorted.insert(std::pair<int,keyframeInfo>(keyIt->getTime(),tmpInfo));
|
||||
}
|
||||
newMeta.tracks[mappedID] = trackIt->second;
|
||||
newMeta.tracks[mappedID].trackID = mappedID;
|
||||
newMeta.tracks[mappedID].reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (fullSort){
|
||||
meta.null();
|
||||
meta["moreheader"] = 0ll;
|
||||
std::string tmpWrite = meta.toPacked();
|
||||
outFile.writeHeader(tmpWrite,true);
|
||||
}
|
||||
|
||||
std::set<int> trackSelector;
|
||||
for (std::multimap<int,keyframeInfo>::iterator sortIt = allSorted.begin(); sortIt != allSorted.end(); sortIt++){
|
||||
trackSelector.clear();
|
||||
trackSelector.insert(sortIt->second.trackID);
|
||||
inFiles[sortIt->second.fileName].selectTracks(trackSelector);
|
||||
inFiles[sortIt->second.fileName].seek_time(sortIt->second.keyTime);
|
||||
inFiles[sortIt->second.fileName].seekNext();
|
||||
while (inFiles[sortIt->second.fileName].getPacket() && inFiles[sortIt->second.fileName].getBytePos() <= sortIt->second.endBPos && !inFiles[sortIt->second.fileName].reachedEOF()){
|
||||
if (inFiles[sortIt->second.fileName].getPacket().getTrackId() == sortIt->second.trackID){
|
||||
JSON::Value tmp = inFiles[sortIt->second.fileName].getPacket().toJSON();
|
||||
tmp["trackid"] = trackMapping[sortIt->second.fileName][sortIt->second.trackID];
|
||||
outFile.writePacket(tmp);
|
||||
}
|
||||
inFiles[sortIt->second.fileName].seekNext();
|
||||
}
|
||||
}
|
||||
|
||||
if (fullSort || (meta.isMember("merged") && meta["merged"])){
|
||||
newMeta.merged = 1;
|
||||
}else{
|
||||
newMeta.merged = 0;
|
||||
}
|
||||
std::string writeMeta = newMeta.toJSON().toPacked();
|
||||
meta["moreheader"] = outFile.addHeader(writeMeta);
|
||||
writeMeta = meta.toPacked();
|
||||
outFile.writeHeader(writeMeta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv){
|
||||
return Converters::DTSCMerge(argc, argv);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/// \file flv2dtsc.cpp
|
||||
/// Contains the code that will transform any valid FLV input into valid DTSC.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <mist/flv_tag.h>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/json.h>
|
||||
#include <mist/amf.h>
|
||||
#include <mist/config.h>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
|
||||
///\brief Converts FLV from stdin to DTSC on stdout.
|
||||
///\return The return code for the converter.
|
||||
int FLV2DTSC(std::ostream & output){
|
||||
FLV::Tag FLV_in; // Temporary storage for incoming FLV data.
|
||||
DTSC::Meta meta_out; // Storage for outgoing header data.
|
||||
JSON::Value pack_out; // Storage for outgoing data.
|
||||
std::stringstream prebuffer; // Temporary buffer before sending real data
|
||||
bool sending = false;
|
||||
unsigned int counter = 0;
|
||||
|
||||
while ( !feof(stdin) && !FLV::Parse_Error){
|
||||
if (FLV_in.FileLoader(stdin)){
|
||||
pack_out = FLV_in.toJSON(meta_out);
|
||||
if (pack_out.isNull()){
|
||||
continue;
|
||||
}
|
||||
if ( !sending){
|
||||
counter++;
|
||||
if (counter > 8){
|
||||
sending = true;
|
||||
output << meta_out.toJSON().toNetPacked();
|
||||
output << prebuffer.rdbuf();
|
||||
prebuffer.str("");
|
||||
std::cerr << "Buffer done, starting real-time output..." << std::endl;
|
||||
}else{
|
||||
prebuffer << pack_out.toNetPacked();
|
||||
continue; //don't also write
|
||||
}
|
||||
}
|
||||
//simply write
|
||||
output << pack_out.toNetPacked();
|
||||
}
|
||||
}
|
||||
if (FLV::Parse_Error){
|
||||
std::cerr << "Conversion failed: " << FLV::Error_Str << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the FLV input is very short, do output it correctly...
|
||||
if ( !sending){
|
||||
std::cerr << "EOF - outputting buffer..." << std::endl;
|
||||
output << meta_out.toJSON().toNetPacked();
|
||||
output << prebuffer.rdbuf();
|
||||
}
|
||||
std::cerr << "Done! If you output this data to a file, don't forget to run MistDTSCFix next." << std::endl;
|
||||
|
||||
return 0;
|
||||
} //FLV2DTSC
|
||||
|
||||
}
|
||||
|
||||
///\brief Entry point for FLV2DTSC, simply calls Converters::FLV2DTSC().
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("output",
|
||||
JSON::fromString(
|
||||
"{\"long\":\"output\", \"value\":[\"stdout\"], \"short\":\"o\", \"arg\":\"string\", \"help\":\"Name of the outputfile or stdout for standard output.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
if (conf.getString("output") == "stdout"){
|
||||
return Converters::FLV2DTSC(std::cout);
|
||||
}
|
||||
std::ofstream oFile(conf.getString("output").c_str());
|
||||
return Converters::FLV2DTSC(oFile);
|
||||
} //main
|
|
@ -1,244 +0,0 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/ogg.h>
|
||||
#include <mist/theora.h>
|
||||
#include <mist/vorbis.h>
|
||||
#include <mist/config.h>
|
||||
#include <mist/json.h>
|
||||
#include <mist/bitstream.h>
|
||||
|
||||
namespace Converters{
|
||||
enum codecType {THEORA, VORBIS};
|
||||
|
||||
class oggTrack{
|
||||
public:
|
||||
oggTrack() : lastTime(0), parsedHeaders(false) { }
|
||||
codecType codec;
|
||||
std::string name;
|
||||
std::string contBuffer;//buffer for continuing pages
|
||||
long long unsigned int dtscID;
|
||||
double lastTime;
|
||||
long long unsigned int lastGran;
|
||||
bool parsedHeaders;
|
||||
//Codec specific elements
|
||||
//theora
|
||||
theora::header idHeader;//needed to determine keyframe
|
||||
//vorbis
|
||||
std::deque<vorbis::mode> vModes;
|
||||
char channels;
|
||||
long long unsigned int blockSize[2];
|
||||
};
|
||||
|
||||
int OGG2DTSC(){
|
||||
std::string oggBuffer;
|
||||
OGG::Page oggPage;
|
||||
//Read all of std::cin to oggBuffer
|
||||
double mspft = 0;//microseconds per frame
|
||||
double mspfv = 0;//microseconds per frame vorbis
|
||||
JSON::Value DTSCOut;
|
||||
JSON::Value DTSCHeader;
|
||||
DTSCHeader.null();
|
||||
DTSCHeader["moreheader"] = 0ll;
|
||||
std::map<long unsigned int, oggTrack> trackData;
|
||||
long long int lastTrackID = 1;
|
||||
int headerSeen = 0;
|
||||
bool headerWritten = false;//important bool, used for outputting the simple DTSC header.
|
||||
//while stream busy
|
||||
while (std::cin.good()){
|
||||
for (unsigned int i = 0; (i < 1024) && (std::cin.good()); i++){//buffering
|
||||
oggBuffer += std::cin.get();
|
||||
}
|
||||
while (oggPage.read(oggBuffer)){//reading ogg to ogg::page
|
||||
//on succes, we handle one page
|
||||
long unsigned int sNum = oggPage.getBitstreamSerialNumber();
|
||||
if (oggPage.typeBOS()){//defines a new track
|
||||
if (memcmp(oggPage.getFullPayload()+1, "theora", 6) == 0){
|
||||
headerSeen += 1;
|
||||
headerWritten = false;
|
||||
trackData[sNum].codec = THEORA;
|
||||
//fix timerate here
|
||||
//frn/frd = fps
|
||||
theora::header tempHead;
|
||||
tempHead.read(oggPage.getFullPayload(), oggPage.getPayloadSize());
|
||||
mspft = (double)(tempHead.getFRD() * 1000) / tempHead.getFRN();
|
||||
}else if(memcmp(oggPage.getFullPayload()+1, "vorbis", 6) == 0){
|
||||
headerSeen += 1;
|
||||
headerWritten = false;
|
||||
trackData[sNum].codec = VORBIS;
|
||||
vorbis::header tempHead;
|
||||
tempHead.read(oggPage.getFullPayload(), oggPage.getPayloadSize());
|
||||
mspfv = (double)1000 / ntohl(tempHead.getAudioSampleRate());
|
||||
}else{
|
||||
std::cerr << "Unknown Codec, " << std::string(oggPage.getFullPayload()+1, 6)<<" skipping" << std::endl;
|
||||
continue;
|
||||
}
|
||||
trackData[sNum].dtscID = lastTrackID++;
|
||||
std::stringstream tID;
|
||||
tID << "track" << trackData[sNum].dtscID;
|
||||
trackData[sNum].name = tID.str();
|
||||
}
|
||||
//if Serial number is available in mapping
|
||||
if(trackData.find(sNum)!=trackData.end()){//create DTSC from OGG page
|
||||
int offset = 0;
|
||||
for (std::deque<unsigned int>::iterator it = oggPage.getSegmentTableDeque().begin(); it != oggPage.getSegmentTableDeque().end(); it++){
|
||||
if (trackData[sNum].parsedHeaders){
|
||||
//if we are dealing with the last segment which is a part of a later continued segment
|
||||
if (it == (oggPage.getSegmentTableDeque().end()-1) && oggPage.getPageSegments() == 255 && oggPage.getSegmentTable()[254] == 255 ){
|
||||
//put in buffer
|
||||
trackData[sNum].contBuffer += std::string(oggPage.getFullPayload()+offset, (*it));
|
||||
}else{
|
||||
//output DTSC packet
|
||||
DTSCOut.null();//clearing DTSC buffer
|
||||
DTSCOut["trackid"] = (long long)trackData[sNum].dtscID;
|
||||
long long unsigned int temp = oggPage.getGranulePosition();
|
||||
DTSCOut["time"] = (long long)trackData[sNum].lastTime;
|
||||
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{
|
||||
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
|
||||
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();
|
||||
}
|
||||
}else{//if we ouput a header:
|
||||
//switch on codec
|
||||
switch(trackData[sNum].codec){
|
||||
case THEORA:{
|
||||
theora::header tHead;
|
||||
if(tHead.read(oggPage.getFullPayload()+offset, (*it))){//if the current segment is a Theora header part
|
||||
//fillDTSC header
|
||||
switch(tHead.getHeaderType()){
|
||||
case 0:{ //identification header
|
||||
trackData[sNum].idHeader = tHead;
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["height"] = (long long)tHead.getPICH();
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["width"] = (long long)tHead.getPICW();
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["idheader"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||
break;
|
||||
}
|
||||
case 1: //comment header
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["commentheader"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||
break;
|
||||
case 2:{ //setup header, also the point to start writing the header
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["codec"] = "theora";
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["trackid"] = (long long)trackData[sNum].dtscID;
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["type"] = "video";
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["init"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||
headerSeen --;
|
||||
trackData[sNum].parsedHeaders = true;
|
||||
trackData[sNum].lastGran = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VORBIS:{
|
||||
vorbis::header vHead;
|
||||
if(vHead.read(oggPage.getFullPayload()+offset, (*it))){//if the current segment is a Vorbis header part
|
||||
switch(vHead.getHeaderType()){
|
||||
case 1:{
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["channels"] = (long long)vHead.getAudioChannels();
|
||||
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;
|
||||
}
|
||||
case 3:{
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["commentheader"] = std::string(oggPage.getFullPayload()+offset, (*it));
|
||||
break;
|
||||
}
|
||||
case 5:{
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["codec"] = "vorbis";
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["trackid"] = (long long)trackData[sNum].dtscID;
|
||||
DTSCHeader["tracks"][trackData[sNum].name]["type"] = "audio";
|
||||
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 --;
|
||||
trackData[sNum].parsedHeaders = true;
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
std::cerr << "Unsupported header type for vorbis" << std::endl;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
std::cerr << "Unknown Header" << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << "Can not handle this codec" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset += (*it);
|
||||
}
|
||||
|
||||
}else{
|
||||
std::cerr <<"Error! Unknown bitstream number " << oggPage.getBitstreamSerialNumber() << std::endl;
|
||||
}
|
||||
//write header here
|
||||
if (headerSeen == 0 && headerWritten == false){
|
||||
std::cout << DTSCHeader.toNetPacked();
|
||||
headerWritten = true;
|
||||
}
|
||||
//write section
|
||||
if (oggPage.typeEOS()){//ending page
|
||||
//remove from trackdata
|
||||
trackData.erase(sNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cerr << "DTSC file created succesfully" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.parseArgs(argc,argv);
|
||||
return Converters::OGG2DTSC();
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
#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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#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);
|
||||
void readDTSCVector(JSON::Value & DTSCPart, std::string & pageBuffer);
|
||||
std::string parsedPages;
|
||||
private:
|
||||
std::map <long long unsigned int, trackStats> trackInf;
|
||||
//long long unsigned int calcGranule(long long unsigned int trackID, bool keyFrame);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/// \file flv2dtsc.cpp
|
||||
/// Contains the code that will transform any valid FLV input into valid DTSC.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <mist/flv_tag.h>
|
||||
#include <mist/dtsc.h>
|
||||
#include <mist/json.h>
|
||||
#include <mist/amf.h>
|
||||
#include <mist/config.h>
|
||||
|
||||
///\brief Holds everything unique to converters.
|
||||
namespace Converters {
|
||||
|
||||
///\brief Converts FLV from stdin to DTSC on stdout.
|
||||
///\return The return code for the converter.
|
||||
int SRT2DTSC(Util::Config & conf){
|
||||
int lineNum;
|
||||
int beginH, beginM, beginS, beginMs;
|
||||
int endH, endM, endS, endMs;
|
||||
char lineBuf[1024];
|
||||
std::string myData;
|
||||
JSON::Value meta;
|
||||
meta["moreheader"] = 0ll;
|
||||
meta["tracks"]["track3"]["trackid"] = 3ll;
|
||||
meta["tracks"]["track3"]["type"] = "meta";
|
||||
meta["tracks"]["track3"]["codec"] = "srt";
|
||||
meta["tracks"]["track3"]["language"] = conf.getString("language");
|
||||
std::cout << meta.toNetPacked();
|
||||
JSON::Value newPack;
|
||||
while (std::cin.good()){
|
||||
if (scanf( "%d\n%d:%d:%d,%d --> %d:%d:%d,%d\n", &lineNum, &beginH, &beginM, &beginS, &beginMs, &endH, &endM, &endS, &endMs) != 9){
|
||||
break;
|
||||
}
|
||||
while (std::cin.good() && myData.find("\r\n\r\n") == std::string::npos && myData.find("\n\n") == std::string::npos){
|
||||
std::cin.getline(lineBuf, 1024);
|
||||
myData += std::string(lineBuf) + "\n";
|
||||
}
|
||||
myData.erase( myData.end() - 1 );
|
||||
newPack.null();
|
||||
newPack["trackid"] = 3;
|
||||
newPack["time"] = (((((beginH * 60) + beginM) * 60) + beginS) * 1000) + beginMs;
|
||||
newPack["duration"] = (((((endH - beginH) * 60) + (endM - beginM)) * 60) + (endS - beginS)) * 1000 + (endMs - beginMs);
|
||||
newPack["data"] = myData;
|
||||
std::cout << newPack.toNetPacked();
|
||||
myData = "";
|
||||
}
|
||||
return 0;
|
||||
} //SRT2DTSC
|
||||
|
||||
}
|
||||
|
||||
///\brief Entry point for SRT2DTSC, simply calls Converters::SRT2DTSC().
|
||||
int main(int argc, char ** argv){
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.addOption("language",
|
||||
JSON::fromString("{\"arg_num\":1,\"value\":[\"?\"], \"help\": \"The language of these subtitles.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
return Converters::SRT2DTSC(conf);
|
||||
} //main
|
Loading…
Add table
Reference in a new issue