Reworked existing subtitle support (sideloaded, MP4 in and srt out)
This commit is contained in:
parent
741c4755cc
commit
b9e261e1ef
7 changed files with 159 additions and 33 deletions
38
lib/subtitles.cpp
Normal file
38
lib/subtitles.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "subtitles.h"
|
||||
#include "bitfields.h"
|
||||
|
||||
#include "defines.h"
|
||||
namespace Subtitle {
|
||||
|
||||
Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta) {
|
||||
char * tmp = 0;
|
||||
uint16_t length = 0;
|
||||
unsigned int len;
|
||||
|
||||
Packet output;
|
||||
long int trackId= packet.getTrackId();
|
||||
if(meta.tracks[trackId].codec != "TTXT" && meta.tracks[trackId].codec != "SRT") {
|
||||
//no subtitle track
|
||||
return output;
|
||||
}
|
||||
|
||||
if(packet.hasMember("duration")) {
|
||||
output.duration = packet.getInt("duration");
|
||||
} else {
|
||||
//get parts from meta
|
||||
//calculate duration
|
||||
|
||||
}
|
||||
|
||||
packet.getString("data", output.subtitle);
|
||||
if(meta.tracks[trackId].codec == "TTXT") {
|
||||
unsigned short size = Bit::btohs(output.subtitle.c_str());
|
||||
output.subtitle = output.subtitle.substr(2,size);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
15
lib/subtitles.h
Normal file
15
lib/subtitles.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "dtsc.h"
|
||||
|
||||
namespace Subtitle {
|
||||
|
||||
struct Packet {
|
||||
std::string subtitle;
|
||||
uint64_t duration;
|
||||
};
|
||||
|
||||
Packet getSubtitle(DTSC::Packet packet, DTSC::Meta meta);
|
||||
|
||||
}
|
||||
|
|
@ -131,8 +131,8 @@ namespace Mist {
|
|||
srtTrack = myMeta.tracks.rbegin()->first + 1;
|
||||
|
||||
myMeta.tracks[srtTrack].trackID = srtTrack;
|
||||
myMeta.tracks[srtTrack].type = "subtitle";
|
||||
myMeta.tracks[srtTrack].codec = "srt";
|
||||
myMeta.tracks[srtTrack].type = "meta";
|
||||
myMeta.tracks[srtTrack].codec = "subtitle";
|
||||
|
||||
getNextSrt();
|
||||
while (srtPack){
|
||||
|
|
|
@ -325,8 +325,8 @@ namespace Mist {
|
|||
}
|
||||
|
||||
if (sType == "tx3g"){//plain text subtitles
|
||||
myMeta.tracks[trackNo].type = "subtitle";
|
||||
myMeta.tracks[trackNo].codec = "TTXT";
|
||||
myMeta.tracks[trackNo].type = "meta";
|
||||
myMeta.tracks[trackNo].codec = "subtitle";
|
||||
}
|
||||
|
||||
MP4::STSS stssBox = stblBox.getChild<MP4::STSS>();
|
||||
|
@ -407,9 +407,23 @@ namespace Mist {
|
|||
}else{
|
||||
BsetPart.timeOffset = 0;
|
||||
}
|
||||
|
||||
if(sType == "tx3g"){
|
||||
if(stszBox.getEntrySize(stszIndex) <=2 && false){
|
||||
FAIL_MSG("size <=2");
|
||||
}else{
|
||||
long long packSendSize = 0;
|
||||
packSendSize = 24 + (BsetPart.timeOffset ? 17 : 0) + (BsetPart.bpos ? 15 : 0) + 19 +
|
||||
stszBox.getEntrySize(stszIndex) + 11-2 + 19;
|
||||
myMeta.update(BsetPart.time, BsetPart.timeOffset, trackNo,
|
||||
stszBox.getEntrySize(stszIndex) -2 , BsetPart.bpos, true,
|
||||
packSendSize);
|
||||
}
|
||||
}else{
|
||||
myMeta.update(BsetPart.time, BsetPart.timeOffset, trackNo, stszBox.getEntrySize(stszIndex), BsetPart.bpos, BsetPart.keyframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!MP4::skipBox(inFile)){//moving on to next box
|
||||
|
@ -459,13 +473,31 @@ namespace Mist {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (myMeta.tracks[curPart.trackID].codec == "TTXT"){
|
||||
if (myMeta.tracks[curPart.trackID].codec == "subtitle"){
|
||||
unsigned int txtLen = Bit::btohs(data);
|
||||
if (!txtLen){
|
||||
thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, " ", 1, 0/*Note: no bpos*/, isKeyframe);
|
||||
if (!txtLen && false ){
|
||||
curPart.index ++;
|
||||
return getNext(smart);
|
||||
//thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, " ", 1, 0/*Note: no bpos*/, isKeyframe);
|
||||
}else{
|
||||
thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, data+2, txtLen, 0/*Note: no bpos*/, isKeyframe);
|
||||
|
||||
static JSON::Value thisPack;
|
||||
thisPack.null();
|
||||
thisPack["trackid"] = (long long)curPart.trackID;
|
||||
thisPack["bpos"] = (long long)curPart.bpos; //(long long)fileSource.tellg();
|
||||
thisPack["data"] = std::string(data+2,txtLen);
|
||||
// thisPack["index"] = index;
|
||||
thisPack["time"] = (long long)curPart.time;
|
||||
thisPack["duration"] = 1000;
|
||||
|
||||
// thisPack["time"] = (long long)timestamp;
|
||||
thisPack["keyframe"] = true;
|
||||
// Write the json value to lastpack
|
||||
std::string tmpStr = thisPack.toNetPacked();
|
||||
thisPacket.reInit(tmpStr.data(), tmpStr.size());
|
||||
//return;
|
||||
|
||||
//thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, data+2, txtLen, 0/*Note: no bpos*/, isKeyframe);
|
||||
}
|
||||
}else{
|
||||
thisPacket.genericFill(curPart.time, curPart.offset, curPart.trackID, data, curPart.size, 0/*Note: no bpos*/, isKeyframe);
|
||||
|
|
|
@ -35,12 +35,19 @@ namespace Mist {
|
|||
if (audioId != -1) {
|
||||
bWidth += myMeta.tracks[audioId].bps;
|
||||
}
|
||||
result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (bWidth * 8) << "\r\n";
|
||||
result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,SUBTITLES=\"sub1\",BANDWIDTH=" << (bWidth * 8) << "\r\n";
|
||||
result << it->first;
|
||||
if (audioId != -1) {
|
||||
result << "_" << audioId;
|
||||
}
|
||||
result << "/index.m3u8?sessId=" << getpid() << "\r\n";
|
||||
}else if(it->second.codec == "subtitle"){
|
||||
|
||||
if(it->second.lang.empty()){
|
||||
it->second.lang = "und";
|
||||
}
|
||||
|
||||
result << "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"sub1\",LANGUAGE=\"" << it->second.lang << "\",NAME=\"" << Encodings::ISO639::decode(it->second.lang) << "\",AUTOSELECT=NO,DEFAULT=NO,FORCED=NO,URI=\"" << it->first << "/index.m3u8\"" << "\r\n";
|
||||
}
|
||||
}
|
||||
if (!vidTracks && audioId) {
|
||||
|
@ -145,11 +152,16 @@ namespace Mist {
|
|||
duration = myMeta.tracks[tid].lastms - starttime;
|
||||
}
|
||||
char lineBuf[400];
|
||||
|
||||
if(myMeta.tracks[tid].codec == "subtitle"){
|
||||
snprintf(lineBuf, 400, "#EXTINF:%f,\r\n../../../%s.vtt?track=%d&from=%lld&to=%lld\r\n", streamName.c_str(),(double)duration/1000,tid, starttime, starttime + duration);
|
||||
}else{
|
||||
if (sessId.size()){
|
||||
snprintf(lineBuf, 400, "#EXTINF:%f,\r\n%lld_%lld.ts?sessId=%s\r\n", (double)duration/1000, starttime, starttime + duration, sessId.c_str());
|
||||
}else{
|
||||
snprintf(lineBuf, 400, "#EXTINF:%f,\r\n%lld_%lld.ts\r\n", (double)duration/1000, starttime, starttime + duration);
|
||||
}
|
||||
}
|
||||
durs.push_back(duration);
|
||||
total_dur += duration;
|
||||
lines.push_back(lineBuf);
|
||||
|
|
|
@ -14,8 +14,7 @@ namespace Mist {
|
|||
capa["desc"] = "Enables HTTP protocol subtitle streaming in subrip and WebVTT formats.";
|
||||
capa["url_match"].append("/$.srt");
|
||||
capa["url_match"].append("/$.vtt");
|
||||
capa["codecs"][0u][0u].append("srt");
|
||||
capa["codecs"][0u][0u].append("TTXT");
|
||||
capa["codecs"][0u][0u].append("subtitle");
|
||||
capa["methods"][0u]["handler"] = "http";
|
||||
capa["methods"][0u]["type"] = "html5/text/plain";
|
||||
capa["methods"][0u]["priority"] = 8ll;
|
||||
|
@ -30,6 +29,7 @@ namespace Mist {
|
|||
char * dataPointer = 0;
|
||||
unsigned int len = 0;
|
||||
thisPacket.getString("data", dataPointer, len);
|
||||
// INFO_MSG("getting sub: %s", dataPointer);
|
||||
//ignore empty subs
|
||||
if (len == 0 || (len == 1 && dataPointer[0] == ' ')){
|
||||
return;
|
||||
|
@ -39,6 +39,20 @@ namespace Mist {
|
|||
tmp << lastNum++ << std::endl;
|
||||
}
|
||||
long long unsigned int time = thisPacket.getTime();
|
||||
|
||||
|
||||
//filter subtitle in specific timespan
|
||||
if(filter_from > 0 && time < filter_from){
|
||||
index++; //when using seek, the index is lost.
|
||||
seek(filter_from);
|
||||
return;
|
||||
}
|
||||
|
||||
if(filter_to > 0 && time > filter_to && filter_to > filter_from){
|
||||
config->is_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
char tmpBuf[50];
|
||||
int tmpLen = sprintf(tmpBuf, "%.2llu:%.2llu:%.2llu.%.3llu", (time / 3600000), ((time % 3600000) / 60000), (((time % 3600000) % 60000) / 1000), time % 1000);
|
||||
tmp.write(tmpBuf, tmpLen);
|
||||
|
@ -79,6 +93,18 @@ namespace Mist {
|
|||
selectedTracks.clear();
|
||||
selectedTracks.insert(JSON::Value(H.GetVar("track")).asInt());
|
||||
}
|
||||
|
||||
filter_from = 0;
|
||||
filter_to = 0;
|
||||
index = 0;
|
||||
|
||||
if (H.GetVar("from") != ""){
|
||||
filter_from = JSON::Value(H.GetVar("from")).asInt();
|
||||
}
|
||||
if (H.GetVar("to") != ""){
|
||||
filter_to = JSON::Value(H.GetVar("to")).asInt();
|
||||
}
|
||||
|
||||
H.Clean();
|
||||
H.setCORSHeaders();
|
||||
if(method == "OPTIONS" || method == "HEAD"){
|
||||
|
|
|
@ -13,6 +13,9 @@ namespace Mist {
|
|||
protected:
|
||||
bool webVTT;
|
||||
int lastNum;
|
||||
uint32_t filter_from;
|
||||
uint32_t filter_to;
|
||||
uint32_t index;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue