TS MPEG2/MP2 support

This commit is contained in:
Erik Zandvliet 2017-07-28 11:59:30 +02:00 committed by Thulinma
parent 9c2bd38611
commit 2a721f5e7f
7 changed files with 200 additions and 97 deletions

View file

@ -527,9 +527,13 @@ namespace TS {
/// \param len The length of this frame. /// \param len The length of this frame.
/// \param PTS The timestamp of the frame. /// \param PTS The timestamp of the frame.
std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps) { std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps) {
if (len){
len += (offset ? 13 : 8); len += (offset ? 13 : 8);
}
if (bps >= 50){ if (bps >= 50){
if (len){
len += 3; len += 3;
}
}else{ }else{
bps = 0; bps = 0;
} }
@ -826,7 +830,7 @@ namespace TS {
case 0x15: return "meta PES"; case 0x15: return "meta PES";
case 0x16: return "meta section"; case 0x16: return "meta section";
case 0x1B: return "H264"; case 0x1B: return "H264";
case 0x24: return "H265"; case 0x24: return "HEVC";
case 0x81: return "AC3"; case 0x81: return "AC3";
default: return "unknown"; default: return "unknown";
} }
@ -1219,6 +1223,8 @@ namespace TS {
entry.setStreamType(0x1B); entry.setStreamType(0x1B);
}else if (myMeta.tracks[*it].codec == "HEVC"){ }else if (myMeta.tracks[*it].codec == "HEVC"){
entry.setStreamType(0x24); entry.setStreamType(0x24);
}else if (myMeta.tracks[*it].codec == "MPEG2"){
entry.setStreamType(0x02);
}else if (myMeta.tracks[*it].codec == "AAC"){ }else if (myMeta.tracks[*it].codec == "AAC"){
entry.setStreamType(0x0F); entry.setStreamType(0x0F);
std::string aac_info("\174\002\121\000", 4);//AAC descriptor: AAC Level 2. Hardcoded, because... what are AAC levels, anyway? std::string aac_info("\174\002\121\000", 4);//AAC descriptor: AAC Level 2. Hardcoded, because... what are AAC levels, anyway?
@ -1229,7 +1235,7 @@ namespace TS {
aac_info.append("\000", 1); aac_info.append("\000", 1);
} }
entry.setESInfo(aac_info); entry.setESInfo(aac_info);
}else if (myMeta.tracks[*it].codec == "MP3"){ }else if (myMeta.tracks[*it].codec == "MP3" || myMeta.tracks[*it].codec == "MP2"){
entry.setStreamType(0x03); entry.setStreamType(0x03);
}else if (myMeta.tracks[*it].codec == "AC3"){ }else if (myMeta.tracks[*it].codec == "AC3"){
entry.setStreamType(0x81); entry.setStreamType(0x81);

View file

@ -6,6 +6,8 @@
#include "nal.h" #include "nal.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <stdint.h> #include <stdint.h>
#include "mpeg.h"
namespace TS{ namespace TS{
@ -187,6 +189,8 @@ namespace TS{
case H265: case H265:
case AC3: case AC3:
case ID3: case ID3:
case MP2:
case MPEG2:
pidToCodec[pid] = sType; pidToCodec[pid] = sType;
if (sType == ID3){ if (sType == ID3){
metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength()); metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength());
@ -517,10 +521,13 @@ namespace TS{
} }
} }
} }
if (thisCodec == ID3 || thisCodec == AC3){ if (thisCodec == ID3 || thisCodec == AC3 || thisCodec == MP2){
out.push_back(DTSC::Packet()); out.push_back(DTSC::Packet());
out.back().genericFill(timeStamp, timeOffset, tid, pesPayload, realPayloadSize, out.back().genericFill(timeStamp, timeOffset, tid, pesPayload, realPayloadSize,
bPos, 0); bPos, 0);
if (thisCodec == MP2 && !mp2Hdr.count(tid)){
mp2Hdr[tid] = std::string(pesPayload, realPayloadSize);
}
} }
@ -626,6 +633,37 @@ namespace TS{
nextPtr = nalu::scanAnnexB(pesPayload, realPayloadSize); nextPtr = nalu::scanAnnexB(pesPayload, realPayloadSize);
} }
} }
if (thisCodec == MPEG2){
const char *origBegin = pesPayload;
size_t origSize = realPayloadSize;
const char *nextPtr;
const char *pesEnd = pesPayload+realPayloadSize;
uint32_t nalSize = 0;
bool isKeyFrame = false;
nextPtr = nalu::scanAnnexB(pesPayload, realPayloadSize);
if (!nextPtr){
WARN_MSG("No start code found in entire PES packet!");
return;
}
while (nextPtr < pesEnd){
if (!nextPtr){nextPtr = pesEnd;}
//Calculate size of NAL unit, removing null bytes from the end
nalSize = nalu::nalEndPosition(pesPayload, nextPtr - pesPayload) - pesPayload;
// Check if this is a keyframe
parseNal(tid, pesPayload, nextPtr, isKeyFrame);
if (((nextPtr - pesPayload) + 3) >= realPayloadSize){break;}//end of the loop
realPayloadSize -= ((nextPtr - pesPayload) + 3); // decrease the total size
pesPayload = nextPtr + 3;
nextPtr = nalu::scanAnnexB(pesPayload, realPayloadSize);
}
out.push_back(DTSC::Packet());
out.back().genericFill(timeStamp, timeOffset, tid, origBegin, origSize, bPos, isKeyFrame);
}
} }
void Stream::getPacket(unsigned long tid, DTSC::Packet &pack){ void Stream::getPacket(unsigned long tid, DTSC::Packet &pack){
@ -660,11 +698,27 @@ namespace TS{
bool firstSlice = true; bool firstSlice = true;
char typeNal; char typeNal;
isKeyFrame = false;
if (pidToCodec[tid] == MPEG2){ if (pidToCodec[tid] == MPEG2){
typeNal = pesPayload[0];
switch (typeNal){
case 0xB3:
if (!mpeg2SeqHdr.count(tid)){
mpeg2SeqHdr[tid] = std::string(pesPayload, (nextPtr - pesPayload));
}
break;
case 0xB5:
if (!mpeg2SeqExt.count(tid)){
mpeg2SeqExt[tid] = std::string(pesPayload, (nextPtr - pesPayload));
}
break;
case 0xB8:
isKeyFrame = true;
break;
}
return; return;
} }
isKeyFrame = false;
if (pidToCodec[tid] == H264){ if (pidToCodec[tid] == H264){
typeNal = pesPayload[0] & 0x1F; typeNal = pesPayload[0] & 0x1F;
switch (typeNal){ switch (typeNal){
@ -816,6 +870,17 @@ namespace TS{
} }
} }
}break; }break;
case MPEG2:{
meta.tracks[mId].type = "video";
meta.tracks[mId].codec = "MPEG2";
meta.tracks[mId].trackID = mId;
meta.tracks[mId].init = std::string("\000\000\001", 3) + mpeg2SeqHdr[it->first] + std::string("\000\000\001", 3) + mpeg2SeqExt[it->first];
Mpeg::MPEG2Info info = Mpeg::parseMPEG2Header(meta.tracks[mId].init);
meta.tracks[mId].width = info.width;
meta.tracks[mId].height = info.height;
meta.tracks[mId].fpks = info.fps * 1000;
}break;
case ID3:{ case ID3:{
meta.tracks[mId].type = "meta"; meta.tracks[mId].type = "meta";
meta.tracks[mId].codec = "ID3"; meta.tracks[mId].codec = "ID3";
@ -831,6 +896,18 @@ namespace TS{
meta.tracks[mId].rate = 0; meta.tracks[mId].rate = 0;
meta.tracks[mId].channels = 0; meta.tracks[mId].channels = 0;
}break; }break;
case MP2:{
meta.tracks[mId].type = "audio";
meta.tracks[mId].codec = "MP2";
meta.tracks[mId].trackID = mId;
Mpeg::MP2Info info = Mpeg::parseMP2Header(mp2Hdr[it->first]);
meta.tracks[mId].rate = info.sampleRate;
meta.tracks[mId].channels = info.channels;
///\todo Fix this value
meta.tracks[mId].size = 0;
}break;
case AAC:{ case AAC:{
meta.tracks[mId].type = "audio"; meta.tracks[mId].type = "audio";
meta.tracks[mId].codec = "AAC"; meta.tracks[mId].codec = "AAC";
@ -887,7 +964,10 @@ namespace TS{
case AAC: case AAC:
case H265: case H265:
case AC3: case AC3:
case ID3: result.insert(entry.getElementaryPid()); break; case ID3:
case MP2:
case MPEG2:
result.insert(entry.getElementaryPid()); break;
default: break; default: break;
} }
entry.advance(); entry.advance();

View file

@ -9,7 +9,7 @@
#include "shared_memory.h" #include "shared_memory.h"
namespace TS{ namespace TS{
enum codecType{H264 = 0x1B, AAC = 0x0F, AC3 = 0x81, MP3 = 0x03, H265 = 0x24, ID3 = 0x15}; enum codecType{H264 = 0x1B, AAC = 0x0F, AC3 = 0x81, MP3 = 0x03, H265 = 0x24, ID3 = 0x15, MPEG2 = 0x02, MP2 = 0x03};
class ADTSRemainder{ class ADTSRemainder{
private: private:
@ -80,6 +80,9 @@ namespace TS{
std::map<unsigned long, std::string> metaInit; std::map<unsigned long, std::string> metaInit;
std::map<unsigned long, std::string> descriptors; std::map<unsigned long, std::string> descriptors;
std::map<unsigned long, uint32_t> seenUnitStart; std::map<unsigned long, uint32_t> seenUnitStart;
std::map<unsigned long, std::string> mpeg2SeqHdr;
std::map<unsigned long, std::string> mpeg2SeqExt;
std::map<unsigned long, std::string> mp2Hdr;
mutable tthread::recursive_mutex tMutex; mutable tthread::recursive_mutex tMutex;
bool threaded; bool threaded;

View file

@ -123,8 +123,10 @@ namespace Mist {
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("HEVC"); capa["codecs"][0u][0u].append("HEVC");
capa["codecs"][0u][0u].append("MPEG2");
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("MP2");
inFile = NULL; inFile = NULL;
inputProcess = 0; inputProcess = 0;
} }

View file

@ -40,9 +40,11 @@ namespace Mist {
capa["socket"] = "http_ts"; capa["socket"] = "http_ts";
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("HEVC"); capa["codecs"][0u][0u].append("HEVC");
capa["codecs"][0u][0u].append("MPEG2");
capa["codecs"][0u][1u].append("AAC"); capa["codecs"][0u][1u].append("AAC");
capa["codecs"][0u][1u].append("MP3"); capa["codecs"][0u][1u].append("MP3");
capa["codecs"][0u][1u].append("AC3"); capa["codecs"][0u][1u].append("AC3");
capa["codecs"][0u][1u].append("MP2");
capa["methods"][0u]["handler"] = "http"; capa["methods"][0u]["handler"] = "http";
capa["methods"][0u]["type"] = "html5/video/mpeg"; capa["methods"][0u]["type"] = "html5/video/mpeg";
capa["methods"][0u]["priority"] = 1ll; capa["methods"][0u]["priority"] = 1ll;

View file

@ -80,9 +80,11 @@ namespace Mist {
capa["optional"]["tracks"]["default"] = ""; capa["optional"]["tracks"]["default"] = "";
capa["codecs"][0u][0u].append("HEVC"); capa["codecs"][0u][0u].append("HEVC");
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("MPEG2");
capa["codecs"][0u][1u].append("AAC"); capa["codecs"][0u][1u].append("AAC");
capa["codecs"][0u][1u].append("MP3"); capa["codecs"][0u][1u].append("MP3");
capa["codecs"][0u][1u].append("AC3"); capa["codecs"][0u][1u].append("AC3");
capa["codecs"][0u][1u].append("MP2");
cfg->addConnectorOptions(8888, capa); cfg->addConnectorOptions(8888, capa);
config = cfg; config = cfg;
capa["push_urls"].append("tsudp://*"); capa["push_urls"].append("tsudp://*");

View file

@ -81,6 +81,7 @@ namespace Mist {
std::string bs; std::string bs;
//prepare bufferstring //prepare bufferstring
if (video){ if (video){
if (Trk.codec == "H264" || Trk.codec == "HEVC"){
unsigned int extraSize = 0; unsigned int extraSize = 0;
//dataPointer[4] & 0x1f is used to check if this should be done later: fillPacket("\000\000\000\001\011\360", 6); //dataPointer[4] & 0x1f is used to check if this should be done later: fillPacket("\000\000\000\001\011\360", 6);
if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){ if (Trk.codec == "H264" && (dataPointer[4] & 0x1f) != 0x09){
@ -184,12 +185,19 @@ namespace Mist {
} }
currPack++; currPack++;
} }
}else{
uint64_t offset = thisPacket.getInt("offset") * 90;
bs = TS::Packet::getPESVideoLeadIn(0, packTime, offset, true, Trk.bps);
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
fillPacket(dataPointer, dataLen, firstPack, video, keyframe, pkgPid, contPkg);
}
}else if (Trk.type == "audio"){ }else if (Trk.type == "audio"){
long unsigned int tempLen = dataLen; long unsigned int tempLen = dataLen;
if (Trk.codec == "AAC"){ if (Trk.codec == "AAC"){
tempLen += 7; tempLen += 7;
} }
bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, Trk.bps);// myMeta.tracks[thisPacket.getTrackId()].rate / 1000 ); bs = TS::Packet::getPESAudioLeadIn(tempLen, packTime, Trk.bps);
fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg); fillPacket(bs.data(), bs.size(), firstPack, video, keyframe, pkgPid, contPkg);
if (Trk.codec == "AAC"){ if (Trk.codec == "AAC"){
bs = TS::getAudioHeader(dataLen, Trk.init); bs = TS::getAudioHeader(dataLen, Trk.init);