Index: liveMedia/include/MultiFramedRTPSink.hh
===================================================================
--- liveMedia/include/MultiFramedRTPSink.hh	(revision 14)
+++ liveMedia/include/MultiFramedRTPSink.hh	(working copy)
@@ -52,6 +52,11 @@
 				      unsigned numBytesInFrame,
 				      struct timeval framePresentationTime,
 				      unsigned numRemainingBytes);
+  virtual void doExtensionHeaderHandling(unsigned fragmentationOffset,
+				      unsigned char* frameStart,
+				      unsigned numBytesInFrame,
+				      struct timeval framePresentationTime,
+				      unsigned numRemainingBytes);
       // perform any processing specific to the particular payload format
   virtual Boolean allowFragmentationAfterStart() const;
       // whether a frame can be fragmented if other frame(s) appear earlier
@@ -62,8 +67,10 @@
   virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart,
 						 unsigned numBytesInFrame) const;
       // whether this frame can appear in position >1 in a pkt (default: True)
+  virtual unsigned extensionHeaderSize() const;
+      // returns the size of any extension header used (following the RTP header) (default: 0)
   virtual unsigned specialHeaderSize() const;
-      // returns the size of any special header used (following the RTP header) (default: 0)
+      // returns the size of any special header used (following the RTP header and optional extension header) (default: 0)
   virtual unsigned frameSpecificHeaderSize() const;
       // returns the size of any frame-specific header used (before each frame
       // within the packet) (default: 0)
@@ -78,7 +85,12 @@
   Boolean isFirstFrameInPacket() const { return fNumFramesUsedSoFar == 0; }
   unsigned curFragmentationOffset() const { return fCurFragmentationOffset; }
   void setMarkerBit();
+  void setExtensionHeaderBit();
   void setTimestamp(struct timeval framePresentationTime);
+  void setExtensionHeaderWord(unsigned word, /* 32 bits, in host order */
+			    unsigned wordPosition = 0);
+  void setExtensionHeaderBytes(unsigned char const* bytes, unsigned numBytes,
+			     unsigned bytePosition = 0);
   void setSpecialHeaderWord(unsigned word, /* 32 bits, in host order */
 			    unsigned wordPosition = 0);
   void setSpecialHeaderBytes(unsigned char const* bytes, unsigned numBytes,
@@ -126,6 +138,8 @@
   Boolean fIsFirstPacket;
   struct timeval fNextSendTime;
   unsigned fTimestampPosition;
+  unsigned fExtensionHeaderPosition;
+  unsigned fExtensionHeaderSize;
   unsigned fSpecialHeaderPosition;
   unsigned fSpecialHeaderSize; // size in bytes of any special header used
   unsigned fCurFrameSpecificHeaderPosition;
Index: liveMedia/include/RTPSource.hh
===================================================================
--- liveMedia/include/RTPSource.hh	(revision 14)
+++ liveMedia/include/RTPSource.hh	(working copy)
@@ -77,6 +77,13 @@
 					   handlerClientData);
   }
 
+  // This is used to set a callback to retrieve the RTP Header Extension data
+  typedef void (*RtpExtHdrCallback_t)(u_int16_t profile, u_int16_t len,
+    u_int8_t* pHdrData, void* pPriv);
+  void setExtensionHeaderCallback( RtpExtHdrCallback_t callback, void* pPriv ) {
+    fRtpExtHdrCallback = callback; fRtpExtHdrCallbackPrivData = pPriv;
+  }
+
   // Note that RTP receivers will usually not need to call either of the following two functions, because
   // RTP sequence numbers and timestamps are usually not useful to receivers.
   // (Our implementation of RTP reception already does all needed handling of RTP sequence numbers and timestamps.)
@@ -98,6 +105,8 @@
   Boolean fCurPacketHasBeenSynchronizedUsingRTCP;
   u_int32_t fLastReceivedSSRC;
   class RTCPInstance* fRTCPInstanceForMultiplexedRTCPPackets;
