/********** 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 2.1 of the License, or (at your option) any later version. (See .) 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-2016 Live Networks, Inc. All rights reserved. // H.265 Video RTP Sources // Implementation #include "H265VideoRTPSource.hh" ////////// H265BufferedPacket and H265BufferedPacketFactory ////////// class H265BufferedPacket: public BufferedPacket { public: H265BufferedPacket(H265VideoRTPSource& ourSource); virtual ~H265BufferedPacket(); private: // redefined virtual functions virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize); private: H265VideoRTPSource& fOurSource; }; class H265BufferedPacketFactory: public BufferedPacketFactory { private: // redefined virtual functions virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); }; ///////// H265VideoRTPSource implementation //////// H265VideoRTPSource* H265VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, Boolean expectDONFields, unsigned rtpTimestampFrequency) { return new H265VideoRTPSource(env, RTPgs, rtpPayloadFormat, expectDONFields, rtpTimestampFrequency); } H265VideoRTPSource ::H265VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, unsigned char rtpPayloadFormat, Boolean expectDONFields, unsigned rtpTimestampFrequency) : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, new H265BufferedPacketFactory), fExpectDONFields(expectDONFields), fPreviousNALUnitDON(0), fCurrentNALUnitAbsDon((u_int64_t)(~0)) { } H265VideoRTPSource::~H265VideoRTPSource() { } Boolean H265VideoRTPSource ::processSpecialHeader(BufferedPacket* packet, unsigned& resultSpecialHeaderSize) { unsigned char* headerStart = packet->data(); unsigned packetSize = packet->dataSize(); u_int16_t DONL = 0; unsigned numBytesToSkip; // Check the Payload Header's 'nal_unit_type' for special aggregation or fragmentation packets: if (packetSize < 2) return False; fCurPacketNALUnitType = (headerStart[0]&0x7E)>>1; switch (fCurPacketNALUnitType) { case 48: { // Aggregation Packet (AP) // We skip over the 2-byte Payload Header, and the DONL header (if any). if (fExpectDONFields) { if (packetSize < 4) return False; DONL = (headerStart[2]<<8)|headerStart[3]; numBytesToSkip = 4; } else { numBytesToSkip = 2; } break; } case 49: { // Fragmentation Unit (FU) // This NALU begins with the 2-byte Payload Header, the 1-byte FU header, and (optionally) // the 2-byte DONL header. // If the start bit is set, we reconstruct the original NAL header at the end of these // 3 (or 5) bytes, and skip over the first 1 (or 3) bytes. if (packetSize < 3) return False; u_int8_t startBit = headerStart[2]&0x80; // from the FU header u_int8_t endBit = headerStart[2]&0x40; // from the FU header if (startBit) { fCurrentPacketBeginsFrame = True; u_int8_t nal_unit_type = headerStart[2]&0x3F; // the last 6 bits of the FU header u_int8_t newNALHeader[2]; newNALHeader[0] = (headerStart[0]&0x81)|(nal_unit_type<<1); newNALHeader[1] = headerStart[1]; if (fExpectDONFields) { if (packetSize < 5) return False; DONL = (headerStart[3]<<8)|headerStart[4]; headerStart[3] = newNALHeader[0]; headerStart[4] = newNALHeader[1]; numBytesToSkip = 3; } else { headerStart[1] = newNALHeader[0]; headerStart[2] = newNALHeader[1]; numBytesToSkip = 1; } } else { // The start bit is not set, so we skip over all headers: fCurrentPacketBeginsFrame = False; if (fExpectDONFields) { if (packetSize < 5) return False; DONL = (headerStart[3]<<8)|headerStart[4]; numBytesToSkip = 5; } else { numBytesToSkip = 3; } } fCurrentPacketCompletesFrame = (endBit != 0); break; } default: { // This packet contains one complete NAL unit: fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame = True; numBytesToSkip = 0; break; } } computeAbsDonFromDON(DONL); resultSpecialHeaderSize = numBytesToSkip; return True; } char const* H265VideoRTPSource::MIMEtype() const { return "video/H265"; } void H265VideoRTPSource::computeAbsDonFromDON(u_int16_t DON) { if (!fExpectDONFields) { // Without DON fields in the input stream, we just increment our "AbsDon" count each time: ++fCurrentNALUnitAbsDon; } else { if (fCurrentNALUnitAbsDon == (u_int64_t)(~0)) { // This is the very first NAL unit, so "AbsDon" is just "DON": fCurrentNALUnitAbsDon = (u_int64_t)DON; } else { // Use the previous NAL unit's DON and the current DON to compute "AbsDon": // AbsDon[n] = AbsDon[n-1] + (DON[n] - DON[n-1]) mod 2^16 short signedDiff16 = (short)(DON - fPreviousNALUnitDON); int64_t signedDiff64 = (int64_t)signedDiff16; fCurrentNALUnitAbsDon += signedDiff64; } fPreviousNALUnitDON = DON; // for next time } } ////////// H265BufferedPacket and H265BufferedPacketFactory implementation ////////// H265BufferedPacket::H265BufferedPacket(H265VideoRTPSource& ourSource) : fOurSource(ourSource) { } H265BufferedPacket::~H265BufferedPacket() { } unsigned H265BufferedPacket ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { unsigned resultNALUSize = 0; // if an error occurs switch (fOurSource.fCurPacketNALUnitType) { case 48: { // Aggregation Packet (AP) if (useCount() > 0) { // We're other than the first NAL unit inside this Aggregation Packet. // Update our 'decoding order number': u_int16_t DONL = 0; if (fOurSource.fExpectDONFields) { // There's a 1-byte DOND field next: if (dataSize < 1) break; u_int8_t DOND = framePtr[0]; DONL = fOurSource.fPreviousNALUnitDON + (u_int16_t)(DOND + 1); ++framePtr; --dataSize; } fOurSource.computeAbsDonFromDON(DONL); } // The next 2 bytes are the NAL unit size: if (dataSize < 2) break; resultNALUSize = (framePtr[0]<<8)|framePtr[1]; framePtr += 2; break; } default: { // Common case: We use the entire packet data: return dataSize; } } return (resultNALUSize <= dataSize) ? resultNALUSize : dataSize; } BufferedPacket* H265BufferedPacketFactory ::createNewPacket(MultiFramedRTPSource* ourSource) { return new H265BufferedPacket((H265VideoRTPSource&)(*ourSource)); }