Re #1219:
 - Initial version of H264 implementation (codec & packetization).
 - Added vid_codec_util.h/c for video codec utilities (e.g: fmtp parser).
 - Updated video RTP packetizations to be configurable and have internal state (to be more resilient to packet lost, etc).
 - Fixed wrong SPF calculation in PJMEDIA_SPF2.
 - Updated vid_codec_test.c to also have RTP packetization test.
 - Updated sdp_neg.c to verify H.264 capability match.



git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3493 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/src/pjmedia-codec/h263_packetizer.c b/pjmedia/src/pjmedia-codec/h263_packetizer.c
new file mode 100644
index 0000000..66d23c9
--- /dev/null
+++ b/pjmedia/src/pjmedia-codec/h263_packetizer.c
@@ -0,0 +1,283 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia-codec/h263_packetizer.h>
+#include <pjmedia/types.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+
+#define THIS_FILE	"h263_packetizer.c"
+
+
+/* H.263 packetizer definition */
+struct pjmedia_h263_packetizer {
+    /* Current settings */
+    pjmedia_h263_packetizer_cfg cfg;
+    
+    /* Unpacketizer state */
+    unsigned	    unpack_last_sync_pos;
+    pj_bool_t	    unpack_prev_lost;
+};
+
+
+/*
+ * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263 
+ * bitstream.
+ */
+static pj_uint8_t* find_sync_point(pj_uint8_t *data,
+				   pj_size_t data_len)
+{
+    pj_uint8_t *p = data, *end = data+data_len;
+
+    while (p < end && *p && *(p+1))
+        ++p;
+
+    if (p == end)
+        return NULL;
+        
+    return p;
+}
+
+
+/*
+ * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263 
+ * bitstream, in reversed manner.
+ */
+static pj_uint8_t* find_sync_point_rev(pj_uint8_t *data,
+                                       pj_size_t data_len)
+{
+    pj_uint8_t *p = data+data_len-1;
+
+    while (p > data && *p && *(p+1))
+        --p;
+
+    if (p == data)
+        return (data + data_len);
+        
+    return p;
+}
+
+
+/*
+ * Create H263 packetizer.
+ */
+PJ_DEF(pj_status_t) pjmedia_h263_packetizer_create(
+				pj_pool_t *pool,
+				const pjmedia_h263_packetizer_cfg *cfg,
+				pjmedia_h263_packetizer **p)
+{
+    pjmedia_h263_packetizer *p_;
+
+    PJ_ASSERT_RETURN(pool && p, PJ_EINVAL);
+
+    if (cfg && cfg->mode != PJMEDIA_H263_PACKETIZER_MODE_RFC4629)
+	return PJ_ENOTSUP;
+
+    p_ = PJ_POOL_ZALLOC_T(pool, pjmedia_h263_packetizer);
+    if (cfg) {
+	pj_memcpy(&p_->cfg, cfg, sizeof(*cfg));
+    } else {
+	p_->cfg.mode = PJMEDIA_H263_PACKETIZER_MODE_RFC4629;
+	p_->cfg.mtu = PJMEDIA_MAX_MTU;
+    }
+
+    *p = p_;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Generate an RTP payload from H.263 frame bitstream, in-place processing.
+ */
+PJ_DEF(pj_status_t) pjmedia_h263_packetize(pjmedia_h263_packetizer *pktz,
+					   pj_uint8_t *bits,
+                                           pj_size_t bits_len,
+                                           unsigned *pos,
+                                           const pj_uint8_t **payload,
+                                           pj_size_t *payload_len)
+{
+    pj_uint8_t *p, *end;
+
+    pj_assert(pktz && bits && pos && payload && payload_len);
+    pj_assert(*pos <= bits_len);
+
+    p = bits + *pos;
+    end = bits + bits_len;
+
+    /* Put two octets payload header */
+    if ((end-p > 2) && *p==0 && *(p+1)==0) {
+        /* The bitstream starts with synchronization point, just override
+         * the two zero octets (sync point mark) for payload header.
+         */
+        *p = 0x04;
+    } else {
+        /* Not started in synchronization point, we will use two octets
+         * preceeding the bitstream for payload header!
+         */
+
+	if (*pos < 2) {
+	    /* Invalid H263 bitstream, it's not started with PSC */
+	    return PJ_EINVAL;
+	}
+
+	p -= 2;
+        *p = 0;
+    }
+    *(p+1) = 0;
+
+    /* When bitstream truncation needed because of payload length/MTU 
+     * limitation, try to use sync point for the payload boundary.
+     */
+    if (end-p > pktz->cfg.mtu) {
+	end = find_sync_point_rev(p+2, pktz->cfg.mtu-2);
+    }
+
+    *payload = p;
+    *payload_len = end-p;
+    *pos = end - bits;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Append an RTP payload to a H.263 picture bitstream.
+ */
+PJ_DEF(pj_status_t) pjmedia_h263_unpacketize (pjmedia_h263_packetizer *pktz,
+					      const pj_uint8_t *payload,
+                                              pj_size_t payload_len,
+                                              pj_uint8_t *bits,
+                                              pj_size_t bits_size,
+					      unsigned *pos)
+{
+    pj_uint8_t P, V, PLEN;
+    const pj_uint8_t *p = payload;
+    pj_uint8_t *q;
+
+    q = bits + *pos;
+
+    /* Check if this is a missing/lost packet */
+    if (payload == NULL) {
+	pktz->unpack_prev_lost = PJ_TRUE;
+	return PJ_SUCCESS;
+    }
+
+    /* H263 payload header size is two octets */
+    if (payload_len < 2) {
+	/* Invalid bitstream, discard this payload */
+	pktz->unpack_prev_lost = PJ_TRUE;
+	return PJ_EINVAL;
+    }
+
+    /* Get payload header info */
+    P = *p & 0x04;
+    V = *p & 0x02;
+    PLEN = ((*p & 0x01) << 5) + ((*(p+1) & 0xF8)>>3);
+
+    /* Get start bitstream pointer */
+    p += 2;	    /* Skip payload header */
+    if (V)
+        p += 1;	    /* Skip VRC data */
+    if (PLEN)
+        p += PLEN;  /* Skip extra picture header data */
+
+    /* Get bitstream length */
+    if (payload_len > (pj_size_t)(p - payload)) {
+	payload_len -= (p - payload);
+    } else {
+	/* Invalid bitstream, discard this payload */
+	pktz->unpack_prev_lost = PJ_TRUE;
+	return PJ_EINVAL;
+    }
+
+    /* Validate bitstream length */
+    if (bits_size < *pos + payload_len + 2) {
+	/* Insufficient bistream buffer, discard this payload */
+	pj_assert(!"Insufficient H.263 bitstream buffer");
+	pktz->unpack_prev_lost = PJ_TRUE;
+	return PJ_ETOOSMALL;
+    }
+
+    /* Start writing bitstream */
+
+    /* No sync point flag */
+    if (!P) {
+	if (*pos == 0) {
+	    /* Previous packet must be lost */
+	    pktz->unpack_prev_lost = PJ_TRUE;
+
+	    /* If there is extra picture header, let's use it. */
+	    if (PLEN) {
+		/* Write two zero octets for PSC */
+		*q++ = 0;
+		*q++ = 0;
+		/* Copy the picture header */
+		p -= PLEN;
+		pj_memcpy(q, p, PLEN);
+		p += PLEN;
+		q += PLEN;
+	    }
+	} else if (pktz->unpack_prev_lost) {
+	    /* If prev packet was lost, revert the bitstream pointer to
+	     * the last sync point.
+	     */
+	    pj_assert(pktz->unpack_last_sync_pos <= *pos);
+	    q = bits + pktz->unpack_last_sync_pos;
+	}
+
+	/* There was packet lost, see if this payload contain sync point
+	 * (usable data).
+	 */
+	if (pktz->unpack_prev_lost) {
+	    pj_uint8_t *sync;
+	    sync = find_sync_point((pj_uint8_t*)p, payload_len);
+	    if (sync) {
+		/* Got sync point, update P/sync-point flag */
+		P = 1;
+		/* Skip the two zero octets */
+		sync += 2;
+		/* Update payload length and start bitstream pointer */
+		payload_len -= (sync - p);
+		p = sync;
+	    } else {
+		/* No sync point in it, just discard this payload */
+		return PJ_EIGNORED;
+	    }
+	}
+    }
+
+    /* Write two zero octets when payload flagged with sync point */
+    if (P) {
+	pktz->unpack_last_sync_pos = q - bits;
+        *q++ = 0;
+        *q++ = 0;
+    }
+
+    /* Write the payload to the bitstream */
+    pj_memcpy(q, p, payload_len);
+    q += payload_len;
+
+    /* Update the bitstream writing offset */
+    *pos = q - bits;
+
+    pktz->unpack_prev_lost = PJ_FALSE;
+
+    return PJ_SUCCESS;
+}