liveMedia/H264VideoRTPSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // RTP sink for H.264 video (RFC 3984)
00019 // Implementation
00020 
00021 #include "H264VideoRTPSink.hh"
00022 #include "H264VideoStreamFramer.hh"
00023 #include "Base64.hh"
00024 #include "H264VideoRTPSource.hh" // for "parseSPropParameterSets()"
00025 
00027 
00028 H264VideoRTPSink
00029 ::H264VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00030                    u_int8_t const* sps, unsigned spsSize, u_int8_t const* pps, unsigned ppsSize)
00031   : VideoRTPSink(env, RTPgs, rtpPayloadFormat, 90000, "H264"),
00032     fOurFragmenter(NULL), fFmtpSDPLine(NULL) {
00033   if (sps != NULL) {
00034     fSPSSize = spsSize;
00035     fSPS = new u_int8_t[fSPSSize];
00036     memmove(fSPS, sps, fSPSSize);
00037   } else {
00038     fSPSSize = 0;
00039     fSPS = NULL;
00040   }
00041   if (pps != NULL) {
00042     fPPSSize = ppsSize;
00043     fPPS = new u_int8_t[fPPSSize];
00044     memmove(fPPS, pps, fPPSSize);
00045   } else {
00046     fPPSSize = 0;
00047     fPPS = NULL;
00048   }
00049 }
00050 
00051 H264VideoRTPSink::~H264VideoRTPSink() {
00052   fSource = fOurFragmenter; // hack: in case "fSource" had gotten set to NULL before we were called
00053   delete[] fFmtpSDPLine;
00054   delete[] fSPS; delete[] fPPS;
00055   stopPlaying(); // call this now, because we won't have our 'FUA fragmenter' when the base class destructor calls it later.
00056 
00057   // Close our 'FUA fragmenter' as well:
00058   Medium::close(fOurFragmenter);
00059   fSource = NULL; // for the base class destructor, which gets called next
00060 }
00061 
00062 H264VideoRTPSink*
00063 H264VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat) {
00064   return new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat);
00065 }
00066 
00067 H264VideoRTPSink*
00068 H264VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00069                             u_int8_t const* sps, unsigned spsSize, u_int8_t const* pps, unsigned ppsSize) {
00070   return new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat, sps, spsSize, pps, ppsSize);
00071 }
00072 
00073 H264VideoRTPSink*
00074 H264VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00075                             char const* sPropParameterSetsStr) {
00076   u_int8_t* sps = NULL; unsigned spsSize = 0;
00077   u_int8_t* pps = NULL; unsigned ppsSize = 0;
00078 
00079   unsigned numSPropRecords;
00080   SPropRecord* sPropRecords = parseSPropParameterSets(sPropParameterSetsStr, numSPropRecords);
00081   for (unsigned i = 0; i < numSPropRecords; ++i) {
00082     if (sPropRecords[i].sPropLength == 0) continue; // bad data
00083     u_int8_t nal_unit_type = (sPropRecords[i].sPropBytes[0])&0x1F;
00084     if (nal_unit_type == 7/*SPS*/) {
00085       sps = sPropRecords[i].sPropBytes;
00086       spsSize = sPropRecords[i].sPropLength;
00087     } else if (nal_unit_type == 8/*PPS*/) {
00088       pps = sPropRecords[i].sPropBytes;
00089       ppsSize = sPropRecords[i].sPropLength;
00090     }
00091   }
00092 
00093   H264VideoRTPSink* result = new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat, sps, spsSize, pps, ppsSize);
00094   delete[] sPropRecords;
00095 
00096   return result;
00097 }
00098 
00099 Boolean H264VideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) {
00100   // Our source must be an appropriate framer:
00101   return source.isH264VideoStreamFramer();
00102 }
00103 
00104 Boolean H264VideoRTPSink::continuePlaying() {
00105   // First, check whether we have a 'fragmenter' class set up yet.
00106   // If not, create it now:
00107   if (fOurFragmenter == NULL) {
00108     fOurFragmenter = new H264FUAFragmenter(envir(), fSource, OutPacketBuffer::maxSize,
00109                                            ourMaxPacketSize() - 12/*RTP hdr size*/);
00110   } else {
00111     fOurFragmenter->reassignInputSource(fSource);
00112   }
00113   fSource = fOurFragmenter;
00114 
00115   // Then call the parent class's implementation:
00116   return MultiFramedRTPSink::continuePlaying();
00117 }
00118 
00119 void H264VideoRTPSink::doSpecialFrameHandling(unsigned /*fragmentationOffset*/,
00120                                               unsigned char* /*frameStart*/,
00121                                               unsigned /*numBytesInFrame*/,
00122                                               struct timeval framePresentationTime,
00123                                               unsigned /*numRemainingBytes*/) {
00124   // Set the RTP 'M' (marker) bit iff
00125   // 1/ The most recently delivered fragment was the end of (or the only fragment of) an NAL unit, and
00126   // 2/ This NAL unit was the last NAL unit of an 'access unit' (i.e. video frame).
00127   if (fOurFragmenter != NULL) {
00128     H264VideoStreamFramer* framerSource
00129       = (H264VideoStreamFramer*)(fOurFragmenter->inputSource());
00130     // This relies on our fragmenter's source being a "H264VideoStreamFramer".
00131     if (fOurFragmenter->lastFragmentCompletedNALUnit()
00132         && framerSource != NULL && framerSource->pictureEndMarker()) {
00133       setMarkerBit();
00134       framerSource->pictureEndMarker() = False;
00135     }
00136   }
00137 
00138   setTimestamp(framePresentationTime);
00139 }
00140 
00141 Boolean H264VideoRTPSink
00142 ::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/,
00143                                  unsigned /*numBytesInFrame*/) const {
00144   return False;
00145 }
00146 
00147 char const* H264VideoRTPSink::auxSDPLine() {
00148   // Generate a new "a=fmtp:" line each time, using our SPS and PPS (if we have them),
00149   // otherwise parameters from our framer source (in case they've changed since the last time that
00150   // we were called):
00151   u_int8_t* sps = fSPS; unsigned spsSize = fSPSSize;
00152   u_int8_t* pps = fPPS; unsigned ppsSize = fPPSSize;
00153   if (sps == NULL || pps == NULL) {
00154     // We need to get SPS and PPS from our framer source:
00155     if (fOurFragmenter == NULL) return NULL; // we don't yet have a fragmenter (and therefore not a source)
00156     H264VideoStreamFramer* framerSource = (H264VideoStreamFramer*)(fOurFragmenter->inputSource());
00157     if (framerSource == NULL) return NULL; // we don't yet have a source
00158 
00159     framerSource->getSPSandPPS(sps, spsSize, pps, ppsSize);
00160     if (sps == NULL || pps == NULL) return NULL; // our source isn't ready
00161   }
00162 
00163   u_int32_t profile_level_id;
00164   if (spsSize < 4) { // sanity check
00165     profile_level_id = 0;
00166   } else {
00167     profile_level_id = (sps[1]<<16)|(sps[2]<<8)|sps[3]; // profile_idc|constraint_setN_flag|level_idc
00168   }
00169   
00170   // Set up the "a=fmtp:" SDP line for this stream:
00171   char* sps_base64 = base64Encode((char*)sps, spsSize);
00172   char* pps_base64 = base64Encode((char*)pps, ppsSize);
00173   char const* fmtpFmt =
00174     "a=fmtp:%d packetization-mode=1"
00175     ";profile-level-id=%06X"
00176     ";sprop-parameter-sets=%s,%s\r\n";
00177   unsigned fmtpFmtSize = strlen(fmtpFmt)
00178     + 3 /* max char len */
00179     + 6 /* 3 bytes in hex */
00180     + strlen(sps_base64) + strlen(pps_base64);
00181   char* fmtp = new char[fmtpFmtSize];
00182   sprintf(fmtp, fmtpFmt,
00183           rtpPayloadType(),
00184           profile_level_id,
00185           sps_base64, pps_base64);
00186   delete[] sps_base64;
00187   delete[] pps_base64;
00188 
00189   delete[] fFmtpSDPLine; fFmtpSDPLine = fmtp;
00190   return fFmtpSDPLine;
00191 }
00192 
00193 
00195 
00196 H264FUAFragmenter::H264FUAFragmenter(UsageEnvironment& env,
00197                                      FramedSource* inputSource,
00198                                      unsigned inputBufferMax,
00199                                      unsigned maxOutputPacketSize)
00200   : FramedFilter(env, inputSource),
00201     fInputBufferSize(inputBufferMax+1), fMaxOutputPacketSize(maxOutputPacketSize),
00202     fNumValidDataBytes(1), fCurDataOffset(1), fSaveNumTruncatedBytes(0),
00203     fLastFragmentCompletedNALUnit(True) {
00204   fInputBuffer = new unsigned char[fInputBufferSize];
00205 }
00206 
00207 H264FUAFragmenter::~H264FUAFragmenter() {
00208   delete[] fInputBuffer;
00209   detachInputSource(); // so that the subsequent ~FramedFilter() doesn't delete it
00210 }
00211 
00212 void H264FUAFragmenter::doGetNextFrame() {
00213   if (fNumValidDataBytes == 1) {
00214     // We have no NAL unit data currently in the buffer.  Read a new one:
00215     fInputSource->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,
00216                                afterGettingFrame, this,
00217                                FramedSource::handleClosure, this);
00218   } else {
00219     // We have NAL unit data in the buffer.  There are three cases to consider:
00220     // 1. There is a new NAL unit in the buffer, and it's small enough to deliver
00221     //    to the RTP sink (as is).
00222     // 2. There is a new NAL unit in the buffer, but it's too large to deliver to
00223     //    the RTP sink in its entirety.  Deliver the first fragment of this data,
00224     //    as a FU-A packet, with one extra preceding header byte.
00225     // 3. There is a NAL unit in the buffer, and we've already delivered some
00226     //    fragment(s) of this.  Deliver the next fragment of this data,
00227     //    as a FU-A packet, with two extra preceding header bytes.
00228 
00229     if (fMaxSize < fMaxOutputPacketSize) { // shouldn't happen
00230       envir() << "H264FUAFragmenter::doGetNextFrame(): fMaxSize ("
00231               << fMaxSize << ") is smaller than expected\n";
00232     } else {
00233       fMaxSize = fMaxOutputPacketSize;
00234     }
00235 
00236     fLastFragmentCompletedNALUnit = True; // by default
00237     if (fCurDataOffset == 1) { // case 1 or 2
00238       if (fNumValidDataBytes - 1 <= fMaxSize) { // case 1
00239         memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);
00240         fFrameSize = fNumValidDataBytes - 1;
00241         fCurDataOffset = fNumValidDataBytes;
00242       } else { // case 2
00243         // We need to send the NAL unit data as FU-A packets.  Deliver the first
00244         // packet now.  Note that we add FU indicator and FU header bytes to the front
00245         // of the packet (reusing the existing NAL header byte for the FU header).
00246         fInputBuffer[0] = (fInputBuffer[1] & 0xE0) | 28; // FU indicator
00247         fInputBuffer[1] = 0x80 | (fInputBuffer[1] & 0x1F); // FU header (with S bit)
00248         memmove(fTo, fInputBuffer, fMaxSize);
00249         fFrameSize = fMaxSize;
00250         fCurDataOffset += fMaxSize - 1;
00251         fLastFragmentCompletedNALUnit = False;
00252       }
00253     } else { // case 3
00254       // We are sending this NAL unit data as FU-A packets.  We've already sent the
00255       // first packet (fragment).  Now, send the next fragment.  Note that we add
00256       // FU indicator and FU header bytes to the front.  (We reuse these bytes that
00257       // we already sent for the first fragment, but clear the S bit, and add the E
00258       // bit if this is the last fragment.)
00259       fInputBuffer[fCurDataOffset-2] = fInputBuffer[0]; // FU indicator
00260       fInputBuffer[fCurDataOffset-1] = fInputBuffer[1]&~0x80; // FU header (no S bit)
00261       unsigned numBytesToSend = 2 + fNumValidDataBytes - fCurDataOffset;
00262       if (numBytesToSend > fMaxSize) {
00263         // We can't send all of the remaining data this time:
00264         numBytesToSend = fMaxSize;
00265         fLastFragmentCompletedNALUnit = False;
00266       } else {
00267         // This is the last fragment:
00268         fInputBuffer[fCurDataOffset-1] |= 0x40; // set the E bit in the FU header
00269         fNumTruncatedBytes = fSaveNumTruncatedBytes;
00270       }
00271       memmove(fTo, &fInputBuffer[fCurDataOffset-2], numBytesToSend);
00272       fFrameSize = numBytesToSend;
00273       fCurDataOffset += numBytesToSend - 2;
00274     }
00275 
00276     if (fCurDataOffset >= fNumValidDataBytes) {
00277       // We're done with this data.  Reset the pointers for receiving new data:
00278       fNumValidDataBytes = fCurDataOffset = 1;
00279     }
00280 
00281     // Complete delivery to the client:
00282     FramedSource::afterGetting(this);
00283   }
00284 }
00285 
00286 void H264FUAFragmenter::afterGettingFrame(void* clientData, unsigned frameSize,
00287                                           unsigned numTruncatedBytes,
00288                                           struct timeval presentationTime,
00289                                           unsigned durationInMicroseconds) {
00290   H264FUAFragmenter* fragmenter = (H264FUAFragmenter*)clientData;
00291   fragmenter->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime,
00292                                  durationInMicroseconds);
00293 }
00294 
00295 void H264FUAFragmenter::afterGettingFrame1(unsigned frameSize,
00296                                            unsigned numTruncatedBytes,
00297                                            struct timeval presentationTime,
00298                                            unsigned durationInMicroseconds) {
00299   fNumValidDataBytes += frameSize;
00300   fSaveNumTruncatedBytes = numTruncatedBytes;
00301   fPresentationTime = presentationTime;
00302   fDurationInMicroseconds = durationInMicroseconds;
00303 
00304   // Deliver data to the client:
00305   doGetNextFrame();
00306 }

Generated on Tue Jun 18 13:16:50 2013 for live by  doxygen 1.5.2