+  RtpExtHdrCallback_t fRtpExtHdrCallback;
+  void*               fRtpExtHdrCallbackPrivData;
 
 private:
   // redefined virtual functions:
Index: liveMedia/MultiFramedRTPSink.cpp
===================================================================
--- liveMedia/MultiFramedRTPSink.cpp	(revision 14)
+++ liveMedia/MultiFramedRTPSink.cpp	(working copy)
@@ -52,6 +52,7 @@
   : RTPSink(env, rtpGS, rtpPayloadType, rtpTimestampFrequency,
 	    rtpPayloadFormatName, numChannels),
     fOutBuf(NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False),
+    fExtensionHeaderPosition(0), fExtensionHeaderSize(0),
     fOnSendErrorFunc(NULL), fOnSendErrorData(NULL) {
   setPacketSizes((RTP_PAYLOAD_PREFERRED_SIZE), (RTP_PAYLOAD_MAX_SIZE));
 }
@@ -61,6 +62,17 @@
 }
 
 void MultiFramedRTPSink
+::doExtensionHeaderHandling(unsigned /*fragmentationOffset*/,
+			 unsigned char* frameStart,
+			 unsigned numBytesInFrame,
+			 struct timeval framePresentationTime,
+			 unsigned numRemainingBytes)
+{
+  // Default implementation does not write any header extension.
+  // Subclasses could call setExtension
+}
+
+void MultiFramedRTPSink
 ::doSpecialFrameHandling(unsigned /*fragmentationOffset*/,
 			 unsigned char* /*frameStart*/,
 			 unsigned /*numBytesInFrame*/,
@@ -87,6 +99,12 @@
   return True; // by default
 }
 
+unsigned MultiFramedRTPSink::extensionHeaderSize() const
+{
+  // default implementation: Assume no extension header:
+  return 0;
+}
+
 unsigned MultiFramedRTPSink::specialHeaderSize() const {
   // default implementation: Assume no special header:
   return 0;
@@ -108,6 +126,13 @@
   fOutBuf->insertWord(rtpHdr, 0);
 }
 
+void MultiFramedRTPSink::setExtensionHeaderBit()
+{
+  unsigned rtpHdr = fOutBuf->extractWord(0);
+  rtpHdr |= 0x10000000;
+  fOutBuf->insertWord(rtpHdr, 0);
+}
+
 void MultiFramedRTPSink::setTimestamp(struct timeval framePresentationTime) {
   // First, convert the presentation time to a 32-bit RTP timestamp:
   fCurrentTimestamp = convertToRTPTimestamp(framePresentationTime);
@@ -116,6 +141,18 @@
   fOutBuf->insertWord(fCurrentTimestamp, fTimestampPosition);
 }
 
+void MultiFramedRTPSink::setExtensionHeaderWord(unsigned word, /* 32 bits, in host order */
+			   unsigned wordPosition)
+{
+  fOutBuf->insertWord(word, fExtensionHeaderPosition + 4*wordPosition);
+}
+
+void MultiFramedRTPSink::setExtensionHeaderBytes(unsigned char const* bytes, unsigned numBytes,
+			   unsigned bytePosition)
+{
+  fOutBuf->insert(bytes, numBytes, fExtensionHeaderPosition + bytePosition);
+}
+
 void MultiFramedRTPSink::setSpecialHeaderWord(unsigned word,
 					      unsigned wordPosition) {
   fOutBuf->insertWord(word, fSpecialHeaderPosition + 4*wordPosition);
@@ -188,9 +225,11 @@
 
   // Allow for a special, payload-format-specific header following the
   // RTP header:
-  fSpecialHeaderPosition = fOutBuf->curPacketSize();
+  fExtensionHeaderPosition = fOutBuf->curPacketSize();
+  fExtensionHeaderSize = extensionHeaderSize();
+  fSpecialHeaderPosition = fExtensionHeaderPosition + fExtensionHeaderSize;
   fSpecialHeaderSize = specialHeaderSize();
-  fOutBuf->skipBytes(fSpecialHeaderSize);
+  fOutBuf->skipBytes(fExtensionHeaderSize + fSpecialHeaderSize);
 
   // Begin packing as many (complete) frames into the packet as we can:
   fTotalFrameSpecificHeaderSizes = 0;
@@ -314,6 +353,11 @@
     fOutBuf->increment(numFrameBytesToUse);
         // do this now, in case "doSpecialFrameHandling()" calls "setFramePadding()" to append padding bytes
 
+   // Allow subclasses to insert extension headers.
+   doExtensionHeaderHandling( curFragmentationOffset, frameStart,
+			   numFrameBytesToUse, presentationTime,
+			   overflowBytes );
+
     // Here's where any payload format specific processing gets done:
     doSpecialFrameHandling(curFragmentationOffset, frameStart,
 			   numFrameBytesToUse, presentationTime,
@@ -358,7 +402,7 @@
   // Check whether a 'numBytes'-byte frame - together with a RTP header and
   // (possible) special headers - would be too big for an output packet:
   // (Later allow for RTP extension header!) #####
-  numBytes += rtpHeaderSize + specialHeaderSize() + frameSpecificHeaderSize();
+  numBytes += rtpHeaderSize + extensionHeaderSize() + specialHeaderSize() + frameSpecificHeaderSize();
   return fOutBuf->isTooBigForAPacket(numBytes);
 }
 
@@ -375,7 +419,7 @@
     ++fPacketCount;
     fTotalOctetCount += fOutBuf->curPacketSize();
     fOctetCount += fOutBuf->curPacketSize()
-      - rtpHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes;
+      - rtpHeaderSize - fExtensionHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes;
 
     ++fSeqNo; // for next time
   }
@@ -387,7 +431,7 @@
     // so that we probably don't have to "memmove()" the overflow data
     // into place when building the next packet:
     unsigned newPacketStart = fOutBuf->curPacketSize()
-      - (rtpHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize());
+      - (rtpHeaderSize + fExtensionHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize());
     fOutBuf->adjustPacketStart(newPacketStart);
   } else {
     // Normal case: Reset the packet start pointer back to the start:
Index: liveMedia/MultiFramedRTPSource.cpp
===================================================================
--- liveMedia/MultiFramedRTPSource.cpp	(revision 14)
+++ liveMedia/MultiFramedRTPSource.cpp	(working copy)
@@ -286,12 +286,18 @@
     if (bPacket->dataSize() < cc*4) break;
     ADVANCE(cc*4);
 
-    // Check for (& ignore) any RTP header extension
+    // Check for any RTP header extension
     if (rtpHdr&0x10000000) {
       if (bPacket->dataSize() < 4) break;
       unsigned extHdr = ntohl(*(u_int32_t*)(bPacket->data())); ADVANCE(4);
       unsigned remExtSize = 4*(extHdr&0xFFFF);
       if (bPacket->dataSize() < remExtSize) break;
+
+      // If we have an extension header callback, call it with the data we found.
+      if( fRtpExtHdrCallback ) {
+        fRtpExtHdrCallback(extHdr>>16, remExtSize, bPacket->data(), fRtpExtHdrCallbackPrivData);
+      }
+
       ADVANCE(remExtSize);
     }
 
Index: liveMedia/RTPSource.cpp
===================================================================
--- liveMedia/RTPSource.cpp	(revision 14)
+++ liveMedia/RTPSource.cpp	(working copy)
@@ -55,6 +55,7 @@
     fRTPInterface(this, RTPgs),
     fCurPacketHasBeenSynchronizedUsingRTCP(False), fLastReceivedSSRC(0),
     fRTCPInstanceForMultiplexedRTCPPackets(NULL),
+    fRtpExtHdrCallback(NULL), fRtpExtHdrCallbackPrivData(NULL),
     fRTPPayloadFormat(rtpPayloadFormat), fTimestampFrequency(rtpTimestampFrequency),
     fSSRC(our_random32()), fEnableRTCPReports(True) {
   fReceptionStatsDB = new RTPReceptionStatsDB();
