/**********
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-2026 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;
}
