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/include/pjmedia-codec/h263_packetizer.h b/pjmedia/include/pjmedia-codec/h263_packetizer.h
index 930115a..b80faf8 100644
--- a/pjmedia/include/pjmedia-codec/h263_packetizer.h
+++ b/pjmedia/include/pjmedia-codec/h263_packetizer.h
@@ -22,121 +22,122 @@
 
 /**
  * @file h263_packetizer.h
- * @brief Packetizes H.263 bitstream into RTP payload.
+ * @brief Packetizes/unpacketizes H.263 bitstream into RTP payload.
  */
 
-#include <pj/errno.h>
+#include <pj/pool.h>
+#include <pj/types.h>
 
 PJ_BEGIN_DECL
 
-/**
- * Find synchronization point (PSC, slice, GSBC, EOS, EOSBS) in H.263 
- * bitstream, in reversed manner.
- */
-PJ_INLINE(pj_uint8_t*) pjmedia_h263_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;
-}
 
 /**
- * Generate an RTP payload from H.263 frame bitstream, in-place processing.
+ * Opaque declaration for H.263 packetizer.
  */
-PJ_INLINE(pj_status_t) pjmedia_h263_packetize(pj_uint8_t *buf,
-                                              pj_size_t buf_len,
-                                              unsigned *pos,
-                                              int max_payload_len,
-                                              const pj_uint8_t **payload,
-                                              pj_size_t *payload_len)
+typedef struct pjmedia_h263_packetizer pjmedia_h263_packetizer;
+
+
+/**
+ * Enumeration of H.263 packetization modes.
+ */
+typedef enum
 {
-    pj_uint8_t *p, *p_end;
-
-    p = buf + *pos;
-    p_end = buf + buf_len;
-
-    /* Put two octets payload header */
-    if ((p_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.
+    /**
+     * H.263 RTP packetization using RFC 4629.
      */
-    if (p_end-p > max_payload_len) {
-        p_end = pjmedia_h263_find_sync_point_rev(p+2, max_payload_len-2);
-    }
+    PJMEDIA_H263_PACKETIZER_MODE_RFC4629,
 
-    *payload = p;
-    *payload_len = p_end-p;
-    *pos = p_end - buf;
+    /**
+     * H.263 RTP packetization using legacy RFC 2190.
+     * This is currently not supported.
+     */
+    PJMEDIA_H263_PACKETIZER_MODE_RFC2190,
 
-    return PJ_SUCCESS;
-}
+} pjmedia_h263_packetizer_mode;
+
 
 /**
- * Append RTP payload to a H.263 picture bitstream.
+ * H.263 packetizer configuration.
  */
-PJ_INLINE(pj_status_t) pjmedia_h263_unpacketize(const pj_uint8_t *payload,
-                                                pj_size_t   payload_len,
-                                                pj_uint8_t *bits,
-                                                pj_size_t  *bits_len)
+typedef struct pjmedia_h263_packetizer_cfg
 {
-    pj_uint8_t P, V, PLEN;
-    const pj_uint8_t *p=payload;
-    pj_size_t max_len = *bits_len;
+    /**
+     * Maximum payload length.
+     * Default: PJMEDIA_MAX_MTU
+     */
+    int	mtu;
 
-    P = *p & 0x04;
-    V = *p & 0x02;
-    PLEN = ((*p & 0x01) << 5) + ((*(p+1) & 0xF8)>>3);
+    /**
+     * Packetization mode.
+     * Default: PJMEDIA_H263_PACKETIZER_MODE_RFC4629
+     */
+    pjmedia_h263_packetizer_mode mode;
 
-    /* Get bitstream pointer */
-    p += 2;
-    if (V)
-        p += 1; /* Skip VRC data */
-    if (PLEN)
-        p += PLEN; /* Skip extra picture header data */
+} pjmedia_h263_packetizer_cfg;
 
-    /* Get bitstream length */
-    payload_len -= (p-payload);
 
-    *bits_len = payload_len + (P?2:0);
-    PJ_ASSERT_RETURN(max_len >= *bits_len, PJ_ETOOSMALL);
+/**
+ * Create H.263 packetizer.
+ *
+ * @param pool		The memory pool.
+ * @param cfg		Packetizer settings, if NULL, default setting
+ *			will be used.
+ * @param p_pktz	Pointer to receive the packetizer.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h263_packetizer_create(
+				    pj_pool_t *pool,
+				    const pjmedia_h263_packetizer_cfg *cfg,
+				    pjmedia_h263_packetizer **p_pktz);
 
-    /* Add two zero octets when payload flagged with sync point */
-    if (P) {
-        *bits++ = 0;
-        *bits++ = 0;
-    }
 
-    /* Add the bitstream */
-    pj_memcpy(bits, p, payload_len);
+/**
+ * Generate an RTP payload from a H.263 picture bitstream. Note that this
+ * function will apply in-place processing, so the bitstream may be modified
+ * during the packetization.
+ *
+ * @param pktz		The packetizer.
+ * @param bits		The picture bitstream to be packetized.
+ * @param bits_len	The length of the bitstream.
+ * @param bits_pos	The bitstream offset to be packetized.
+ * @param payload	The output payload.
+ * @param payload_len	The output payload length.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h263_packetize(pjmedia_h263_packetizer *pktz,
+					    pj_uint8_t *bits,
+                                            pj_size_t bits_len,
+                                            unsigned *bits_pos,
+                                            const pj_uint8_t **payload,
+                                            pj_size_t *payload_len);
 
-    return PJ_SUCCESS;
-}
+
+/**
+ * Append an RTP payload to an H.263 picture bitstream. Note that in case of
+ * noticing packet lost, application should keep calling this function with
+ * payload pointer set to NULL, as the packetizer need to update its internal
+ * state.
+ *
+ * @param pktz		The packetizer.
+ * @param payload	The payload to be unpacketized.
+ * @param payload_len	The payload length.
+ * @param bits		The bitstream buffer.
+ * @param bits_size	The bitstream buffer size.
+ * @param bits_pos	The bitstream offset to put the unpacketized payload
+ *			in the bitstream, upon return, this will be updated
+ *			to the latest offset as a result of the unpacketized
+ *			payload.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(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 *bits_pos);
 
 
 PJ_END_DECL
diff --git a/pjmedia/include/pjmedia-codec/h264_packetizer.h b/pjmedia/include/pjmedia-codec/h264_packetizer.h
new file mode 100644
index 0000000..a676a04
--- /dev/null
+++ b/pjmedia/include/pjmedia-codec/h264_packetizer.h
@@ -0,0 +1,157 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2011 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 
+ */
+#ifndef __PJMEDIA_H264_PACKETIZER_H__
+#define __PJMEDIA_H264_PACKETIZER_H__
+
+/**
+ * @file h264_packetizer.h
+ * @brief Packetizes H.264 bitstream into RTP payload and vice versa.
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * Opaque declaration for H.264 packetizer.
+ */
+typedef struct pjmedia_h264_packetizer pjmedia_h264_packetizer;
+
+
+/**
+ * Enumeration of H.264 packetization modes.
+ */
+typedef enum
+{
+    /**
+     * Single NAL unit packetization mode will only generate payloads
+     * containing a complete single NAL unit packet. As H.264 NAL unit
+     * size can be very large, this mode is usually not applicable for
+     * network environments with MTU size limitation.
+     */
+    PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL,
+    
+    /**
+     * Non-interleaved packetization mode will generate payloads with the
+     * following possible formats:
+     * - single NAL unit packets,
+     * - NAL units aggregation STAP-A packets,
+     * - fragmented NAL unit FU-A packets.
+     */
+    PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED,
+
+    /**
+     * Interleaved packetization mode will generate payloads with the
+     * following possible formats:
+     * - single NAL unit packets,
+     * - NAL units aggregation STAP-A & STAP-B packets,
+     * - fragmented NAL unit FU-A & FU-B packets.
+     * This packetization mode is currently unsupported.
+     */
+    PJMEDIA_H264_PACKETIZER_MODE_INTERLEAVED,
+} pjmedia_h264_packetizer_mode;
+
+
+/**
+ * H.264 packetizer setting.
+ */
+typedef struct pjmedia_h264_packetizer_cfg
+{
+    /**
+     * Maximum payload length.
+     * Default: PJMEDIA_MAX_MTU
+     */
+    int	mtu;
+
+    /**
+     * Packetization mode.
+     * Default: PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED
+     */
+    pjmedia_h264_packetizer_mode mode;
+}
+pjmedia_h264_packetizer_cfg;
+
+
+/**
+ * Create H.264 packetizer.
+ *
+ * @param pool		The memory pool.
+ * @param cfg		Packetizer settings, if NULL, default setting
+ *			will be used.
+ * @param p_pktz	Pointer to receive the packetizer.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_packetizer_create(
+				    pj_pool_t *pool,
+				    const pjmedia_h264_packetizer_cfg *cfg,
+				    pjmedia_h264_packetizer **p_pktz);
+
+
+/**
+ * Generate an RTP payload from a H.264 picture bitstream. Note that this
+ * function will apply in-place processing, so the bitstream may be modified
+ * during the packetization.
+ *
+ * @param pktz		The packetizer.
+ * @param bits		The picture bitstream to be packetized.
+ * @param bits_len	The length of the bitstream.
+ * @param bits_pos	The bitstream offset to be packetized.
+ * @param payload	The output payload.
+ * @param payload_len	The output payload length.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_packetize(pjmedia_h264_packetizer *pktz,
+					    pj_uint8_t *bits,
+                                            pj_size_t bits_len,
+                                            unsigned *bits_pos,
+                                            const pj_uint8_t **payload,
+                                            pj_size_t *payload_len);
+
+
+/**
+ * Append an RTP payload to an H.264 picture bitstream. Note that in case of
+ * noticing packet lost, application should keep calling this function with
+ * payload pointer set to NULL, as the packetizer need to update its internal
+ * state.
+ *
+ * @param pktz		The packetizer.
+ * @param payload	The payload to be unpacketized.
+ * @param payload_len	The payload length.
+ * @param bits		The bitstream buffer.
+ * @param bits_size	The bitstream buffer size.
+ * @param bits_pos	The bitstream offset to put the unpacketized payload
+ *			in the bitstream, upon return, this will be updated
+ *			to the latest offset as a result of the unpacketized
+ *			payload.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
+					      const pj_uint8_t *payload,
+                                              pj_size_t   payload_len,
+                                              pj_uint8_t *bits,
+                                              pj_size_t   bits_len,
+					      unsigned   *bits_pos);
+
+
+PJ_END_DECL
+
+#endif	/* __PJMEDIA_H264_PACKETIZER_H__ */
diff --git a/pjmedia/include/pjmedia/format.h b/pjmedia/include/pjmedia/format.h
index ae31f98..5fcf8f3 100644
--- a/pjmedia/include/pjmedia/format.h
+++ b/pjmedia/include/pjmedia/format.h
@@ -457,12 +457,12 @@
 				 unsigned channel_count)
 {
 #if PJ_HAS_INT64
-    return ((unsigned)((pj_uint64_t)clock_rate * fr->num \
-		       / fr->denum / channel_count));
+    return ((unsigned)((pj_uint64_t)clock_rate * fr->denum \
+		       / fr->num / channel_count));
 #elif PJ_HAS_FLOATING_POINT
-    return ((unsigned)(1.0 * clock_rate * fr->num /fr->denum /channel_count));
+    return ((unsigned)(1.0* clock_rate * fr->denum / fr->num /channel_count));
 #else
-    return ((unsigned)(1L * clock_rate * fr->num / fr->denum / channel_count));
+    return ((unsigned)(1L * clock_rate * fr->denum / fr->num / channel_count));
 #endif
 }
 
