blob: e10c024187362e3538d034d86ff141003f35a4f0 [file] [log] [blame]
/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********/
// "liveMedia"
// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sources
// Implementation
#include "MPEG4GenericRTPSource.hh"
#include "BitVector.hh"
#include "MPEG4LATMAudioRTPSource.hh" // for parseGeneralConfigStr()
////////// MPEG4GenericBufferedPacket and MPEG4GenericBufferedPacketFactory
class MPEG4GenericBufferedPacket: public BufferedPacket {
public:
MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource);
virtual ~MPEG4GenericBufferedPacket();
private: // redefined virtual functions
virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
unsigned dataSize);
private:
MPEG4GenericRTPSource* fOurSource;
};
class MPEG4GenericBufferedPacketFactory: public BufferedPacketFactory {
private: // redefined virtual functions
virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
};
////////// AUHeader //////////
struct AUHeader {
unsigned size;
unsigned index; // indexDelta for the 2nd & subsequent headers
};
///////// MPEG4GenericRTPSource implementation ////////
//##### NOTE: INCOMPLETE!!! Support more modes, and interleaving #####
MPEG4GenericRTPSource*
MPEG4GenericRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
unsigned char rtpPayloadFormat,
unsigned rtpTimestampFrequency,
char const* mediumName,
char const* mode,
unsigned sizeLength, unsigned indexLength,
unsigned indexDeltaLength
) {
return new MPEG4GenericRTPSource(env, RTPgs, rtpPayloadFormat,
rtpTimestampFrequency, mediumName,
mode, sizeLength, indexLength,
indexDeltaLength
);
}
MPEG4GenericRTPSource
::MPEG4GenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
unsigned char rtpPayloadFormat,
unsigned rtpTimestampFrequency,
char const* mediumName,
char const* mode,
unsigned sizeLength, unsigned indexLength,
unsigned indexDeltaLength
)
: MultiFramedRTPSource(env, RTPgs,
rtpPayloadFormat, rtpTimestampFrequency,
new MPEG4GenericBufferedPacketFactory),
fSizeLength(sizeLength), fIndexLength(indexLength),
fIndexDeltaLength(indexDeltaLength),
fNumAUHeaders(0), fNextAUHeader(0), fAUHeaders(NULL) {
unsigned mimeTypeLength =
strlen(mediumName) + 14 /* strlen("/MPEG4-GENERIC") */ + 1;
fMIMEType = new char[mimeTypeLength];
if (fMIMEType != NULL) {
sprintf(fMIMEType, "%s/MPEG4-GENERIC", mediumName);
}
fMode = strDup(mode);
// Check for a "mode" that we don't yet support: //#####
if (mode == NULL ||
(strcmp(mode, "aac-hbr") != 0 && strcmp(mode, "generic") != 0)) {
envir() << "MPEG4GenericRTPSource Warning: Unknown or unsupported \"mode\": "
<< mode << "\n";
}
}
MPEG4GenericRTPSource::~MPEG4GenericRTPSource() {
delete[] fAUHeaders;
delete[] fMode;
delete[] fMIMEType;
}
Boolean MPEG4GenericRTPSource
::processSpecialHeader(BufferedPacket* packet,
unsigned& resultSpecialHeaderSize) {
unsigned char* headerStart = packet->data();
unsigned packetSize = packet->dataSize();
fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame;
// whether the *previous* packet ended a frame
// The RTP "M" (marker) bit indicates the last fragment of a frame:
fCurrentPacketCompletesFrame = packet->rtpMarkerBit();
// default values:
resultSpecialHeaderSize = 0;
fNumAUHeaders = 0;
fNextAUHeader = 0;
delete[] fAUHeaders; fAUHeaders = NULL;
if (fSizeLength > 0) {
// The packet begins with a "AU Header Section". Parse it, to
// determine the "AU-header"s for each frame present in this packet:
resultSpecialHeaderSize += 2;
if (packetSize < resultSpecialHeaderSize) return False;
unsigned AU_headers_length = (headerStart[0]<<8)|headerStart[1];
unsigned AU_headers_length_bytes = (AU_headers_length+7)/8;
if (packetSize
< resultSpecialHeaderSize + AU_headers_length_bytes) return False;
resultSpecialHeaderSize += AU_headers_length_bytes;
// Figure out how many AU-headers are present in the packet:
int bitsAvail = AU_headers_length - (fSizeLength + fIndexLength);
if (bitsAvail >= 0 && (fSizeLength + fIndexDeltaLength) > 0) {
fNumAUHeaders = 1 + bitsAvail/(fSizeLength + fIndexDeltaLength);
}
if (fNumAUHeaders > 0) {
fAUHeaders = new AUHeader[fNumAUHeaders];
// Fill in each header:
BitVector bv(&headerStart[2], 0, AU_headers_length);
fAUHeaders[0].size = bv.getBits(fSizeLength);
fAUHeaders[0].index = bv.getBits(fIndexLength);
for (unsigned i = 1; i < fNumAUHeaders; ++i) {
fAUHeaders[i].size = bv.getBits(fSizeLength);
fAUHeaders[i].index = bv.getBits(fIndexDeltaLength);
}
}
}
return True;
}
char const* MPEG4GenericRTPSource::MIMEtype() const {
return fMIMEType;
}
////////// MPEG4GenericBufferedPacket
////////// and MPEG4GenericBufferedPacketFactory implementation
MPEG4GenericBufferedPacket
::MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource)
: fOurSource(ourSource) {
}
MPEG4GenericBufferedPacket::~MPEG4GenericBufferedPacket() {
}
unsigned MPEG4GenericBufferedPacket
::nextEnclosedFrameSize(unsigned char*& /*framePtr*/, unsigned dataSize) {
// WE CURRENTLY DON'T IMPLEMENT INTERLEAVING. FIX THIS! #####
AUHeader* auHeader = fOurSource->fAUHeaders;
if (auHeader == NULL) return dataSize;
unsigned numAUHeaders = fOurSource->fNumAUHeaders;
if (fOurSource->fNextAUHeader >= numAUHeaders) {
fOurSource->envir() << "MPEG4GenericBufferedPacket::nextEnclosedFrameSize("
<< dataSize << "): data error ("
<< auHeader << "," << fOurSource->fNextAUHeader
<< "," << numAUHeaders << ")!\n";
return dataSize;
}
auHeader = &auHeader[fOurSource->fNextAUHeader++];
return auHeader->size <= dataSize ? auHeader->size : dataSize;
}
BufferedPacket* MPEG4GenericBufferedPacketFactory
::createNewPacket(MultiFramedRTPSource* ourSource) {
return new MPEG4GenericBufferedPacket((MPEG4GenericRTPSource*)ourSource);
}
////////// samplingFrequencyFromAudioSpecificConfig() implementation //////////
static unsigned const samplingFrequencyFromIndex[16] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
unsigned samplingFrequencyFromAudioSpecificConfig(char const* configStr) {
unsigned char* config = NULL;
unsigned result = 0; // if returned, indicates an error
do {
// Begin by parsing the config string:
unsigned configSize;
config = parseGeneralConfigStr(configStr, configSize);
if (config == NULL) break;
if (configSize < 2) break;
unsigned char samplingFrequencyIndex = ((config[0]&0x07)<<1) | (config[1]>>7);
if (samplingFrequencyIndex < 15) {
result = samplingFrequencyFromIndex[samplingFrequencyIndex];
break;
}
// Index == 15 means that the actual frequency is next (24 bits):
if (configSize < 5) break;
result = ((config[1]&0x7F)<<17) | (config[2]<<9) | (config[3]<<1) | (config[4]>>7);
} while (0);
delete[] config;
return result;
}