TS stream lib fixes

This commit is contained in:
Thulinma 2017-05-15 15:28:51 +02:00
parent 6b379f63b6
commit 5be4892ae5
2 changed files with 51 additions and 110 deletions

View file

@ -68,7 +68,6 @@ namespace TS{
Stream::Stream(bool _threaded){ Stream::Stream(bool _threaded){
threaded = _threaded; threaded = _threaded;
firstPacketFound = false;
if (threaded){ if (threaded){
globalSem.open("MstTSInputLock", O_CREAT | O_RDWR, ACCESSPERMS, 1); globalSem.open("MstTSInputLock", O_CREAT | O_RDWR, ACCESSPERMS, 1);
if (!globalSem){ if (!globalSem){
@ -96,7 +95,6 @@ namespace TS{
pesPositions.clear(); pesPositions.clear();
outPackets.clear(); outPackets.clear();
buildPacket.clear(); buildPacket.clear();
partialBuffer.clear();
if (threaded){globalSem.post();} if (threaded){globalSem.post();}
} }
@ -388,12 +386,15 @@ namespace TS{
// Create a buffer for the current PES, and remove it from the pesStreams buffer. // Create a buffer for the current PES, and remove it from the pesStreams buffer.
int paySize = 0; int paySize = 0;
// Loop over the packets we need, and calculate the total payload size
curPack = inStream.begin(); curPack = inStream.begin();
for (int i = 0; i < packNum; i++){ for (int i = 0; i < packNum; i++){
paySize += curPack->getPayloadLength(); paySize += curPack->getPayloadLength();
curPack++; curPack++;
} }
VERYHIGH_MSG("Parsing PES for track %lu, length %i", tid, paySize); VERYHIGH_MSG("Parsing PES for track %lu, length %i", tid, paySize);
// allocate a buffer, do it all again, but this time also copy the data bytes over to char*
// payload
char *payload = (char *)malloc(paySize); char *payload = (char *)malloc(paySize);
paySize = 0; paySize = 0;
curPack = inStream.begin(); curPack = inStream.begin();
@ -415,6 +416,8 @@ namespace TS{
inStream.erase(inStream.begin(), curPack); inStream.erase(inStream.begin(), curPack);
inPositions.erase(inPositions.begin(), inPositions.begin() + packNum); inPositions.erase(inPositions.begin(), inPositions.begin() + packNum);
if (threaded){globalSem.post();} if (threaded){globalSem.post();}
// we now have the whole PES packet in char* payload, with a total size of paySize (including
// headers)
// Parse the PES header // Parse the PES header
int offset = 0; int offset = 0;
@ -441,17 +444,19 @@ namespace TS{
// Note: this is technically only allowed for video pes streams. // Note: this is technically only allowed for video pes streams.
unsigned long long realPayloadSize = (((int)pesHeader[4] << 8) | pesHeader[5]); unsigned long long realPayloadSize = (((int)pesHeader[4] << 8) | pesHeader[5]);
if (!realPayloadSize){ if (!realPayloadSize){
realPayloadSize = paySize; realPayloadSize = paySize; // PES header size already included here
}else{ }else{
realPayloadSize += 6; realPayloadSize += 6; // add the PES header size, always 6 bytes
} }
// realPayloadSize is now the whole packet
// We substract PES_header_data_length, plus the 9 bytes of mandatory header bytes
realPayloadSize -= (9 + pesHeader[8]); realPayloadSize -= (9 + pesHeader[8]);
// Read the metadata for this PES Packet // Read the metadata for this PES Packet
///\todo Determine keyframe-ness ///\todo Determine keyframe-ness
unsigned int timeStamp = 0; unsigned int timeStamp = 0;
int64_t timeOffset = 0; int64_t timeOffset = 0;
unsigned int pesOffset = 9; unsigned int pesOffset = 9; // mandatory headers
if ((pesHeader[7] >> 6) & 0x02){// Check for PTS presence if ((pesHeader[7] >> 6) & 0x02){// Check for PTS presence
timeStamp = decodePTS(pesHeader + pesOffset); timeStamp = decodePTS(pesHeader + pesOffset);
pesOffset += 5; pesOffset += 5;
@ -488,10 +493,9 @@ namespace TS{
const char *pesPayload = pesHeader + pesOffset; const char *pesPayload = pesHeader + pesOffset;
parseBitstream(tid, pesPayload, realPayloadSize, timeStamp, timeOffset, bPos); parseBitstream(tid, pesPayload, realPayloadSize, timeStamp, timeOffset, bPos);
// We are done with the realpayload size, reverse calculation so we know the correct offset // Shift the offset by the payload size, the mandatory headers and the optional
// increase. // headers/padding
realPayloadSize += (9 + pesHeader[8]); offset += realPayloadSize + (9 + pesHeader[8]);
offset += realPayloadSize;
} }
free(payload); free(payload);
} }
@ -569,111 +573,50 @@ namespace TS{
bool completePES = false; bool completePES = false;
const char *packetPtr; const char *packetPtr;
const char *nalEnd; const char *nalEnd;
bool checkForKeyFrame = true;
bool isKeyFrame = false; bool isKeyFrame = false;
int nalRemove = 0; int nalRemove = 0;
bool clearKey = false; bool clearKey = true;
nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr); nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr);
// std::cerr << "\t\tNew PES Packet" << std::endl; // std::cerr << "\t\tNew PES Packet" << std::endl;
while (!completePES){ while (!completePES){
if (!packetPtr){
if (packetPtr){ WARN_MSG("No H264 start code found in entire PES packet!");
// when startcode is found, check if we were already constructing a packet. break;
if (!partialBuffer[tid].empty()){
parseNal(tid, partialBuffer[tid].c_str(),
partialBuffer[tid].c_str() + partialBuffer[tid].length(), isKeyFrame);
}else{
parseNal(tid, pesPayload, packetPtr, isKeyFrame);
} }
if (!isKeyFrame || clearKey){clearKey = true;} // Check if this is a keyframe
parseNal(tid, pesPayload, packetPtr, isKeyFrame);
// If yes, don't clear the keyframe flag
if (isKeyFrame){clearKey = false;}
nalEnd = nalu::nalEndPosition(pesPayload, packetPtr - pesPayload); nalEnd = nalu::nalEndPosition(pesPayload, packetPtr - pesPayload);
nalRemove = packetPtr - nalEnd; nalRemove = packetPtr - nalEnd;
if (firstPacketFound && checkForKeyFrame){checkForKeyFrame = false;} // If we don't have a packet yet, init an empty packet with the key frame bit set to true
if (!buildPacket.count(tid)){
if (!buildPacket[tid] && !firstPacketFound){ buildPacket[tid].genericFill(timeStamp, timeOffset, tid, 0, 0, bPos, true);
// clean start
// remove everything before this point as this is the very first hal packet.
if (partialBuffer[tid].empty() && !firstPacketFound){// if buffer is empty
// very first packet, check for keyframe
checkForKeyFrame = true;
} }
firstPacketFound = true; // If the timestamp differs from current PES timestamp, send the previous packet out and
}else{
if (!buildPacket[tid]){// when no data in packet -> genericFill
buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360",
6, bPos, true);
}
// if the timestamp differs from current PES timestamp, send the previous packet out and
// fill a new one. // fill a new one.
if (buildPacket[tid].getTime() != timeStamp){ if (buildPacket[tid].getTime() != timeStamp){
// next packet's timestamp differs from current timestamp, add hal packet to // Clear the key frame bit if we didn't end up finding a key frame
// buildpacket and send it out.
if (!partialBuffer[tid].empty()){
// std::cerr << "append remaining data to partialbuffer" << std::endl;
buildPacket[tid].appendNal(partialBuffer[tid].c_str(), partialBuffer[tid].length(),
partialBuffer[tid].length() + (packetPtr - pesPayload) -
nalRemove);
buildPacket[tid].appendData(pesPayload, (packetPtr - pesPayload) - nalRemove);
if (clearKey){buildPacket[tid].clearKeyFrame();} if (clearKey){buildPacket[tid].clearKeyFrame();}
// Add the finished DTSC packet to our output buffer
if (threaded){globalSem.wait();}
outPackets[tid].push_back(buildPacket[tid]); outPackets[tid].push_back(buildPacket[tid]);
if (threaded){globalSem.post();}
// Create a new empty packet with the key frame bit set to true
buildPacket[tid].null(); buildPacket[tid].null();
buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360", buildPacket[tid].genericFill(timeStamp, timeOffset, tid, 0, 0, bPos, true);
6, bPos, true); }
// No matter what, now append the current NAL unit to the current packet
partialBuffer[tid].clear();
}else{
if (clearKey){buildPacket[tid].clearKeyFrame();}
outPackets[tid].push_back(buildPacket[tid]);
buildPacket[tid].null();
buildPacket[tid].genericFill(timeStamp, timeOffset, tid, "\000\000\000\002\011\360",
6, bPos, true);
buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove, buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove,
(packetPtr - pesPayload) - nalRemove); (packetPtr - pesPayload) - nalRemove);
}
if (threaded){globalSem.wait();}
if (threaded){globalSem.post();}
}else{
// we have a partial packet which belongs to the previous packet in partialBuffer.
if (!partialBuffer[tid].empty()){// if buffer is used
buildPacket[tid].appendNal(partialBuffer[tid].c_str(), partialBuffer[tid].length(),
partialBuffer[tid].length() + (packetPtr - pesPayload) -
nalRemove);
buildPacket[tid].appendData(pesPayload, (packetPtr - pesPayload) - nalRemove);
partialBuffer.clear();
}else{
// hal packet at first position
// buildPacket[tid].appendData(pesPayload, packetPtr-pesPayload);
// //append part before the startcode.
buildPacket[tid].appendNal(pesPayload, (packetPtr - pesPayload) - nalRemove,
(packetPtr - pesPayload) -
nalRemove); // append part before the startcode.
}
}
}
realPayloadSize -= ((packetPtr - pesPayload) + 3); // decrease the total size realPayloadSize -= ((packetPtr - pesPayload) + 3); // decrease the total size
pesPayload = packetPtr + 3; pesPayload = packetPtr + 3;
}else{// no startcode found...
if (partialBuffer[tid].empty()){
partialBuffer[tid].assign(pesPayload, realPayloadSize);
}else{
partialBuffer[tid].append(pesPayload, realPayloadSize);
}
completePES = true;
}
nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr); nalu::scanAnnexB(pesPayload, realPayloadSize, packetPtr);
} }

View file

@ -64,7 +64,6 @@ namespace TS{
ProgramAssociationTable associationTable; ProgramAssociationTable associationTable;
std::map<unsigned long, ADTSRemainder> remainders; std::map<unsigned long, ADTSRemainder> remainders;
bool firstPacketFound;
std::map<unsigned long, unsigned long long> lastPMT; std::map<unsigned long, unsigned long long> lastPMT;
std::map<unsigned long, ProgramMappingTable> mappingTable; std::map<unsigned long, ProgramMappingTable> mappingTable;
@ -79,7 +78,6 @@ namespace TS{
std::map<unsigned long, h265::initData> hevcInfo; std::map<unsigned long, h265::initData> hevcInfo;
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, std::string> partialBuffer;
mutable IPC::semaphore globalSem; mutable IPC::semaphore globalSem;
bool threaded; bool threaded;