Added SRT input, MP4 output subtitle support, DASH and HLS output subtitle support
This commit is contained in:
parent
b9e261e1ef
commit
e09cd5308e
6 changed files with 374 additions and 133 deletions
|
@ -382,6 +382,8 @@ makeInput(Folder folder)#LTS
|
||||||
makeInput(Balancer balancer)#LTS
|
makeInput(Balancer balancer)#LTS
|
||||||
makeInput(RTSP rtsp)#LTS
|
makeInput(RTSP rtsp)#LTS
|
||||||
|
|
||||||
|
makeInput(SRT srt)#LTS
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# MistServer - Outputs #
|
# MistServer - Outputs #
|
||||||
########################################
|
########################################
|
||||||
|
|
145
src/input/input_srt.cpp
Normal file
145
src/input/input_srt.cpp
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#include "input_srt.h"
|
||||||
|
|
||||||
|
namespace Mist{
|
||||||
|
|
||||||
|
InputSrt::InputSrt(Util::Config *cfg) : Input(cfg){
|
||||||
|
capa["name"] = "SRT";
|
||||||
|
capa["decs"] = "Enables SRT Input";
|
||||||
|
capa["source_match"].append("/*.srt");
|
||||||
|
capa["source_match"].append("/*.vtt");
|
||||||
|
capa["priority"] = 9ll;
|
||||||
|
capa["codecs"][0u][0u].append("subtitle");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSrt::preRun(){
|
||||||
|
fileSource.close();
|
||||||
|
fileSource.open(config->getString("input").c_str());
|
||||||
|
if (!fileSource.is_open()){
|
||||||
|
FAIL_MSG("Could not open file %s: %s", config->getString("input").c_str(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSrt::checkArguments(){
|
||||||
|
if (config->getString("input") == "-"){
|
||||||
|
FAIL_MSG("Reading from standard input not yet supported");
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
preRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config->getString("streamname").size()){
|
||||||
|
if (config->getString("output") == "-"){
|
||||||
|
FAIL_MSG("Writing to standard output not yet supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (config->getString("output") != "-"){
|
||||||
|
FAIL_MSG("File output in player mode not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSrt::readHeader(){
|
||||||
|
if (!fileSource.good()){return false;}
|
||||||
|
|
||||||
|
myMeta.tracks[1].trackID = 1;
|
||||||
|
myMeta.tracks[1].type = "meta";
|
||||||
|
myMeta.tracks[1].codec = "subtitle";
|
||||||
|
|
||||||
|
getNext();
|
||||||
|
while (thisPacket){
|
||||||
|
myMeta.update(thisPacket);
|
||||||
|
getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputting dtsh file
|
||||||
|
myMeta.toFile(config->getString("input") + ".dtsh");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSrt::getNext(bool smart){
|
||||||
|
bool hasPacket = false;
|
||||||
|
|
||||||
|
thisPacket.null();
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
uint32_t index;
|
||||||
|
uint32_t timestamp;
|
||||||
|
uint32_t duration;
|
||||||
|
int lineNr = 0;
|
||||||
|
std::string data;
|
||||||
|
|
||||||
|
while (std::getline(fileSource, line)){// && !line.empty()){
|
||||||
|
|
||||||
|
INFO_MSG("");
|
||||||
|
INFO_MSG("reading line: %s", line.c_str());
|
||||||
|
|
||||||
|
if (line.size() >= 7 && line.substr(0, 7) == "WEBVTT"){
|
||||||
|
vtt = true;
|
||||||
|
std::getline(fileSource, line);
|
||||||
|
lineNr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lineNr++;
|
||||||
|
|
||||||
|
INFO_MSG("linenr: %d", lineNr);
|
||||||
|
if (line.empty() || (line.size() == 1 && line.at(0) == '\r')){
|
||||||
|
static JSON::Value thisPack;
|
||||||
|
thisPack.null();
|
||||||
|
thisPack["trackid"] = 1;
|
||||||
|
thisPack["bpos"] = (long long)fileSource.tellg();
|
||||||
|
thisPack["data"] = data;
|
||||||
|
thisPack["index"] = index;
|
||||||
|
thisPack["time"] = timestamp;
|
||||||
|
thisPack["duration"] = duration;
|
||||||
|
|
||||||
|
// Write the json value to lastpack
|
||||||
|
std::string tmpStr = thisPack.toNetPacked();
|
||||||
|
thisPacket.reInit(tmpStr.data(), tmpStr.size());
|
||||||
|
lineNr = 0;
|
||||||
|
if (vtt){lineNr++;}
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
if (lineNr == 1){
|
||||||
|
index = atoi(line.c_str());
|
||||||
|
}else if (lineNr == 2){
|
||||||
|
// timestamp
|
||||||
|
int from_hour = 0;
|
||||||
|
int from_min = 0;
|
||||||
|
int from_sec = 0;
|
||||||
|
int from_ms = 0;
|
||||||
|
|
||||||
|
int to_hour = 0;
|
||||||
|
int to_min = 0;
|
||||||
|
int to_sec = 0;
|
||||||
|
int to_ms = 0;
|
||||||
|
sscanf(line.c_str(), "%d:%d:%d,%d --> %d:%d:%d,%d", &from_hour, &from_min, &from_sec,
|
||||||
|
&from_ms, &to_hour, &to_min, &to_sec, &to_ms);
|
||||||
|
timestamp =
|
||||||
|
(from_hour * 60 * 60 * 1000) + (from_min * 60 * 1000) + (from_sec * 1000) + from_ms;
|
||||||
|
duration = ((to_hour * 60 * 60 * 1000) + (to_min * 60 * 1000) + (to_sec * 1000) + to_ms) -
|
||||||
|
timestamp;
|
||||||
|
}else{
|
||||||
|
// subtitle
|
||||||
|
if (data.size() > 1){data.append("\n");}
|
||||||
|
data.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thisPacket.null();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSrt::seek(int seekTime){fileSource.seekg(0, fileSource.beg);}
|
||||||
|
|
||||||
|
void InputSrt::trackSelect(std::string trackSpec){
|
||||||
|
// we only have one track..
|
||||||
|
selectedTracks.clear();
|
||||||
|
selectedTracks.insert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}// namespace Mist
|
||||||
|
|
34
src/input/input_srt.h
Normal file
34
src/input/input_srt.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
#include "input.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <mist/dtsc.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Mist{
|
||||||
|
|
||||||
|
class InputSrt : public Input{
|
||||||
|
public:
|
||||||
|
InputSrt(Util::Config *cfg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::ifstream fileSource;
|
||||||
|
|
||||||
|
bool checkArguments();
|
||||||
|
bool readHeader();
|
||||||
|
bool preRun();
|
||||||
|
void getNext(bool smart = true);
|
||||||
|
void seek(int seekTime);
|
||||||
|
void trackSelect(std::string trackSpec);
|
||||||
|
bool vtt = false;
|
||||||
|
|
||||||
|
FILE * inFile;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Mist::InputSrt mistIn;
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace Mist {
|
||||||
MP4::SMHD smhdBox;
|
MP4::SMHD smhdBox;
|
||||||
minfBox.setContent(smhdBox, 2);
|
minfBox.setContent(smhdBox, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mdiaBox.setContent(minfBox, 2);
|
mdiaBox.setContent(minfBox, 2);
|
||||||
trakBox.setContent(mdiaBox, 1);
|
trakBox.setContent(mdiaBox, 1);
|
||||||
moovBox.setContent(trakBox, 3);
|
moovBox.setContent(trakBox, 3);
|
||||||
|
@ -183,6 +184,7 @@ namespace Mist {
|
||||||
tfdtBox.setBaseMediaDecodeTime(Trk.getKey(Trk.fragments[fragIndice].getNumber()).getTime());
|
tfdtBox.setBaseMediaDecodeTime(Trk.getKey(Trk.fragments[fragIndice].getNumber()).getTime());
|
||||||
trafBox.setContent(tfdtBox, 1);
|
trafBox.setContent(tfdtBox, 1);
|
||||||
MP4::TRUN trunBox;
|
MP4::TRUN trunBox;
|
||||||
|
|
||||||
if (Trk.type == "video"){
|
if (Trk.type == "video"){
|
||||||
uint32_t headSize = 0;
|
uint32_t headSize = 0;
|
||||||
if (Trk.codec == "H264"){
|
if (Trk.codec == "H264"){
|
||||||
|
@ -371,6 +373,8 @@ namespace Mist {
|
||||||
uint64_t vidInitTrack = 0;
|
uint64_t vidInitTrack = 0;
|
||||||
uint64_t lastAudTime = 0;
|
uint64_t lastAudTime = 0;
|
||||||
uint64_t audInitTrack = 0;
|
uint64_t audInitTrack = 0;
|
||||||
|
uint64_t subInitTrack = 0;
|
||||||
|
|
||||||
/// \TODO DASH pretends there is only one audio/video track, and then prints them all using the same timing information. This is obviously wrong if the tracks are not in sync.
|
/// \TODO DASH pretends there is only one audio/video track, and then prints them all using the same timing information. This is obviously wrong if the tracks are not in sync.
|
||||||
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it ++){
|
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it ++){
|
||||||
if ((it->second.codec == "H264" || it->second.codec == "HEVC") && it->second.lastms > lastVidTime){
|
if ((it->second.codec == "H264" || it->second.codec == "HEVC") && it->second.lastms > lastVidTime){
|
||||||
|
@ -381,8 +385,12 @@ namespace Mist {
|
||||||
lastAudTime = it->second.lastms;
|
lastAudTime = it->second.lastms;
|
||||||
audInitTrack = it->first;
|
audInitTrack = it->first;
|
||||||
}
|
}
|
||||||
|
if(it->second.codec == "subtitle"){
|
||||||
|
subInitTrack = it->first;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::stringstream r;
|
std::stringstream r;
|
||||||
|
|
||||||
r << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
|
r << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
|
||||||
r << "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" ";
|
r << "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" ";
|
||||||
if (myMeta.vod){
|
if (myMeta.vod){
|
||||||
|
@ -456,6 +464,20 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
r << " </AdaptationSet>" << std::endl;
|
r << " </AdaptationSet>" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(subInitTrack){
|
||||||
|
for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++){
|
||||||
|
if(it->second.codec == "subtitle"){
|
||||||
|
subInitTrack = it->first;
|
||||||
|
std::string lang = (it->second.lang == "" ? "unknown" : it->second.lang);
|
||||||
|
r << "<AdaptationSet group=\"3\" mimeType=\"text/vtt\" lang=\"" << lang << "\">";
|
||||||
|
r << " <Representation id=\"caption_en"<< it->first << "\" bandwidth=\"256\">";
|
||||||
|
r << " <BaseURL>../../" << streamName << ".vtt?track=" << it->first << "</BaseURL>";
|
||||||
|
r << " </Representation></AdaptationSet>" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r << " </Period>" << std::endl;
|
r << " </Period>" << std::endl;
|
||||||
r << "</MPD>" << std::endl;
|
r << "</MPD>" << std::endl;
|
||||||
|
|
||||||
|
@ -474,6 +496,8 @@ namespace Mist {
|
||||||
capa["codecs"][0u][1u].append("AAC");
|
capa["codecs"][0u][1u].append("AAC");
|
||||||
capa["codecs"][0u][1u].append("AC3");
|
capa["codecs"][0u][1u].append("AC3");
|
||||||
capa["codecs"][0u][1u].append("MP3");
|
capa["codecs"][0u][1u].append("MP3");
|
||||||
|
capa["codecs"][0u][2u].append("subtitle");
|
||||||
|
|
||||||
capa["methods"][0u]["handler"] = "http";
|
capa["methods"][0u]["handler"] = "http";
|
||||||
capa["methods"][0u]["type"] = "dash/video/mp4";
|
capa["methods"][0u]["type"] = "dash/video/mp4";
|
||||||
capa["methods"][0u]["priority"] = 8ll;
|
capa["methods"][0u]["priority"] = 8ll;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "output_hls.h"
|
#include "output_hls.h"
|
||||||
#include <mist/stream.h>
|
#include <mist/stream.h>
|
||||||
|
#include <mist/langcodes.h> /*LTS*/
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace Mist {
|
namespace Mist {
|
||||||
|
|
|
@ -86,6 +86,12 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thisTrack.type == "meta"){
|
||||||
|
tmpRes += 12 //NMHD Box
|
||||||
|
+ 16//STSD
|
||||||
|
+ 64; //tx3g Box
|
||||||
|
}
|
||||||
|
|
||||||
if (!fragmented){
|
if (!fragmented){
|
||||||
//Unfortunately, for our STTS and CTTS boxes, we need to loop through all parts of the track
|
//Unfortunately, for our STTS and CTTS boxes, we need to loop through all parts of the track
|
||||||
uint64_t sttsCount = 1;
|
uint64_t sttsCount = 1;
|
||||||
|
@ -131,7 +137,6 @@ namespace Mist {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///\todo This function does not indicate errors anywhere... maybe fix this...
|
///\todo This function does not indicate errors anywhere... maybe fix this...
|
||||||
std::string OutProgressiveMP4::DTSCMeta2MP4Header(uint64_t & size, int fragmented){
|
std::string OutProgressiveMP4::DTSCMeta2MP4Header(uint64_t & size, int fragmented){
|
||||||
if (myMeta.live){
|
if (myMeta.live){
|
||||||
|
@ -146,7 +151,6 @@ namespace Mist {
|
||||||
//Keeps track of the total size of the mdat box
|
//Keeps track of the total size of the mdat box
|
||||||
uint64_t mdatSize = 0;
|
uint64_t mdatSize = 0;
|
||||||
|
|
||||||
|
|
||||||
//Start actually creating the header
|
//Start actually creating the header
|
||||||
|
|
||||||
//MP4 Files always start with an FTYP box. Constructor sets default values
|
//MP4 Files always start with an FTYP box. Constructor sets default values
|
||||||
|
@ -162,7 +166,6 @@ namespace Mist {
|
||||||
//Keep track of the current index within the moovBox
|
//Keep track of the current index within the moovBox
|
||||||
unsigned int moovOffset = 0;
|
unsigned int moovOffset = 0;
|
||||||
|
|
||||||
|
|
||||||
//Construct with duration of -1, as this is the default for fragmented
|
//Construct with duration of -1, as this is the default for fragmented
|
||||||
MP4::MVHD mvhdBox(-1);
|
MP4::MVHD mvhdBox(-1);
|
||||||
//Then override it only when we are not sending a fragmented file
|
//Then override it only when we are not sending a fragmented file
|
||||||
|
@ -224,6 +227,9 @@ namespace Mist {
|
||||||
MP4::MINF minfBox;
|
MP4::MINF minfBox;
|
||||||
size_t minfOffset = 0;
|
size_t minfOffset = 0;
|
||||||
|
|
||||||
|
MP4::STBL stblBox;
|
||||||
|
unsigned int stblOffset = 0;
|
||||||
|
|
||||||
//Add a track-type specific box to the MINF box
|
//Add a track-type specific box to the MINF box
|
||||||
if (thisTrack.type == "video"){
|
if (thisTrack.type == "video"){
|
||||||
MP4::VMHD vmhdBox;
|
MP4::VMHD vmhdBox;
|
||||||
|
@ -232,6 +238,10 @@ namespace Mist {
|
||||||
}else if (thisTrack.type == "audio"){
|
}else if (thisTrack.type == "audio"){
|
||||||
MP4::SMHD smhdBox;
|
MP4::SMHD smhdBox;
|
||||||
minfBox.setContent(smhdBox, minfOffset++);
|
minfBox.setContent(smhdBox, minfOffset++);
|
||||||
|
}else{
|
||||||
|
//create nmhd box
|
||||||
|
MP4::NMHD nmhdBox;
|
||||||
|
minfBox.setContent(nmhdBox, minfOffset++);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add the mandatory DREF (dataReference) box
|
//Add the mandatory DREF (dataReference) box
|
||||||
|
@ -240,10 +250,6 @@ namespace Mist {
|
||||||
dinfBox.setContent(drefBox, 0);
|
dinfBox.setContent(drefBox, 0);
|
||||||
minfBox.setContent(dinfBox, minfOffset++);
|
minfBox.setContent(dinfBox, minfOffset++);
|
||||||
|
|
||||||
|
|
||||||
MP4::STBL stblBox;
|
|
||||||
size_t stblOffset = 0;
|
|
||||||
|
|
||||||
//Add STSD box
|
//Add STSD box
|
||||||
MP4::STSD stsdBox(0);
|
MP4::STSD stsdBox(0);
|
||||||
if (thisTrack.type == "video"){
|
if (thisTrack.type == "video"){
|
||||||
|
@ -252,9 +258,16 @@ namespace Mist {
|
||||||
}else if (thisTrack.type == "audio"){
|
}else if (thisTrack.type == "audio"){
|
||||||
MP4::AudioSampleEntry sampleEntry(thisTrack);
|
MP4::AudioSampleEntry sampleEntry(thisTrack);
|
||||||
stsdBox.setEntry(sampleEntry, 0);
|
stsdBox.setEntry(sampleEntry, 0);
|
||||||
}
|
}else if (thisTrack.type == "meta"){
|
||||||
stblBox.setContent(stsdBox, stblOffset++);
|
INFO_MSG("add subtitlesample\n");
|
||||||
|
MP4::TextSampleEntry sampleEntry(thisTrack);
|
||||||
|
|
||||||
|
MP4::FontTableBox ftab;
|
||||||
|
sampleEntry.setFontTableBox(ftab);
|
||||||
|
stsdBox.setEntry(sampleEntry, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
stblBox.setContent(stsdBox, stblOffset++);
|
||||||
|
|
||||||
//Add STTS Box
|
//Add STTS Box
|
||||||
//note: STTS is empty when fragmented
|
//note: STTS is empty when fragmented
|
||||||
|
@ -267,7 +280,6 @@ namespace Mist {
|
||||||
MP4::CTTS cttsBox;
|
MP4::CTTS cttsBox;
|
||||||
cttsBox.setVersion(0);
|
cttsBox.setVersion(0);
|
||||||
|
|
||||||
|
|
||||||
MP4::CTTSEntry tmpEntry;
|
MP4::CTTSEntry tmpEntry;
|
||||||
tmpEntry.sampleCount = 0;
|
tmpEntry.sampleCount = 0;
|
||||||
tmpEntry.sampleOffset = thisTrack.parts[0].getOffset();
|
tmpEntry.sampleOffset = thisTrack.parts[0].getOffset();
|
||||||
|
@ -290,6 +302,10 @@ namespace Mist {
|
||||||
//Update the counter
|
//Update the counter
|
||||||
sttsCounter.rbegin()->first++;
|
sttsCounter.rbegin()->first++;
|
||||||
|
|
||||||
|
if(thisTrack.type == "meta"){
|
||||||
|
partSize += 2;
|
||||||
|
}
|
||||||
|
|
||||||
stszBox.setEntrySize(partSize, part);
|
stszBox.setEntrySize(partSize, part);
|
||||||
size += partSize;
|
size += partSize;
|
||||||
|
|
||||||
|
@ -338,7 +354,6 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
stblBox.setContent(stscBox, stblOffset++);
|
stblBox.setContent(stscBox, stblOffset++);
|
||||||
|
|
||||||
|
|
||||||
//Create STCO Box (either stco or co64)
|
//Create STCO Box (either stco or co64)
|
||||||
//note: 64bit boxes will never be used in fragmented
|
//note: 64bit boxes will never be used in fragmented
|
||||||
//note: Inserting empty values on purpose here, will be fixed later.
|
//note: Inserting empty values on purpose here, will be fixed later.
|
||||||
|
@ -377,7 +392,6 @@ namespace Mist {
|
||||||
//initial offset length ftyp, length moov + 8
|
//initial offset length ftyp, length moov + 8
|
||||||
uint64_t dataOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
uint64_t dataOffset = ftypBox.boxedSize() + moovBox.boxedSize() + 8;
|
||||||
|
|
||||||
|
|
||||||
std::map <size_t, MP4::STCO> checkStcoBoxes;
|
std::map <size_t, MP4::STCO> checkStcoBoxes;
|
||||||
std::map <size_t, MP4::CO64> checkCO64Boxes;
|
std::map <size_t, MP4::CO64> checkCO64Boxes;
|
||||||
|
|
||||||
|
@ -423,6 +437,10 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
dataSize += thisTrack.parts[temp.index].getSize();
|
dataSize += thisTrack.parts[temp.index].getSize();
|
||||||
|
|
||||||
|
if(thisTrack.type == "meta"){
|
||||||
|
dataSize += 2;
|
||||||
|
}
|
||||||
|
|
||||||
//add next keyPart to sortSet
|
//add next keyPart to sortSet
|
||||||
if (temp.index + 1< thisTrack.parts.size()){//Only create new element, when there are new elements to be added
|
if (temp.index + 1< thisTrack.parts.size()){//Only create new element, when there are new elements to be added
|
||||||
temp.time += thisTrack.parts[temp.index].getDuration();
|
temp.time += thisTrack.parts[temp.index].getDuration();
|
||||||
|
@ -473,6 +491,11 @@ namespace Mist {
|
||||||
DTSC::Track & thisTrack = myMeta.tracks[temp.trackID];
|
DTSC::Track & thisTrack = myMeta.tracks[temp.trackID];
|
||||||
uint64_t partSize = thisTrack.parts[temp.index].getSize();
|
uint64_t partSize = thisTrack.parts[temp.index].getSize();
|
||||||
|
|
||||||
|
//add 2 bytes in front of the subtitle that contains the length of the subtitle.
|
||||||
|
if(myMeta.tracks[temp.trackID].codec == "subtitle"){
|
||||||
|
partSize += 2;
|
||||||
|
}
|
||||||
|
|
||||||
//record where we are
|
//record where we are
|
||||||
seekPoint = temp.time;
|
seekPoint = temp.time;
|
||||||
//substract the size of this fragment from byteStart
|
//substract the size of this fragment from byteStart
|
||||||
|
@ -482,7 +505,6 @@ namespace Mist {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
byteStart -= partSize;
|
byteStart -= partSize;
|
||||||
|
|
||||||
//otherwise, set currPos to where we are now and continue
|
//otherwise, set currPos to where we are now and continue
|
||||||
|
@ -758,6 +780,7 @@ namespace Mist {
|
||||||
realTime = 0;
|
realTime = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*LTS-END*/
|
/*LTS-END*/
|
||||||
|
|
||||||
//Make sure we start receiving data after this function
|
//Make sure we start receiving data after this function
|
||||||
|
@ -920,8 +943,7 @@ namespace Mist {
|
||||||
char * dataPointer = 0;
|
char * dataPointer = 0;
|
||||||
unsigned int len = 0;
|
unsigned int len = 0;
|
||||||
thisPacket.getString("data", dataPointer, len);
|
thisPacket.getString("data", dataPointer, len);
|
||||||
|
std::string subtitle;
|
||||||
|
|
||||||
|
|
||||||
if (myMeta.live){
|
if (myMeta.live){
|
||||||
//if header needed
|
//if header needed
|
||||||
|
@ -944,6 +966,7 @@ namespace Mist {
|
||||||
partListSent++;
|
partListSent++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
keyPart thisPart = *sortSet.begin();
|
keyPart thisPart = *sortSet.begin();
|
||||||
if ((unsigned long)thisPacket.getTrackId() != thisPart.trackID || thisPacket.getTime() != thisPart.time || len != thisPart.size){
|
if ((unsigned long)thisPacket.getTrackId() != thisPart.trackID || thisPacket.getTime() != thisPart.time || len != thisPart.size){
|
||||||
if (thisPacket.getTime() > sortSet.begin()->time || thisPacket.getTrackId() > sortSet.begin()->trackID){
|
if (thisPacket.getTime() > sortSet.begin()->time || thisPacket.getTrackId() > sortSet.begin()->trackID){
|
||||||
|
@ -964,6 +987,17 @@ namespace Mist {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//prepend subtitle text with 2 bytes datalength
|
||||||
|
if(myMeta.tracks[thisPacket.getTrackId()].codec == "subtitle"){
|
||||||
|
char pre[2];
|
||||||
|
Bit::htobs(pre,len);
|
||||||
|
subtitle.assign(pre,2);
|
||||||
|
subtitle.append(dataPointer, len);
|
||||||
|
dataPointer = (char*)subtitle.c_str();
|
||||||
|
len+=2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (currPos >= byteStart){
|
if (currPos >= byteStart){
|
||||||
myConn.SendNow(dataPointer, std::min(leftOver, (int64_t)len));
|
myConn.SendNow(dataPointer, std::min(leftOver, (int64_t)len));
|
||||||
leftOver -= len;
|
leftOver -= len;
|
||||||
|
@ -1024,3 +1058,4 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue