VT: ARTPWriter: Enhanced ARTPWriter as a RTP output

Enhances ARTPWriter that sends RTP packets to network.
Code modification as per RFC 3550, RFC 1889, RFC 894.

1. Interfaces are added to provide local-ip and remote-ip address to ARTPWriter.
2. By the RFC 3550, RTP protocol is run on top of UDP typically.
2-1. A port number for RTP is EVEN.
3. By the RFC 3550, RTCP protocol exists with RTP as coupled one.
3-1. By the RFC 1889, a port number for RTCP is the next ODD number of RTP port.
4. SPS/PPS are sent for every I-frame.
   Basically encoder generates SPS/PPS at the first video stream.
   But those can be lost because RTP is run on UDP.
   So those are sent for every I-frame, and this is common action for RTP.
5. By the RFC 894, the maximum length of an IP datagram sent over an Ethernet is 1500 byte.
   A packet would be fragmented if its size overs.
   So some margin is needed for various cases. (various headers for UDP, RTP, encryption, etc...)

Change-Id: I34e18ed5ada6b51be3645eb8f725a6c16fe4878d
Signed-off-by: Kim Sungyeon <sy85.kim@samsung.com>
Signed-off-by: Byeongjo Park <bjo.park@samsung.com>
Merged-in: I34e18ed5ada6b51be3645eb8f725a6c16fe4878d
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 64eb8b4..d455093 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -247,6 +247,8 @@
 
     // Treat empty track as malformed for MediaRecorder.
     kKeyEmptyTrackMalFormed = 'nemt', // bool (int32_t)
+    kKeySps              = 'sSps', // int32_t, indicates that a buffer is sps.
+    kKeyPps              = 'sPps', // int32_t, indicates that a buffer is pps.
 };
 
 enum {
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 58d6086..92eaa70 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -35,6 +35,18 @@
 #define PT      97
 #define PT_STR  "97"
 
+#define H264_NALU_MASK 0x1F
+#define H264_NALU_SPS 0x7
+#define H264_NALU_PPS 0x8
+#define H264_NALU_IFRAME 0x5
+#define H264_NALU_PFRAME 0x1
+#define UDP_HEADER_SIZE 8
+#define RTP_HEADER_SIZE 12
+#define RTP_HEADER_EXT_SIZE 1
+#define RTP_FU_HEADER_SIZE 2
+#define RTP_PAYLOAD_ROOM_SIZE 140
+
+
 namespace android {
 
 // static const size_t kMaxPacketSize = 65507;  // maximum payload in UDP over IP
@@ -55,8 +67,10 @@
     mLooper->registerHandler(mReflector);
     mLooper->start();
 
-    mSocket = socket(AF_INET, SOCK_DGRAM, 0);
-    CHECK_GE(mSocket, 0);
+    mRTPSocket = socket(AF_INET, SOCK_DGRAM, 0);
+    CHECK_GE(mRTPSocket, 0);
+    mRTCPSocket = socket(AF_INET, SOCK_DGRAM, 0);
+    CHECK_GE(mRTCPSocket, 0);
 
     memset(mRTPAddr.sin_zero, 0, sizeof(mRTPAddr.sin_zero));
     mRTPAddr.sin_family = AF_INET;
@@ -72,6 +86,83 @@
 
     mRTCPAddr = mRTPAddr;
     mRTCPAddr.sin_port = htons(ntohs(mRTPAddr.sin_port) | 1);
+    mSPSBuf = NULL;
+    mPPSBuf = NULL;
+
+#if LOG_TO_FILES
+    mRTPFd = open(
+            "/data/misc/rtpout.bin",
+            O_WRONLY | O_CREAT | O_TRUNC,
+            0644);
+    CHECK_GE(mRTPFd, 0);
+
+    mRTCPFd = open(
+            "/data/misc/rtcpout.bin",
+            O_WRONLY | O_CREAT | O_TRUNC,
+            0644);
+    CHECK_GE(mRTCPFd, 0);
+#endif
+}
+
+ARTPWriter::ARTPWriter(int fd, String8& localIp, int localPort, String8& remoteIp,
+    int remotePort)
+    : mFlags(0),
+      mFd(dup(fd)),
+      mLooper(new ALooper),
+      mReflector(new AHandlerReflector<ARTPWriter>(this)) {
+    CHECK_GE(fd, 0);
+
+    mLooper->setName("rtp writer");
+    mLooper->registerHandler(mReflector);
+    mLooper->start();
+
+    mRTPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    CHECK_GE(mRTPSocket, 0);
+    mRTCPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    CHECK_GE(mRTCPSocket, 0);
+
+    // socket need to be SO_REUSEADDR to avoid "Address already in use" error.
+    int sockopt = 1;
+    setsockopt(mRTPSocket, SOL_SOCKET, SO_REUSEADDR, (int *)&sockopt, sizeof(sockopt));
+    setsockopt(mRTPSocket, SOL_SOCKET, SO_REUSEPORT, (int *)&sockopt, sizeof(sockopt));
+    setsockopt(mRTCPSocket, SOL_SOCKET, SO_REUSEADDR, (int *)&sockopt, sizeof(sockopt));
+    setsockopt(mRTCPSocket, SOL_SOCKET, SO_REUSEPORT, (int *)&sockopt, sizeof(sockopt));
+
+    // binding rtp socket to assign source ip/port.
+    memset(mLocalAddr.sin_zero, 0, sizeof(mRTPAddr.sin_zero));
+    mLocalAddr.sin_family = AF_INET;
+    mLocalAddr.sin_addr.s_addr = inet_addr(localIp.string());
+    mLocalAddr.sin_port = htons((unsigned short int)localPort);
+    if (bind(mRTPSocket, (struct sockaddr*)&mLocalAddr, sizeof(mLocalAddr)) == -1) {
+        ALOGE("failed to bind rtp %s:%d err=%s", localIp.string(),
+                ntohs(mLocalAddr.sin_port), strerror(errno));
+    } else {
+        ALOGD("succeed to bind rtp %s:%d", localIp.string(), ntohs(mLocalAddr.sin_port));
+    }
+    // binding rtcp socket to assign source ip/port.
+    mLocalAddr.sin_port = htons(ntohs(mLocalAddr.sin_port) + 1);
+    if (bind(mRTCPSocket, (struct sockaddr*)&mLocalAddr, sizeof(mLocalAddr)) == -1) {
+        ALOGE("failed to bind rtcp %s:%d", localIp.string(), ntohs(mLocalAddr.sin_port));
+    } else {
+        ALOGD("succeed to bind rtcp %s:%d", localIp.string(), ntohs(mLocalAddr.sin_port) | 1);
+    }
+    mLocalAddr.sin_port = htons(ntohs(mLocalAddr.sin_port) - 1);
+
+    // update client settings
+    memset(mRTPAddr.sin_zero, 0, sizeof(mRTPAddr.sin_zero));
+    mRTPAddr.sin_family = AF_INET;
+    mRTPAddr.sin_addr.s_addr = inet_addr(remoteIp.string());
+    mRTPAddr.sin_port = htons((unsigned short int)remotePort);
+
+    mRTCPAddr = mRTPAddr;
+    mRTCPAddr.sin_port = htons(ntohs(mRTPAddr.sin_port) | 1);
+
+    ALOGD("localIp=%s, rtp=%d, rtcp=%d", localIp.string(), localPort, localPort+1);
+    ALOGD("remoteIp=%s, rtp=%d, rtcp=%d", remoteIp.string(), ntohs(mRTPAddr.sin_port),
+            ntohs(mRTCPAddr.sin_port));
+
+    mSPSBuf = NULL;
+    mPPSBuf = NULL;
 
 #if LOG_TO_FILES
     mRTPFd = open(
@@ -97,11 +188,24 @@
     mRTPFd = -1;
 #endif
 
-    close(mSocket);
-    mSocket = -1;
+    close(mRTPSocket);
+    mRTPSocket = -1;
+
+    close(mRTCPSocket);
+    mRTCPSocket = -1;
 
     close(mFd);
     mFd = -1;
+
+    if(mSPSBuf != NULL) {
+        mSPSBuf->release();
+        mSPSBuf = NULL;
+    }
+
+    if(mPPSBuf != NULL) {
+        mPPSBuf->release();
+        mPPSBuf = NULL;
+    }
 }
 
 status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
@@ -123,7 +227,7 @@
     mFlags &= ~kFlagEOS;
     mSourceID = rand();
     mSeqNo = UniformRand(65536);
-    mRTPTimeBase = rand();
+    mRTPTimeBase = 0;
     mNumRTPSent = 0;
     mNumRTPOctetsSent = 0;
     mLastRTPTime = 0;
@@ -173,9 +277,12 @@
     return OK;
 }
 
-static void StripStartcode(MediaBufferBase *buffer) {
+// return size of SPS if there is more NAL unit found following to SPS.
+static uint32_t StripStartcode(MediaBufferBase *buffer) {
+    uint32_t nalSize = 0;
+
     if (buffer->range_length() < 4) {
-        return;
+        return 0;
     }
 
     const uint8_t *ptr =
@@ -185,6 +292,56 @@
         buffer->set_range(
                 buffer->range_offset() + 4, buffer->range_length() - 4);
     }
+
+    ptr = (const uint8_t *)buffer->data() + buffer->range_offset();
+
+    if ((*ptr & H264_NALU_MASK) == H264_NALU_SPS) {
+        for (uint32_t i = 0; i < buffer->range_length(); i++) {
+
+            if (!memcmp(ptr + i, "\x00\x00\x00\x01", 4)) {
+                // Now, we found one more NAL unit in the media buffer.
+                // Mostly, it will be a PPS.
+                nalSize = i;
+                ALOGV("SPS found. size=%d", nalSize);
+            }
+        }
+    }
+
+    return nalSize;
+}
+
+static void SpsPpsParser(MediaBufferBase *mediaBuffer,
+    MediaBufferBase **spsBuffer, MediaBufferBase **ppsBuffer, uint32_t spsSize) {
+
+    if (mediaBuffer == NULL || mediaBuffer->range_length() < 4)
+        return;
+
+    if((*spsBuffer) != NULL) {
+        (*spsBuffer)->release();
+        (*spsBuffer) = NULL;
+    }
+
+    if((*ppsBuffer) != NULL) {
+        (*ppsBuffer)->release();
+        (*ppsBuffer) = NULL;
+    }
+
+    // we got sps/pps but startcode of sps is striped.
+    (*spsBuffer) = MediaBufferBase::Create(spsSize);
+    int32_t ppsSize = mediaBuffer->range_length() - spsSize - 4/*startcode*/;
+    (*ppsBuffer) = MediaBufferBase::Create(ppsSize);
+    memcpy((*spsBuffer)->data(),
+            (const uint8_t *)mediaBuffer->data() + mediaBuffer->range_offset(),
+            spsSize);
+
+    if (ppsSize > 0) {
+        ALOGV("PPS found. size=%d", (int)ppsSize);
+        mediaBuffer->set_range(mediaBuffer->range_offset() + spsSize + 4/*startcode*/,
+                mediaBuffer->range_length() - spsSize - 4/*startcode*/);
+        memcpy((*ppsBuffer)->data(),
+                (const uint8_t *)mediaBuffer->data() + mediaBuffer->range_offset(),
+                ppsSize);
+    }
 }
 
 void ARTPWriter::onMessageReceived(const sp<AMessage> &msg) {
@@ -280,8 +437,12 @@
         ALOGV("read buffer of size %zu", mediaBuf->range_length());
 
         if (mMode == H264) {
-            StripStartcode(mediaBuf);
-            sendAVCData(mediaBuf);
+            uint32_t spsSize = 0;
+            if ((spsSize = StripStartcode(mediaBuf)) > 0) {
+                SpsPpsParser(mediaBuf, &mSPSBuf, &mPPSBuf, spsSize);
+            } else {
+                sendAVCData(mediaBuf);
+            }
         } else if (mMode == H263) {
             sendH263Data(mediaBuf);
         } else if (mMode == AMR_NB || mMode == AMR_WB) {
@@ -310,7 +471,7 @@
 
 void ARTPWriter::send(const sp<ABuffer> &buffer, bool isRTCP) {
     ssize_t n = sendto(
-            mSocket, buffer->data(), buffer->size(), 0,
+            isRTCP ? mRTCPSocket : mRTPSocket, buffer->data(), buffer->size(), 0,
             (const struct sockaddr *)(isRTCP ? &mRTCPAddr : &mRTPAddr),
             sizeof(mRTCPAddr));
 
@@ -569,6 +730,26 @@
     send(buffer, true /* isRTCP */);
 }
 
+void ARTPWriter::sendSPSPPSIfIFrame(MediaBufferBase *mediaBuf, int64_t timeUs) {
+    const uint8_t *mediaData =
+        (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
+
+    if ((mediaData[0] & H264_NALU_MASK) != H264_NALU_IFRAME)
+        return;
+
+    if (mSPSBuf != NULL) {
+        mSPSBuf->meta_data().setInt64(kKeyTime, timeUs);
+        mSPSBuf->meta_data().setInt32(kKeySps, 1);
+        sendAVCData(mSPSBuf);
+    }
+
+    if (mPPSBuf != NULL) {
+        mPPSBuf->meta_data().setInt64(kKeyTime, timeUs);
+        mPPSBuf->meta_data().setInt32(kKeyPps, 1);
+        sendAVCData(mPPSBuf);
+    }
+}
+
 void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
     // 12 bytes RTP header + 2 bytes for the FU-indicator and FU-header.
     CHECK_GE(kMaxPacketSize, 12u + 2u);
@@ -576,17 +757,30 @@
     int64_t timeUs;
     CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
 
+    sendSPSPPSIfIFrame(mediaBuf, timeUs);
+
     uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
 
     const uint8_t *mediaData =
         (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
 
+    int32_t sps, pps;
+    bool isSpsPps = false;
+    if (mediaBuf->meta_data().findInt32(kKeySps, &sps) ||
+            mediaBuf->meta_data().findInt32(kKeyPps, &pps)) {
+        isSpsPps = true;
+    }
+
     sp<ABuffer> buffer = new ABuffer(kMaxPacketSize);
-    if (mediaBuf->range_length() + 12 <= buffer->capacity()) {
+    if (mediaBuf->range_length() + UDP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_PAYLOAD_ROOM_SIZE
+            <= buffer->capacity()) {
         // The data fits into a single packet
         uint8_t *data = buffer->data();
         data[0] = 0x80;
-        data[1] = (1 << 7) | PT;  // M-bit
+        if (isSpsPps)
+            data[1] = PT;  // Marker bit should not be set in case of sps/pps
+        else
+            data[1] = (1 << 7) | PT;
         data[2] = (mSeqNo >> 8) & 0xff;
         data[3] = mSeqNo & 0xff;
         data[4] = rtpTime >> 24;
@@ -618,9 +812,11 @@
         while (offset < mediaBuf->range_length()) {
             size_t size = mediaBuf->range_length() - offset;
             bool lastPacket = true;
-            if (size + 12 + 2 > buffer->capacity()) {
+            if (size + UDP_HEADER_SIZE + RTP_HEADER_SIZE + RTP_FU_HEADER_SIZE +
+                    RTP_PAYLOAD_ROOM_SIZE > buffer->capacity()) {
                 lastPacket = false;
-                size = buffer->capacity() - 12 - 2;
+                size = buffer->capacity() - UDP_HEADER_SIZE - RTP_HEADER_SIZE -
+                    RTP_FU_HEADER_SIZE - RTP_PAYLOAD_ROOM_SIZE;
             }
 
             uint8_t *data = buffer->data();
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 2f13486..6795d28 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -36,6 +36,8 @@
 
 struct ARTPWriter : public MediaWriter {
     explicit ARTPWriter(int fd);
+    explicit ARTPWriter(int fd, String8& localIp, int localPort,
+                                String8& remoteIp, int remotePort);
 
     virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
@@ -76,7 +78,8 @@
     sp<ALooper> mLooper;
     sp<AHandlerReflector<ARTPWriter> > mReflector;
 
-    int mSocket;
+    int mRTPSocket, mRTCPSocket;
+    struct sockaddr_in mLocalAddr;
     struct sockaddr_in mRTPAddr;
     struct sockaddr_in mRTCPAddr;
 
@@ -84,6 +87,9 @@
     AString mSeqParamSet;
     AString mPicParamSet;
 
+    MediaBufferBase *mSPSBuf;
+    MediaBufferBase *mPPSBuf;
+
     uint32_t mSourceID;
     uint32_t mSeqNo;
     uint32_t mRTPTimeBase;
@@ -114,6 +120,7 @@
     void dumpSessionDesc();
 
     void sendBye();
+    void sendSPSPPSIfIFrame(MediaBufferBase *mediaBuf, int64_t timeUs);
     void sendAVCData(MediaBufferBase *mediaBuf);
     void sendH263Data(MediaBufferBase *mediaBuf);
     void sendAMRData(MediaBufferBase *mediaBuf);