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-2014 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                    unsigned profile_level_id)
00032   : H264or5VideoRTPSink(264, env, RTPgs, rtpPayloadFormat,
00033                         NULL, 0, sps, spsSize, pps, ppsSize),
00034     fProfileLevelId(profile_level_id) {
00035 }
00036 
00037 H264VideoRTPSink::~H264VideoRTPSink() {
00038 }
00039 
00040 H264VideoRTPSink* H264VideoRTPSink
00041 ::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat) {
00042   return new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat);
00043 }
00044 
00045 H264VideoRTPSink* H264VideoRTPSink
00046 ::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00047             u_int8_t const* sps, unsigned spsSize, u_int8_t const* pps, unsigned ppsSize,
00048             unsigned profile_level_id) {
00049   return new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat, sps, spsSize, pps, ppsSize, profile_level_id);
00050 }
00051 
00052 H264VideoRTPSink* H264VideoRTPSink
00053 ::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat,
00054             char const* sPropParameterSetsStr, unsigned profile_level_id) {
00055   u_int8_t* sps = NULL; unsigned spsSize = 0;
00056   u_int8_t* pps = NULL; unsigned ppsSize = 0;
00057 
00058   unsigned numSPropRecords;
00059   SPropRecord* sPropRecords = parseSPropParameterSets(sPropParameterSetsStr, numSPropRecords);
00060   for (unsigned i = 0; i < numSPropRecords; ++i) {
00061     if (sPropRecords[i].sPropLength == 0) continue; // bad data
00062     u_int8_t nal_unit_type = (sPropRecords[i].sPropBytes[0])&0x1F;
00063     if (nal_unit_type == 7/*SPS*/) {
00064       sps = sPropRecords[i].sPropBytes;
00065       spsSize = sPropRecords[i].sPropLength;
00066     } else if (nal_unit_type == 8/*PPS*/) {
00067       pps = sPropRecords[i].sPropBytes;
00068       ppsSize = sPropRecords[i].sPropLength;
00069     }
00070   }
00071 
00072   H264VideoRTPSink* result
00073     = new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat, sps, spsSize, pps, ppsSize, profile_level_id);
00074   delete[] sPropRecords;
00075 
00076   return result;
00077 }
00078 
00079 Boolean H264VideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) {
00080   // Our source must be an appropriate framer:
00081   return source.isH264VideoStreamFramer();
00082 }
00083 
00084 char const* H264VideoRTPSink::auxSDPLine() {
00085   // Generate a new "a=fmtp:" line each time, using our SPS and PPS (if we have them),
00086   // otherwise parameters from our framer source (in case they've changed since the last time that
00087   // we were called):
00088   H264or5VideoStreamFramer* framerSource = NULL;
00089   u_int8_t* vpsDummy = NULL; unsigned vpsDummySize = 0;
00090   u_int8_t* sps = fSPS; unsigned spsSize = fSPSSize;
00091   u_int8_t* pps = fPPS; unsigned ppsSize = fPPSSize;
00092   if (sps == NULL || pps == NULL) {
00093     // We need to get SPS and PPS from our framer source:
00094     if (fOurFragmenter == NULL) return NULL; // we don't yet have a fragmenter (and therefore not a source)
00095     framerSource = (H264or5VideoStreamFramer*)(fOurFragmenter->inputSource());
00096     if (framerSource == NULL) return NULL; // we don't yet have a source
00097 
00098     framerSource->getVPSandSPSandPPS(vpsDummy, vpsDummySize, sps, spsSize, pps, ppsSize);
00099     if (sps == NULL || pps == NULL) return NULL; // our source isn't ready
00100 
00101     fProfileLevelId = framerSource->profileLevelId();
00102   }
00103 
00104   // Set up the "a=fmtp:" SDP line for this stream:
00105   char* sps_base64 = base64Encode((char*)sps, spsSize);
00106   char* pps_base64 = base64Encode((char*)pps, ppsSize);
00107 
00108   char const* fmtpFmt =
00109     "a=fmtp:%d packetization-mode=1"
00110     ";profile-level-id=%06X"
00111     ";sprop-parameter-sets=%s,%s\r\n";
00112   unsigned fmtpFmtSize = strlen(fmtpFmt)
00113     + 3 /* max char len */
00114     + 6 /* 3 bytes in hex */
00115     + strlen(sps_base64) + strlen(pps_base64);
00116   char* fmtp = new char[fmtpFmtSize];
00117   sprintf(fmtp, fmtpFmt,
00118           rtpPayloadType(),
00119           fProfileLevelId,
00120           sps_base64, pps_base64);
00121 
00122   delete[] sps_base64;
00123   delete[] pps_base64;
00124 
00125   delete[] fFmtpSDPLine; fFmtpSDPLine = fmtp;
00126   return fFmtpSDPLine;
00127 }

Generated on Tue Mar 25 14:35:34 2014 for live by  doxygen 1.5.2