diff --git a/pjmedia/include/pjmedia/vid_codec.h b/pjmedia/include/pjmedia/vid_codec.h
index 55d6abb..f36727b 100644
--- a/pjmedia/include/pjmedia/vid_codec.h
+++ b/pjmedia/include/pjmedia/vid_codec.h
@@ -223,7 +223,9 @@
      * picture boundary detection by itself, e.g: for RTP delivery, payloads
      * belong to the same picture will share the same RTP timestamp and also
      * there is marker bit in the RTP header that is usually reserved for
-     * end-of-picture flag.
+     * end-of-picture flag. Also note that in case of noticing packet lost,
+     * application should keep calling this function with payload pointer
+     * set to NULL, as the packetizer need to update its internal state.
      *
      * @param codec	The codec instance
      * @param pkt	The input packet.
@@ -241,7 +243,8 @@
                                const pj_uint8_t *payload,
                                pj_size_t   payload_len,
                                pj_uint8_t *bits,
-                               pj_size_t  *bits_len);
+                               pj_size_t   bits_len,
+			       unsigned	  *bits_pos);
 
     /** 
      * Instruct the codec to encode the specified input frame. The input
diff --git a/pjmedia/include/pjmedia/vid_codec_util.h b/pjmedia/include/pjmedia/vid_codec_util.h
new file mode 100644
index 0000000..64271d1
--- /dev/null
+++ b/pjmedia/include/pjmedia/vid_codec_util.h
@@ -0,0 +1,120 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * 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 
+ */
+#ifndef __PJMEDIA_VID_CODEC_UTIL_H__
+#define __PJMEDIA_VID_CODEC_UTIL_H__
+
+
+/**
+ * @file vid_codec_util.h
+ * @brief Video codec utilities.
+ */
+
+#include <pjmedia/vid_codec.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * Definition of H.263 parameters.
+ */
+typedef struct pjmedia_vid_codec_h263_fmtp
+{
+    unsigned mpi_cnt;		    /**< # of parsed MPI param		    */
+    struct mpi {
+	pjmedia_rect_size   size;   /**< Picture size/resolution	    */
+	unsigned	    val;    /**< MPI value			    */
+    } mpi[8];			    /**< Minimum Picture Interval parameter */
+
+} pjmedia_vid_codec_h263_fmtp;
+
+
+/**
+ * Parse SDP fmtp of H.263.
+ *
+ * @param fmtp		The H.263 SDP fmtp to be parsed.
+ * @param h263_fmtp	The parsing result.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_h263_parse_fmtp(
+				const pjmedia_codec_fmtp *fmtp,
+				pjmedia_vid_codec_h263_fmtp *h263_fmtp);
+
+
+/**
+ * Parse, negotiate, and apply the encoding and decoding SDP fmtp of H.263
+ * in the specified codec parameter.
+ *
+ * @param param		The codec parameter.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_h263_apply_fmtp(
+				pjmedia_vid_codec_param *param);
+
+
+/**
+ * Definition of H.264 parameters.
+ */
+typedef struct pjmedia_vid_codec_h264_fmtp
+{
+    /* profile-level-id */
+    pj_uint8_t	    profile_idc;    /**< Profile ID			    */
+    pj_uint8_t	    profile_iop;    /**< Profile constraints bits	    */
+    pj_uint8_t	    level;	    /**< Level				    */
+
+    /* packetization-mode */
+    pj_uint8_t	    packetization_mode;	/**< Packetization mode		    */
+
+    /* max-mbps, max-fs, max-cpb, max-dpb, and max-br */
+    unsigned	    max_mbps;	    /**< Max macroblock processing rate	    */
+    unsigned	    max_fs;	    /**< Max frame size (in macroblocks)    */
+    unsigned	    max_cpb;	    /**< Max coded picture buffer size	    */
+    unsigned	    max_dpb;	    /**< Max decoded picture buffer size    */
+    unsigned	    max_br;	    /**< Max video bit rate		    */
+
+    /* sprop-parameter-sets, in NAL units */
+    pj_size_t	    sprop_param_sets_len;   /**< Parameter set length	    */
+    pj_uint8_t	    sprop_param_sets[256];  /**< Parameter set (SPS & PPS),
+						 in NAL unit bitstream	    */
+
+} pjmedia_vid_codec_h264_fmtp;
+
+
+/**
+ * Parse SDP fmtp of H.264.
+ *
+ * @param fmtp		The H.264 SDP fmtp to be parsed.
+ * @param h264_fmtp	The parsing result.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_codec_parse_h264_fmtp(
+				const pjmedia_codec_fmtp *fmtp,
+				pjmedia_vid_codec_h264_fmtp *h264_fmtp);
+
+
+
+
+PJ_END_DECL
+
+
+#endif	/* __PJMEDIA_VID_CODEC_UTIL_H__ */