Several bugfixes (HTTP dynamic seeking!) and updates to the MP4 lib.
This commit is contained in:
parent
a91e53e0bc
commit
521c19f932
8 changed files with 177 additions and 100 deletions
|
@ -1,7 +1,8 @@
|
|||
AM_CPPFLAGS = $(global_CFLAGS) $(MIST_CFLAGS)
|
||||
LDADD = $(MIST_LIBS)
|
||||
bin_PROGRAMS=MistAnalyserRTMP MistAnalyserFLV MistAnalyserDTSC MistAnalyserAMF
|
||||
bin_PROGRAMS=MistAnalyserRTMP MistAnalyserFLV MistAnalyserDTSC MistAnalyserAMF MistAnalyserMP4
|
||||
MistAnalyserRTMP_SOURCES=rtmp_analyser.cpp
|
||||
MistAnalyserFLV_SOURCES=flv_analyser.cpp
|
||||
MistAnalyserDTSC_SOURCES=dtsc_analyser.cpp
|
||||
MistAnalyserAMF_SOURCES=amf_analyser.cpp
|
||||
MistAnalyserMP4_SOURCES=mp4_analyser.cpp
|
||||
|
|
|
@ -13,8 +13,7 @@ int main(int argc, char ** argv){
|
|||
conf.addOption("filename", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the DTSC file to analyse.\"}"));
|
||||
conf.parseArgs(argc, argv);
|
||||
DTSC::File F(conf.getString("filename"));
|
||||
std::string loader = F.getHeader();
|
||||
JSON::Value meta = JSON::fromDTMI(loader);
|
||||
JSON::Value meta = F.getMeta();
|
||||
std::cout << meta.toPrettyString() << std::endl;
|
||||
JSON::Value pack;
|
||||
|
||||
|
|
29
src/analysers/mp4_analyser.cpp
Normal file
29
src/analysers/mp4_analyser.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/// \file mp4_analyser.cpp
|
||||
/// Debugging tool for MP4 data.
|
||||
/// Expects MP4 data through stdin, outputs human-readable information to stderr.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <mist/mp4.h>
|
||||
#include <mist/config.h>
|
||||
|
||||
/// Debugging tool for MP4 data.
|
||||
/// Expects MP4 data through stdin, outputs human-readable information to stderr.
|
||||
int main(int argc, char ** argv) {
|
||||
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
|
||||
conf.parseArgs(argc, argv);
|
||||
|
||||
std::string temp;
|
||||
while (std::cin.good()){temp += std::cin.get();}//read all of std::cin to temp
|
||||
temp.erase(temp.size()-1, 1);//strip the invalid last character
|
||||
|
||||
MP4::Box mp4data;
|
||||
while (mp4data.read(temp)){
|
||||
std::cerr << mp4data.toPrettyString(0) << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -26,64 +26,94 @@
|
|||
/// Holds everything unique to HTTP Dynamic Connector.
|
||||
namespace Connector_HTTP{
|
||||
|
||||
std::string GenerateBootstrap(std::string & MovieId, JSON::Value & metadata, int fragnum, int starttime){
|
||||
MP4::AFRT afrt;
|
||||
if (starttime == 0){
|
||||
afrt.SetUpdate(false);
|
||||
}else{
|
||||
afrt.SetUpdate(true);
|
||||
}
|
||||
afrt.SetTimeScale(1000);
|
||||
afrt.AddQualityEntry("");
|
||||
if (!metadata.isMember("video") || !metadata["video"].isMember("keyms") || metadata["video"]["keyms"].asInt() == 0){
|
||||
//metadata["lasttime"].asInt()?
|
||||
afrt.AddFragmentRunEntry(fragnum, starttime, 2000); //FirstFragment, FirstFragmentTimestamp,Fragment Duration in milliseconds
|
||||
}else{
|
||||
afrt.AddFragmentRunEntry(fragnum, starttime, metadata["video"]["keyms"].asInt()); //FirstFragment, FirstFragmentTimestamp,Fragment Duration in milliseconds
|
||||
}
|
||||
afrt.WriteContent();
|
||||
std::string GenerateBootstrap(std::string & MovieId, JSON::Value & metadata, int fragnum, int starttime, int endtime){
|
||||
std::string empty;
|
||||
|
||||
MP4::ASRT asrt;
|
||||
if (starttime == 0){
|
||||
asrt.SetUpdate(false);
|
||||
asrt.setUpdate(false);
|
||||
}else{
|
||||
asrt.SetUpdate(true);
|
||||
asrt.setUpdate(true);
|
||||
}
|
||||
asrt.setVersion(1);
|
||||
asrt.setQualityEntry(empty, 0);
|
||||
if (!metadata.isMember("keytime") || metadata["keytime"].size() == 0){
|
||||
asrt.setSegmentRun(1, 20000, 0);
|
||||
}else{
|
||||
asrt.setSegmentRun(1, metadata["keytime"].size(), 0);
|
||||
}
|
||||
|
||||
|
||||
MP4::AFRT afrt;
|
||||
if (starttime == 0){
|
||||
afrt.setUpdate(false);
|
||||
}else{
|
||||
afrt.setUpdate(true);
|
||||
}
|
||||
afrt.setVersion(1);
|
||||
afrt.setTimeScale(1000);
|
||||
afrt.setQualityEntry(empty, 0);
|
||||
MP4::afrt_runtable afrtrun;
|
||||
if (!metadata.isMember("keytime") || metadata["keytime"].size() == 0){
|
||||
afrtrun.firstFragment = 1;
|
||||
afrtrun.firstTimestamp = 0;
|
||||
if (!metadata.isMember("video") || !metadata["video"].isMember("keyms") || metadata["video"]["keyms"].asInt() == 0){
|
||||
afrtrun.duration = 2000;
|
||||
}else{
|
||||
afrtrun.duration = metadata["video"]["keyms"].asInt();
|
||||
}
|
||||
afrt.setFragmentRun(afrtrun, 0);
|
||||
}else{
|
||||
for (int i = 0; i < metadata["keytime"].size(); i++){
|
||||
afrtrun.firstFragment = i+1;
|
||||
afrtrun.firstTimestamp = metadata["keytime"][i].asInt();
|
||||
if (i+1 < metadata["keytime"].size()){
|
||||
afrtrun.duration = metadata["keytime"][i+1].asInt() - metadata["keytime"][i].asInt();
|
||||
}else{
|
||||
if (metadata["lastms"].asInt()){
|
||||
afrtrun.duration = metadata["lastms"].asInt() - metadata["keytime"][i].asInt();
|
||||
}else{
|
||||
afrtrun.duration = 3000;//guess 3 seconds if unknown
|
||||
}
|
||||
}
|
||||
afrt.setFragmentRun(afrtrun, i);
|
||||
}
|
||||
}
|
||||
asrt.AddQualityEntry("");
|
||||
/// \todo Actually use correct number of fragments.
|
||||
asrt.AddSegmentRunEntry(1, 20000);//1 Segment, 20000 Fragments
|
||||
asrt.WriteContent();
|
||||
|
||||
MP4::ABST abst;
|
||||
abst.AddFragmentRunTable(&afrt);
|
||||
abst.AddSegmentRunTable(&asrt);
|
||||
abst.SetBootstrapVersion(1);
|
||||
abst.SetProfile(0);
|
||||
if (metadata.isMember("length") && metadata["length"].asInt() > 0){
|
||||
abst.SetLive(false);
|
||||
abst.SetMediaTime(1000*metadata["length"].asInt());
|
||||
}else{
|
||||
abst.SetLive(true);
|
||||
abst.SetMediaTime(0xFFFFFFFF);//metadata["lasttime"].asInt()?
|
||||
}
|
||||
abst.setVersion(1);
|
||||
abst.setBootstrapinfoVersion(1);
|
||||
abst.setProfile(0);
|
||||
if (starttime == 0){
|
||||
abst.SetUpdate(false);
|
||||
abst.setUpdate(false);
|
||||
}else{
|
||||
abst.SetUpdate(true);
|
||||
abst.setUpdate(true);
|
||||
}
|
||||
abst.SetTimeScale(1000);
|
||||
abst.SetSMPTE(0);
|
||||
abst.SetMovieIdentifier(MovieId);
|
||||
abst.SetDRM("");
|
||||
abst.SetMetaData("");
|
||||
abst.AddServerEntry("");
|
||||
abst.AddQualityEntry("");
|
||||
abst.WriteContent();
|
||||
abst.setTimeScale(1000);
|
||||
if (metadata.isMember("length") && metadata["length"].asInt() > 0){
|
||||
abst.setLive(false);
|
||||
if (metadata["lastms"].asInt()){
|
||||
abst.setCurrentMediaTime(metadata["lastms"].asInt());
|
||||
}else{
|
||||
abst.setCurrentMediaTime(1000*metadata["length"].asInt());
|
||||
}
|
||||
}else{
|
||||
abst.setLive(true);
|
||||
abst.setCurrentMediaTime(0xFFFFFFFF);
|
||||
}
|
||||
abst.setSmpteTimeCodeOffset(0);
|
||||
abst.setMovieIdentifier(MovieId);
|
||||
abst.setServerEntry(empty, 0);
|
||||
abst.setQualityEntry(empty, 0);
|
||||
abst.setDrmData(empty);
|
||||
abst.setMetaData(empty);
|
||||
abst.setSegmentRunTable(asrt, 0);
|
||||
abst.setFragmentRunTable(afrt, 0);
|
||||
|
||||
//#if DEBUG >= 8
|
||||
std::cout << "Sending bootstrap:" << std::endl << abst.toPrettyString(0) << std::endl;
|
||||
//#endif
|
||||
return std::string((char*)abst.GetBoxedData(), (int)abst.GetBoxedDataSize());
|
||||
return std::string((char*)abst.asBox(), (int)abst.boxedSize());
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,18 +121,19 @@ namespace Connector_HTTP{
|
|||
std::string BuildManifest(std::string & MovieId, JSON::Value & metadata){
|
||||
std::string Result;
|
||||
if (metadata.isMember("length") && metadata["length"].asInt() > 0){
|
||||
std::stringstream st;
|
||||
st << ((double)metadata["video"]["keyms"].asInt() / 1000);
|
||||
Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
"<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n"
|
||||
"<id>" + MovieId + "</id>\n"
|
||||
"<duration>" + metadata["length"].asString() + "</duration>\n"
|
||||
"<width>" + metadata["video"]["width"].asString() + "</width>\n"
|
||||
"<height>" + metadata["video"]["height"].asString() + "</height>\n"
|
||||
"<duration>" + metadata["length"].asString() + ".000</duration>\n"
|
||||
"<mimeType>video/mp4</mimeType>\n"
|
||||
"<streamType>recorded</streamType>\n"
|
||||
"<deliveryType>streaming</deliveryType>\n"
|
||||
"<bestEffortFetchInfo segmentDuration=\""+metadata["length"].asString()+".000\" fragmentDuration=\""+st.str()+"\" />\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0)) + "</bootstrapInfo>\n"
|
||||
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\"></media>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n"
|
||||
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\">\n"
|
||||
"<metadata>AgAKb25NZXRhRGF0YQgAAAAAAAl0cmFja2luZm8KAAAAAgMACXRpbWVzY2FsZQBA+GoAAAAAAAAGbGVuZ3RoAEGMcHoQAAAAAAhsYW5ndWFnZQIAA2VuZwARc2FtcGxlZGVzY3JpcHRpb24KAAAAAQMACnNhbXBsZXR5cGUCAARhdmMxAAAJAAAJAwAJdGltZXNjYWxlAEDncAAAAAAAAAZsZW5ndGgAQXtNvTAAAAAACGxhbmd1YWdlAgADZW5nABFzYW1wbGVkZXNjcmlwdGlvbgoAAAABAwAKc2FtcGxldHlwZQIABG1wNGEAAAkAAAkADWF1ZGlvY2hhbm5lbHMAQAAAAAAAAAAAD2F1ZGlvc2FtcGxlcmF0ZQBA53AAAAAAAAAOdmlkZW9mcmFtZXJhdGUAQDf/gi5SciUABmFhY2FvdABAAAAAAAAAAAAIYXZjbGV2ZWwAQD8AAAAAAAAACmF2Y3Byb2ZpbGUAQFNAAAAAAAAADGF1ZGlvY29kZWNpZAIABG1wNGEADHZpZGVvY29kZWNpZAIABGF2YzEABXdpZHRoAECQ4AAAAAAAAAZoZWlnaHQAQIMAAAAAAAAACmZyYW1lV2lkdGgAQJDgAAAAAAAAC2ZyYW1lSGVpZ2h0AECDAAAAAAAAAAxkaXNwbGF5V2lkdGgAQJDgAAAAAAAADWRpc3BsYXlIZWlnaHQAQIMAAAAAAAAADG1vb3Zwb3NpdGlvbgBBmxq2uAAAAAAIZHVyYXRpb24AQIKjqW3oyhIAAAk=</metadata>\n"
|
||||
"</media>\n"
|
||||
"</manifest>\n";
|
||||
}else{
|
||||
Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
|
@ -111,7 +142,7 @@ namespace Connector_HTTP{
|
|||
"<mimeType>video/mp4</mimeType>\n"
|
||||
"<streamType>live</streamType>\n"
|
||||
"<deliveryType>streaming</deliveryType>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0)) + "</bootstrapInfo>\n"
|
||||
"<bootstrapInfo profile=\"named\" id=\"bootstrap1\">" + Base64::encode(GenerateBootstrap(MovieId, metadata, 1, 0, 0)) + "</bootstrapInfo>\n"
|
||||
"<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"" + MovieId + "/\"></media>\n"
|
||||
"</manifest>\n";
|
||||
}
|
||||
|
@ -273,26 +304,26 @@ namespace Connector_HTTP{
|
|||
#if DEBUG >= 3
|
||||
fprintf(stderr, "Sending a fragment...");
|
||||
#endif
|
||||
static std::string btstrp;
|
||||
btstrp = GenerateBootstrap(streamname, Strm.metadata, ReqFragment, FlashBufTime);
|
||||
//static std::string btstrp;
|
||||
//btstrp = GenerateBootstrap(streamname, Strm.metadata, ReqFragment, FlashBufTime, Strm.getPacket(0)["time"]);
|
||||
HTTP_S.Clean();
|
||||
HTTP_S.SetHeader("Content-Type", "video/mp4");
|
||||
HTTP_S.SetBody("");
|
||||
HTTP_S.SetHeader("Content-Length", FlashBufSize+32+33+btstrp.size());
|
||||
HTTP_S.SetHeader("Content-Length", FlashBufSize+8);//32+33+btstrp.size());
|
||||
conn.SendNow(HTTP_S.BuildResponse("200", "OK"));
|
||||
conn.SendNow("\x00\x00\x00\x21" "afra\x00\x00\x00\x00\x00\x00\x00\x03\xE8\x00\x00\x00\x01", 21);
|
||||
unsigned long tmptime = htonl(FlashBufTime << 32);
|
||||
conn.SendNow((char*)&tmptime, 4);
|
||||
tmptime = htonl(FlashBufTime & 0xFFFFFFFF);
|
||||
conn.SendNow((char*)&tmptime, 4);
|
||||
tmptime = htonl(65);
|
||||
conn.SendNow((char*)&tmptime, 4);
|
||||
//conn.SendNow("\x00\x00\x00\x21" "afra\x00\x00\x00\x00\x00\x00\x00\x03\xE8\x00\x00\x00\x01", 21);
|
||||
//unsigned long tmptime = htonl(FlashBufTime << 32);
|
||||
//conn.SendNow((char*)&tmptime, 4);
|
||||
//tmptime = htonl(FlashBufTime & 0xFFFFFFFF);
|
||||
//conn.SendNow((char*)&tmptime, 4);
|
||||
//tmptime = htonl(65);
|
||||
//conn.SendNow((char*)&tmptime, 4);
|
||||
|
||||
conn.SendNow(btstrp);
|
||||
//conn.SendNow(btstrp);
|
||||
|
||||
conn.SendNow("\x00\x00\x00\x18moof\x00\x00\x00\x10mfhd\x00\x00\x00\x00", 20);
|
||||
unsigned long fragno = htonl(ReqFragment);
|
||||
conn.SendNow((char*)&fragno, 4);
|
||||
//conn.SendNow("\x00\x00\x00\x18moof\x00\x00\x00\x10mfhd\x00\x00\x00\x00", 20);
|
||||
//unsigned long fragno = htonl(ReqFragment);
|
||||
//conn.SendNow((char*)&fragno, 4);
|
||||
unsigned long size = htonl(FlashBufSize+8);
|
||||
conn.SendNow((char*)&size, 4);
|
||||
conn.SendNow("mdat", 4);
|
||||
|
@ -313,11 +344,13 @@ namespace Connector_HTTP{
|
|||
//fill buffer with init data, if needed.
|
||||
if (Strm.metadata.isMember("audio") && Strm.metadata["audio"].isMember("init")){
|
||||
tmp.DTSCAudioInit(Strm);
|
||||
tmp.tagTime(Strm.getPacket(0)["time"].asInt());
|
||||
FlashBuf.push_back(std::string(tmp.data, tmp.len));
|
||||
FlashBufSize += tmp.len;
|
||||
}
|
||||
if (Strm.metadata.isMember("video") && Strm.metadata["video"].isMember("init")){
|
||||
tmp.DTSCVideoInit(Strm);
|
||||
tmp.tagTime(Strm.getPacket(0)["time"].asInt());
|
||||
FlashBuf.push_back(std::string(tmp.data, tmp.len));
|
||||
FlashBufSize += tmp.len;
|
||||
}
|
||||
|
|
|
@ -215,7 +215,6 @@ void CheckConfig(JSON::Value & in, JSON::Value & out){
|
|||
}
|
||||
}
|
||||
out = in;
|
||||
out["version"] = PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
bool streamsEqual(JSON::Value & one, JSON::Value & two){
|
||||
|
@ -558,6 +557,7 @@ int main(int argc, char ** argv){
|
|||
//sent current configuration, no matter if it was changed or not
|
||||
//Response["streams"] = Storage["streams"];
|
||||
Response["config"] = Connector::Storage["config"];
|
||||
Response["config"]["version"] = PACKAGE_VERSION "/" + Util::Config::libver;
|
||||
Response["streams"] = Connector::Storage["streams"];
|
||||
//add required data to the current unix time to the config, for syncing reasons
|
||||
Response["config"]["time"] = Util::epoch();
|
||||
|
|
|
@ -12,10 +12,21 @@ namespace Converters{
|
|||
/// Reads an DTSC file and attempts to fix the metadata in it.
|
||||
int DTSCFix(Util::Config & conf) {
|
||||
DTSC::File F(conf.getString("filename"));
|
||||
std::string loader = F.getHeader();
|
||||
JSON::Value meta = JSON::fromDTMI(loader);
|
||||
JSON::Value oriheader = F.getMeta();
|
||||
JSON::Value meta = oriheader;
|
||||
JSON::Value pack;
|
||||
|
||||
if (!oriheader.isMember("moreheader")){
|
||||
std::cerr << "This file is not DTSCFix'able. Please re-convert and try again." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (oriheader["moreheader"].asInt() > 0){
|
||||
std::cerr << "Warning: This file has already been DTSCFix'ed. Doing this multiple times makes the file larger for no reason." << std::endl;
|
||||
}
|
||||
meta.removeMember("keytime");
|
||||
meta.removeMember("keybpos");
|
||||
meta.removeMember("moreheader");
|
||||
|
||||
long long unsigned int firstpack = 0;
|
||||
long long unsigned int nowpack = 0;
|
||||
long long unsigned int lastaudio = 0;
|
||||
|
@ -54,6 +65,8 @@ namespace Converters{
|
|||
if (bps > vid_max){vid_max = bps;}
|
||||
}
|
||||
if (F.getJSON()["keyframe"].asInt() != 0){
|
||||
meta["keytime"].append(F.getJSON()["time"]);
|
||||
meta["keybpos"].append(F.getLastReadPos());
|
||||
if (lastkey != 0){
|
||||
bps = nowpack - lastkey;
|
||||
if (bps < key_min){key_min = bps;}
|
||||
|
@ -73,12 +86,10 @@ namespace Converters{
|
|||
F.seekNext();
|
||||
}
|
||||
|
||||
std::cout << std::endl << "Summary:" << std::endl;
|
||||
meta["length"] = (long long int)((nowpack - firstpack)/1000);
|
||||
meta["lastms"] = (long long int)nowpack;
|
||||
if (meta.isMember("audio")){
|
||||
meta["audio"]["bps"] = (long long int)(totalaudio / ((lastaudio - firstpack) / 1000));
|
||||
std::cout << " Audio: " << meta["audio"]["codec"].asString() << std::endl;
|
||||
std::cout << " Bitrate: " << meta["audio"]["bps"].asInt() << std::endl;
|
||||
}
|
||||
if (meta.isMember("video")){
|
||||
meta["video"]["bps"] = (long long int)(totalvideo / ((lastvideo - firstpack) / 1000));
|
||||
|
@ -88,16 +99,20 @@ namespace Converters{
|
|||
}else{
|
||||
meta["video"]["keyvar"] = (long long int)(key_max - meta["video"]["keyms"].asInt());
|
||||
}
|
||||
std::cout << " Video: " << meta["video"]["codec"].asString() << std::endl;
|
||||
std::cout << " Bitrate: " << meta["video"]["bps"].asInt() << std::endl;
|
||||
std::cout << " Keyframes: " << meta["video"]["keyms"].asInt() << "~" << meta["video"]["keyvar"].asInt() << std::endl;
|
||||
std::cout << " B-frames: " << bfrm_min << " - " << bfrm_max << std::endl;
|
||||
}
|
||||
|
||||
std::cerr << "Appending new header..." << std::endl;
|
||||
std::string loader = meta.toPacked();
|
||||
long long int newHPos = F.addHeader(loader);
|
||||
if (!newHPos){
|
||||
std::cerr << "Failure appending new header. Cancelling." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cerr << "Re-writing header..." << std::endl;
|
||||
|
||||
loader = meta.toPacked();
|
||||
oriheader["moreheader"] = newHPos;
|
||||
loader = oriheader.toPacked();
|
||||
if (F.writeHeader(loader)){
|
||||
std::cerr << "Metadata is now: " << meta.toPrettyString(0) << std::endl;
|
||||
return 0;
|
||||
}else{
|
||||
return -1;
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace Converters{
|
|||
counter++;
|
||||
if (counter > 8){
|
||||
sending = true;
|
||||
meta_out["moreheader"] = 0LL;
|
||||
std::string packed_header = meta_out.toPacked();
|
||||
unsigned int size = htonl(packed_header.size());
|
||||
std::cout << std::string(DTSC::Magic_Header, 4) << std::string((char*)&size, 4) << packed_header;
|
||||
|
@ -59,12 +60,13 @@ namespace Converters{
|
|||
// if the FLV input is very short, do output it correctly...
|
||||
if (!sending){
|
||||
std::cerr << "EOF - outputting buffer..." << std::endl;
|
||||
meta_out["moreheader"] = 0LL;
|
||||
std::string packed_header = meta_out.toPacked();
|
||||
unsigned int size = htonl(packed_header.size());
|
||||
std::cout << std::string(DTSC::Magic_Header, 4) << std::string((char*)&size, 4) << packed_header;
|
||||
std::cout << prebuffer.rdbuf();
|
||||
}
|
||||
std::cerr << "Done!" << std::endl;
|
||||
std::cerr << "Done! If you output this data to a file, don't forget to run MistDTSCFix next." << std::endl;
|
||||
|
||||
return 0;
|
||||
}//FLV2DTSC
|
||||
|
|
|
@ -69,7 +69,7 @@ int main(int argc, char** argv){
|
|||
|
||||
DTSC::File source = DTSC::File(conf.getString("filename"));
|
||||
Socket::Connection in_out = Socket::Connection(fileno(stdout), fileno(stdin));
|
||||
std::string meta_str = source.getHeader();
|
||||
JSON::Value meta = source.getMeta();
|
||||
JSON::Value pausemark;
|
||||
pausemark["datatype"] = "pause_marker";
|
||||
pausemark["time"] = (long long int)0;
|
||||
|
@ -78,14 +78,9 @@ int main(int argc, char** argv){
|
|||
int lasttime = Util::epoch();//time last packet was sent
|
||||
|
||||
//send the header
|
||||
{
|
||||
in_out.Send("DTSC");
|
||||
unsigned int size = htonl(meta_str.size());
|
||||
in_out.Send((char*)&size, 4);
|
||||
std::string meta_str = meta.toNetPacked();
|
||||
in_out.Send(meta_str);
|
||||
}
|
||||
|
||||
JSON::Value meta = JSON::fromDTMI(meta_str);
|
||||
if (meta["video"]["keyms"].asInt() < 11){
|
||||
meta["video"]["keyms"] = (long long int)1000;
|
||||
}
|
||||
|
@ -132,6 +127,10 @@ int main(int argc, char** argv){
|
|||
json_sts["vod"]["start"] = Util::epoch() - sts.conntime;
|
||||
if (!meta_sent){
|
||||
json_sts["vod"]["meta"] = meta;
|
||||
json_sts["vod"]["meta"]["audio"].removeMember("init");
|
||||
json_sts["vod"]["meta"]["video"].removeMember("init");
|
||||
json_sts["vod"]["meta"].removeMember("keytime");
|
||||
json_sts["vod"]["meta"].removeMember("keybpos");
|
||||
meta_sent = true;
|
||||
}
|
||||
StatsSocket.Send(json_sts.toString().c_str());
|
||||
|
@ -181,17 +180,16 @@ int main(int argc, char** argv){
|
|||
}
|
||||
lastTime = now;
|
||||
if (playing > 0){--playing;}
|
||||
}
|
||||
if (playing == 0){
|
||||
#if DEBUG >= 4
|
||||
std::cerr << "Sending pause_marker (" << (Util::getMS() - bench) << "ms)" << std::endl;
|
||||
#endif
|
||||
pausemark["time"] = (long long int)now;
|
||||
pausemark["time"] = source.getJSON()["time"];
|
||||
pausemark.toPacked();
|
||||
in_out.SendNow(pausemark.toNetPacked());
|
||||
in_out.setBlocking(true);
|
||||
}
|
||||
}
|
||||
if (playing != 0){
|
||||
}else{
|
||||
lasttime = Util::epoch();
|
||||
//insert proper header for this type of data
|
||||
in_out.Send("DTPD");
|
||||
|
|
Loading…
Add table
Reference in a new issue