Added PCM A-law support to RTSP, both input and output

This commit is contained in:
Thulinma 2017-04-07 15:35:14 +02:00
parent b9f60ac92c
commit d158ba3213
3 changed files with 70 additions and 40 deletions

View file

@ -155,13 +155,10 @@ namespace RTP {
((int *)rtcpData)[2] = htonl(2208988800UL + Util::epoch()); //epoch is in seconds
((int *)rtcpData)[3] = htonl((Util::getMS() % 1000) * 4294967.295);
if (metadata.tracks[tid].codec == "H264" || metadata.tracks[tid].codec == "MP3") {
if (metadata.tracks[tid].codec == "H264") {
((int *)rtcpData)[4] = htonl((ntpTime - 0) * 90000); //rtpts
} else if (metadata.tracks[tid].codec == "AAC" || metadata.tracks[tid].codec == "AC3") {
((int *)rtcpData)[4] = htonl((ntpTime - 0) * metadata.tracks[tid].rate); //rtpts
} else {
DEBUG_MSG(DLVL_FAIL, "Unsupported codec: %s", metadata.tracks[tid].codec.c_str());
return;
((int *)rtcpData)[4] = htonl((ntpTime - 0) * metadata.tracks[tid].rate); //rtpts
}
//it should be the time packet was sent maybe, after all?
//*((int *)(rtcpData+16) ) = htonl(getTimeStamp());//rtpts

View file

@ -59,6 +59,7 @@ namespace Mist {
capa["codecs"][0u][1u].append("AAC");
capa["codecs"][0u][1u].append("MP3");
capa["codecs"][0u][1u].append("AC3");
capa["codecs"][0u][1u].append("ALAW");
capa["methods"][0u]["handler"] = "rtsp";
capa["methods"][0u]["type"] = "rtsp";
@ -118,18 +119,6 @@ namespace Mist {
callBack = sendTCP;
}
if(myMeta.tracks[tid].codec == "MP3"){
tracks[tid].pack.setTimestamp(timestamp * 90);
tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel, "MP3");
return;
}
if( myMeta.tracks[tid].codec == "AC3" || myMeta.tracks[tid].codec == "AAC"){
tracks[tid].pack.setTimestamp(timestamp * ((double) myMeta.tracks[tid].rate / 1000.0));
tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel,myMeta.tracks[tid].codec);
return;
}
if(myMeta.tracks[tid].codec == "H264"){
long long offset = thisPacket.getInt("offset");
tracks[tid].pack.setTimestamp(90 * (timestamp + offset));
@ -141,6 +130,10 @@ namespace Mist {
}
return;
}
//Default packager
tracks[tid].pack.setTimestamp(timestamp * ((double) myMeta.tracks[tid].rate / 1000.0));
tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel,myMeta.tracks[tid].codec);
}
@ -580,8 +573,6 @@ namespace Mist {
DTSC::Packet nextPack;
nextPack.genericFill(newTs, offset, track, buffer, len, 0, isKey);
tracks[track].packCount++;
nProxy.streamName = streamName;
continueNegotiate(track);
bufferLivePacket(nextPack);
}
@ -591,6 +582,13 @@ namespace Mist {
if (!tracks[track].firstTime){
tracks[track].firstTime = pkt.getTimeStamp() + 1;
}
if (myMeta.tracks[track].codec == "ALAW"){
char * pl = pkt.getPayload();
DTSC::Packet nextPack;
nextPack.genericFill((pkt.getTimeStamp() - tracks[track].firstTime + 1) / ((double)myMeta.tracks[track].rate / 1000.0), 0, track, pl, pkt.getPayloadSize(), 0, false);
bufferLivePacket(nextPack);
return;
}
if (myMeta.tracks[track].codec == "AAC"){
//assume AAC packets are single AU units
/// \todo Support other input than single AU units
@ -606,8 +604,6 @@ namespace Mist {
nextPack.genericFill((pkt.getTimeStamp() + sampleOffset - tracks[track].firstTime + 1) / ((double)myMeta.tracks[track].rate / 1000.0), 0, track, pl+headLen+offset, std::min(auSize, pkt.getPayloadSize() - headLen - offset), 0, false);
offset += auSize;
sampleOffset += samples;
nProxy.streamName = streamName;
continueNegotiate(track);
bufferLivePacket(nextPack);
}
return;
@ -784,6 +780,7 @@ namespace Mist {
std::string to;
uint64_t trackNo = 0;
bool nope = true; //true if we have no valid track to fill
DTSC::Track * thisTrack = 0;
while(std::getline(ss,to,'\n')){
if (!to.empty() && *to.rbegin() == '\r'){to.erase(to.size()-1, 1);}
@ -791,11 +788,12 @@ namespace Mist {
if (to.substr(0,2) == "m="){
nope = true;
++trackNo;
thisTrack = &(myMeta.tracks[trackNo]);
std::stringstream words(to.substr(2));
std::string item;
if (getline(words, item, ' ') && (item == "audio" || item == "video")){
myMeta.tracks[trackNo].type = item;
myMeta.tracks[trackNo].trackID = trackNo;
thisTrack->type = item;
thisTrack->trackID = trackNo;
}else{
WARN_MSG("Media type not supported: %s", item.c_str());
continue;
@ -805,7 +803,29 @@ namespace Mist {
WARN_MSG("Media transport not supported: %s", item.c_str());
continue;
}
nope = false;
if (getline(words, item, ' ')){
uint64_t avp_type = JSON::Value(item).asInt();
switch (avp_type){
case 8: //PCM A-law
INFO_MSG("PCM A-law payload type");
nope = false;
thisTrack->codec = "ALAW";
thisTrack->rate = 8000;
thisTrack->channels = 1;
INFO_MSG("Incoming track %s", thisTrack->getIdentifier().c_str());
break;
default:
//dynamic type
if (avp_type >= 96 && avp_type <= 127){
INFO_MSG("Dynamic payload type (%llu) detected", avp_type);
nope = false;
continue;
}else{
FAIL_MSG("Payload type %llu not supported!", avp_type);
continue;
}
}
}
continue;
}
if (nope){continue;}//ignore lines if we have no valid track
@ -813,25 +833,25 @@ namespace Mist {
if (to.substr(0, 8) == "a=rtpmap"){
std::string mediaType = to.substr(to.find(' ', 8)+1);
std::string trCodec = mediaType.substr(0, mediaType.find('/'));
//convert to fullcaps
for(unsigned int i=0;i<trCodec.size();++i){
if(trCodec[i]<=122 && trCodec[i]>=97){trCodec[i]-=32;}
}
if (trCodec == "H264"){
myMeta.tracks[trackNo].codec = "H264";
}
if (trCodec == "MPEG4-GENERIC"){
myMeta.tracks[trackNo].codec = "AAC";
if (thisTrack->type == "audio"){
std::string extraInfo = mediaType.substr(mediaType.find('/')+1);
if (extraInfo.find('/') != std::string::npos){
size_t lastSlash = extraInfo.find('/');
myMeta.tracks[trackNo].rate = atoll(extraInfo.substr(0, lastSlash).c_str());
myMeta.tracks[trackNo].channels = atoll(extraInfo.substr(lastSlash+1).c_str());
thisTrack->rate = atoll(extraInfo.substr(0, lastSlash).c_str());
thisTrack->channels = atoll(extraInfo.substr(lastSlash+1).c_str());
}else{
myMeta.tracks[trackNo].rate = atoll(extraInfo.c_str());
myMeta.tracks[trackNo].channels = 1;
thisTrack->rate = atoll(extraInfo.c_str());
thisTrack->channels = 1;
}
}
INFO_MSG("Incoming track %s", myMeta.tracks[trackNo].getIdentifier().c_str());
if (trCodec == "H264"){thisTrack->codec = "H264";}
if (trCodec == "PCMA"){thisTrack->codec = "ALAW";}
if (trCodec == "MPEG4-GENERIC"){thisTrack->codec = "AAC";}
INFO_MSG("Incoming track %s", thisTrack->getIdentifier().c_str());
continue;
}
if (to.substr(0, 10) == "a=control:"){
@ -840,7 +860,7 @@ namespace Mist {
}
if (to.substr(0, 7) == "a=fmtp:"){
tracks[trackNo].fmtp = to.substr(7);
if (myMeta.tracks[trackNo].codec == "AAC"){
if (thisTrack->codec == "AAC"){
if (tracks[trackNo].getParamString("mode") != "AAC-hbr"){
//a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=120856E500
FAIL_MSG("AAC transport mode not supported: %s", tracks[trackNo].getParamString("mode").c_str());
@ -849,11 +869,11 @@ namespace Mist {
tracks.erase(trackNo);
continue;
}
myMeta.tracks[trackNo].init = Encodings::Hex::decode(tracks[trackNo].getParamString("config"));
thisTrack->init = Encodings::Hex::decode(tracks[trackNo].getParamString("config"));
//myMeta.tracks[trackNo].rate = aac::AudSpecConf::rate(myMeta.tracks[trackNo].init);
}
if (myMeta.tracks[trackNo].codec == "H264"){
if (thisTrack->codec == "H264"){
//a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0LAHtkA2D3m//AUABqxAAADAAEAAAMAMg8WLkg=,aMuDyyA=; profile-level-id=42C01E
std::string sprop = tracks[trackNo].getParamString("sprop-parameter-sets");
size_t comma = sprop.find(',');

View file

@ -37,6 +37,7 @@ namespace Mist {
cPort = 0;
rtpSeq = 0;
fpsTime = 0;
fpsMeta = 0;
fps = 0;
}
std::string getParamString(const std::string & param) const{
@ -87,6 +88,14 @@ namespace Mist {
mediaDesc << "m=audio 0 RTP/AVP 100" << "\r\n"
"a=rtpmap:100 AC3/" << trk.rate << "/" << trk.channels << "\r\n"
"a=control:track" << trk.trackID << "\r\n";
}else if ( trk.codec == "ALAW") {
if (trk.channels == 1 && trk.rate == 8000){
mediaDesc << "m=audio 0 RTP/AVP 8" << "\r\n";
}else{
mediaDesc << "m=audio 0 RTP/AVP 101" << "\r\n";
mediaDesc << "a=rtpmap:101 PCMA/" << trk.rate << "/" << trk.channels << "\r\n";
}
mediaDesc << "a=control:track" << trk.trackID << "\r\n";
}
return mediaDesc.str();
}
@ -100,11 +109,16 @@ namespace Mist {
pack = RTP::Packet(100, 1, 0, SSrc);
}else if(trk.codec == "MP3"){
pack = RTP::Packet(14, 1, 0, SSrc);
}else if(trk.codec == "ALAW"){
if (trk.channels == 1 && trk.rate == 8000){
pack = RTP::Packet(8, 1, 0, SSrc);
}else{
pack = RTP::Packet(101, 1, 0, SSrc);
}
}else{
ERROR_MSG("Unsupported codec %s for RTSP on track %u", trk.codec.c_str(), trk.trackID);
return false;
}
std::cerr << transport << std::endl;
if (transport.find("TCP") != std::string::npos) {
std::string chanE = transport.substr(transport.find("interleaved=") + 12, (transport.size() - transport.rfind('-') - 1)); //extract channel ID
channel = atol(chanE.c_str());
@ -136,10 +150,9 @@ namespace Mist {
}
std::string rtpInfo(const DTSC::Track & trk, const std::string & source, uint64_t currentTime){
unsigned int timeMultiplier = 1;
timeMultiplier = ((double)trk.rate / 1000.0);
if (trk.codec == "H264") {
timeMultiplier = 90;
} else if (trk.codec == "AAC" || trk.codec == "MP3" || trk.codec == "AC3") {
timeMultiplier = ((double)trk.rate / 1000.0);
}
std::stringstream rInfo;
rInfo << "url=" << source << "/track" << trk.trackID << ";"; //get the current url, not localhost