Index: pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/sdp.h
===================================================================
--- pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/sdp.h	(revision 3418)
+++ pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/sdp.h	(revision 3419)
@@ -366,4 +366,18 @@
 						  const pjmedia_sdp_conn *rhs);
 
+
+/** 
+ * Compare connection info. 
+ * 
+ * @param conn1	    The first connection info to compare.
+ * @param conn1	    The second connection info to compare.
+ * @param option    Comparison option, which should be zero for now.
+ *
+ * @return	    PJ_SUCCESS when both connection info are equal, otherwise
+ *		    returns PJMEDIA_SDP_ECONNNOTEQUAL.
+ */
+PJ_DECL(pj_status_t) pjmedia_sdp_conn_cmp(const pjmedia_sdp_conn *conn1, 
+					  const pjmedia_sdp_conn *conn2,
+					  unsigned option);
 
 
Index: pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/stream_common.h
===================================================================
--- pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/stream_common.h	(revision 3419)
+++ pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/stream_common.h	(revision 3419)
@@ -0,0 +1,55 @@
+/* $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_STREAM_COMMON_H__
+#define __PJMEDIA_STREAM_COMMON_H__
+
+
+/**
+ * @file stream_common.h
+ * @brief Stream common functions.
+ */
+
+#include <pjmedia/codec.h>
+#include <pjmedia/sdp.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * This is internal function for parsing SDP format parameter of specific format
+ * or payload type, used by stream in generating stream info from SDP.
+ *
+ * @param pool		Pool to allocate memory.
+ * @param m		The SDP media containing the format parameter to
+ *			be parsed.
+ * @param pt		The format or payload type.
+ * @param fmtp		The format parameter to store the parsing result.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_info_parse_fmtp(pj_pool_t *pool,
+						    const pjmedia_sdp_media *m,
+						    unsigned pt,
+						    pjmedia_codec_fmtp *fmtp);
+
+
+PJ_END_DECL
+
+
+#endif /* __PJMEDIA_STREAM_COMMON_H__ */
Index: pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/endpoint.c	(revision 3418)
+++ pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/endpoint.c	(revision 3419)
@@ -21,4 +21,5 @@
 #include <pjmedia/errno.h>
 #include <pjmedia/sdp.h>
+#include <pjmedia/vid_codec.h>
 #include <pjmedia-audiodev/audiodev.h>
 #include <pj/assert.h>
@@ -320,23 +321,11 @@
 }
 
-/**
- * Create a SDP session description that describes the endpoint
- * capability.
- */
-PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
-					      pj_pool_t *pool,
-					      unsigned stream_cnt,
-					      const pjmedia_sock_info sock_info[],
-					      pjmedia_sdp_session **p_sdp )
-{
-    pj_time_val tv;
+
+static pj_status_t init_sdp_media_audio_format(pj_pool_t *pool,
+					       pjmedia_endpt *endpt,
+					       pjmedia_sdp_media *m)
+{
+    pjmedia_sdp_attr *attr;
     unsigned i;
-    const pj_sockaddr *addr0;
-    pjmedia_sdp_session *sdp;
-    pjmedia_sdp_media *m;
-    pjmedia_sdp_attr *attr;
-
-    /* Sanity check arguments */
-    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);
 
     /* Check that there are not too many codecs */
@@ -344,70 +333,4 @@
 		     PJ_ETOOMANY);
 
-    /* Create and initialize basic SDP session */
-    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
-
-    addr0 = &sock_info[0].rtp_addr_name;
-
-    pj_gettimeofday(&tv);
-    sdp->origin.user = pj_str("-");
-    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
-    sdp->origin.net_type = STR_IN;
-
-    if (addr0->addr.sa_family == pj_AF_INET()) {
-	sdp->origin.addr_type = STR_IP4;
-	pj_strdup2(pool, &sdp->origin.addr, 
-		   pj_inet_ntoa(addr0->ipv4.sin_addr));
-    } else if (addr0->addr.sa_family == pj_AF_INET6()) {
-	char tmp_addr[PJ_INET6_ADDRSTRLEN];
-
-	sdp->origin.addr_type = STR_IP6;
-	pj_strdup2(pool, &sdp->origin.addr, 
-		   pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0));
-
-    } else {
-	pj_assert(!"Invalid address family");
-	return PJ_EAFNOTSUP;
-    }
-
-    sdp->name = STR_SDP_NAME;
-
-    /* Since we only support one media stream at present, put the
-     * SDP connection line in the session level.
-     */
-    sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
-    sdp->conn->net_type = sdp->origin.net_type;
-    sdp->conn->addr_type = sdp->origin.addr_type;
-    sdp->conn->addr = sdp->origin.addr;
-
-
-    /* SDP time and attributes. */
-    sdp->time.start = sdp->time.stop = 0;
-    sdp->attr_count = 0;
-
-    /* Create media stream 0: */
-
-    sdp->media_count = 1;
-    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
-    sdp->media[0] = m;
-
-    /* Standard media info: */
-    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
-    m->desc.port = pj_sockaddr_get_port(addr0);
-    m->desc.port_count = 1;
-    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
-
-    /* Init media line and attribute list. */
-    m->desc.fmt_count = 0;
-    m->attr_count = 0;
-
-    /* Add "rtcp" attribute */
-#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
-    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
-	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
-	if (attr)
-	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
-    }
-#endif
-
     /* Add format, rtpmap, and fmtp (when applicable) for each codec */
     for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
@@ -416,5 +339,4 @@
 	pjmedia_sdp_rtpmap rtpmap;
 	char tmp_param[3];
-	pjmedia_sdp_attr *attr;
 	pjmedia_codec_param codec_param;
 	pj_str_t *fmt;
@@ -520,9 +442,4 @@
     }
 
-    /* Add sendrecv attribute. */
-    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
-    attr->name = STR_SENDRECV;
-    m->attr[m->attr_count++] = attr;
-
 #if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
     PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
@@ -548,4 +465,279 @@
     }
 #endif
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t init_sdp_media_video_format(pj_pool_t *pool,
+					       pjmedia_endpt *endpt,
+					       pjmedia_sdp_media *m)
+{
+    pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
+    unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
+    pjmedia_sdp_attr *attr;
+    unsigned cnt, i;
+    pj_status_t status;
+
+    /* Make sure video codec manager is instantiated */
+    if (!pjmedia_vid_codec_mgr_instance())
+	pjmedia_vid_codec_mgr_create(endpt->pool, NULL);
+
+    cnt = PJ_ARRAY_SIZE(codec_info);
+    status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, 
+					       codec_info, codec_prio);
+
+    /* Check that there are not too many codecs */
+    PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
+		     PJ_ETOOMANY);
+
+    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
+    for (i=0; i<cnt; ++i) {
+
+	pjmedia_sdp_rtpmap rtpmap = {0};
+	pjmedia_vid_codec_param codec_param;
+	pj_str_t *fmt;
+
+	if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
+	    break;
+
+	if (i > PJMEDIA_MAX_SDP_FMT) {
+	    /* Too many codecs, perhaps it is better to tell application by
+	     * returning appropriate status code.
+	     */
+	    PJ_LOG(3, (THIS_FILE, "Too many video codecs"));
+	    break;
+	}
+
+	/* Payload type */
+	if (codec_info[i].pt == 255) {
+	    PJ_TODO(ALLOCATE_DYNAMIC_PAYLOAD_TYPE);
+	    continue;
+	}
+
+	pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
+						&codec_param);
+
+	fmt = &m->desc.fmt[m->desc.fmt_count++];
+	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
+	fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
+	rtpmap.pt = *fmt;
+
+	/* Encoding name */
+	rtpmap.enc_name = codec_info[i].encoding_name;
+
+	/* Clock rate */
+	rtpmap.clock_rate = codec_info[i].clock_rate;
+
+	if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
+	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
+	    m->attr[m->attr_count++] = attr;
+	}
+
+	/* Add fmtp params */
+	if (codec_param.dec_fmtp.cnt > 0) {
+	    enum { MAX_FMTP_STR_LEN = 160 };
+	    char buf[MAX_FMTP_STR_LEN];
+	    unsigned buf_len = 0, j;
+	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;
+
+	    /* Print codec PT */
+	    buf_len += pj_ansi_snprintf(buf, 
+					MAX_FMTP_STR_LEN - buf_len, 
+					"%d", 
+					codec_info[i].pt);
+
+	    for (j = 0; j < dec_fmtp->cnt; ++j) {
+		unsigned test_len = 2;
+
+		/* Check if buf still available */
+		test_len = dec_fmtp->param[j].val.slen + 
+			   dec_fmtp->param[j].name.slen;
+		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
+		    return PJ_ETOOBIG;
+
+		/* Print delimiter */
+		buf_len += pj_ansi_snprintf(&buf[buf_len], 
+					    MAX_FMTP_STR_LEN - buf_len,
+					    (j == 0?" ":";"));
+
+		/* Print an fmtp param */
+		if (dec_fmtp->param[j].name.slen)
+		    buf_len += pj_ansi_snprintf(
+					    &buf[buf_len],
+					    MAX_FMTP_STR_LEN - buf_len,
+					    "%.*s=%.*s",
+					    (int)dec_fmtp->param[j].name.slen,
+					    dec_fmtp->param[j].name.ptr,
+					    (int)dec_fmtp->param[j].val.slen,
+					    dec_fmtp->param[j].val.ptr);
+		else
+		    buf_len += pj_ansi_snprintf(&buf[buf_len], 
+					    MAX_FMTP_STR_LEN - buf_len,
+					    "%.*s", 
+					    (int)dec_fmtp->param[j].val.slen,
+					    dec_fmtp->param[j].val.ptr);
+	    }
+
+	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+
+	    attr->name = pj_str("fmtp");
+	    attr->value = pj_strdup3(pool, buf);
+	    m->attr[m->attr_count++] = attr;
+	}
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t add_sdp_media(pjmedia_endpt *endpt,
+				 pj_pool_t *pool,
+				 pjmedia_type type,
+				 const pjmedia_sock_info *sock_info,
+				 pjmedia_sdp_session *sdp)
+{
+    pjmedia_sdp_media *m;
+    pjmedia_sdp_attr *attr;
+    pjmedia_sdp_conn conn;
+    const pj_sockaddr *addr;
+    pj_status_t status;
+
+    addr = &sock_info->rtp_addr_name;
+
+    /* Validate address family */
+    if (addr->addr.sa_family != pj_AF_INET() &&
+	addr->addr.sa_family != pj_AF_INET6())
+    {
+	pj_assert(!"Invalid address family");
+	return PJ_EAFNOTSUP;
+    }
+
+    /* Validate media type */
+    if (type != PJMEDIA_TYPE_AUDIO && type != PJMEDIA_TYPE_VIDEO) {
+	pj_assert(!"Invalid mediay type");
+	return PJMEDIA_EINVALIMEDIATYPE;
+    }
+
+    /* Allocate SDP media */
+    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
+
+    /* Connection data, if not the same to one in the session level */
+    {
+	char tmp_addr[PJ_INET6_ADDRSTRLEN];
+	pj_bzero(&conn, sizeof(conn));
+	conn.net_type = STR_IN;
+	conn.addr_type = (addr->addr.sa_family==pj_AF_INET())? STR_IP4:STR_IP6;
+	pj_sockaddr_print(addr, tmp_addr, sizeof(tmp_addr), 0);
+	pj_strset2(&conn.addr, tmp_addr);
+
+	if (pjmedia_sdp_conn_cmp(&conn, sdp->conn, 0) != PJ_SUCCESS)
+	    m->conn = pjmedia_sdp_conn_clone(pool, &conn);
+    }
+
+    /* Port and transport in media description */
+    m->desc.port = pj_sockaddr_get_port(addr);
+    m->desc.port_count = 1;
+    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
+
+    /* Media formats and parameters */
+    if (type == PJMEDIA_TYPE_AUDIO) {
+	pj_strdup(pool, &m->desc.media, &STR_AUDIO);
+	status = init_sdp_media_audio_format(pool, endpt, m);
+    } else {
+	pj_strdup(pool, &m->desc.media, &STR_VIDEO);
+	status = init_sdp_media_video_format(pool, endpt, m);
+    }
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Add "rtcp" attribute */
+#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
+    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
+	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
+	if (attr)
+	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
+    }
+#endif
+
+    /* Add sendrecv attribute. */
+    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+    attr->name = STR_SENDRECV;
+    m->attr[m->attr_count++] = attr;
+
+    /* Done */
+    sdp->media[sdp->media_count++] = m;
+
+    return PJ_SUCCESS;
+}
+
+/**
+ * Create a SDP session description that describes the endpoint
+ * capability.
+ */
+PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
+					      pj_pool_t *pool,
+					      unsigned stream_cnt,
+					      const pjmedia_sock_info sock_info[],
+					      pjmedia_sdp_session **p_sdp )
+{
+    pj_time_val tv;
+    unsigned i;
+    const pj_sockaddr *addr0;
+    pjmedia_sdp_session *sdp;
+    pjmedia_type media_types[] = {PJMEDIA_TYPE_AUDIO, PJMEDIA_TYPE_VIDEO};
+
+    /* Sanity check arguments */
+    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);
+    PJ_ASSERT_RETURN(stream_cnt <= PJ_ARRAY_SIZE(media_types), PJ_ETOOMANY);
+
+    /* Create and initialize basic SDP session */
+    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
+
+    addr0 = &sock_info[0].rtp_addr_name;
+
+    pj_gettimeofday(&tv);
+    sdp->origin.user = pj_str("-");
+    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
+    sdp->origin.net_type = STR_IN;
+
+    if (addr0->addr.sa_family == pj_AF_INET()) {
+	sdp->origin.addr_type = STR_IP4;
+	pj_strdup2(pool, &sdp->origin.addr, 
+		   pj_inet_ntoa(addr0->ipv4.sin_addr));
+    } else if (addr0->addr.sa_family == pj_AF_INET6()) {
+	char tmp_addr[PJ_INET6_ADDRSTRLEN];
+
+	sdp->origin.addr_type = STR_IP6;
+	pj_strdup2(pool, &sdp->origin.addr, 
+		   pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0));
+
+    } else {
+	pj_assert(!"Invalid address family");
+	return PJ_EAFNOTSUP;
+    }
+
+    sdp->name = STR_SDP_NAME;
+
+    /* SDP connection line in the session level. */
+    sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
+    sdp->conn->net_type = sdp->origin.net_type;
+    sdp->conn->addr_type = sdp->origin.addr_type;
+    sdp->conn->addr = sdp->origin.addr;
+
+
+    /* SDP time and attributes. */
+    sdp->time.start = sdp->time.stop = 0;
+    sdp->attr_count = 0;
+
+    /* Add SDP media. */
+    for (i = 0; i < stream_cnt; ++i) {
+	pj_status_t status;
+
+	status = add_sdp_media(endpt, pool, media_types[i], 
+			       &sock_info[i], sdp);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
 
     /* Done */
Index: pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/sdp_cmp.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/sdp_cmp.c	(revision 3418)
+++ pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/sdp_cmp.c	(revision 3419)
@@ -296,2 +296,9 @@
 
 
+PJ_DEF(pj_status_t) pjmedia_sdp_conn_cmp(const pjmedia_sdp_conn *conn1, 
+					 const pjmedia_sdp_conn *conn2,
+					 unsigned option)
+{
+    PJ_UNUSED_ARG(option);
+    return compare_conn(conn1, conn2);
+}
Index: pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream_common.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream_common.c	(revision 3419)
+++ pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream_common.c	(revision 3419)
@@ -0,0 +1,97 @@
+/* $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 
+ */
+#include <pjmedia/stream_common.h>
+
+/*
+ * Parse fmtp for specified format/payload type.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_info_parse_fmtp( pj_pool_t *pool,
+						    const pjmedia_sdp_media *m,
+						    unsigned pt,
+						    pjmedia_codec_fmtp *fmtp)
+{
+    const pjmedia_sdp_attr *attr;
+    pjmedia_sdp_fmtp sdp_fmtp;
+    char *p, *p_end, fmt_buf[8];
+    pj_str_t fmt;
+    pj_status_t status;
+
+    pj_assert(m && fmtp);
+
+    pj_bzero(fmtp, sizeof(pjmedia_codec_fmtp));
+
+    /* Get "fmtp" attribute for the format */
+    pj_ansi_sprintf(fmt_buf, "%d", pt);
+    fmt = pj_str(fmt_buf);
+    attr = pjmedia_sdp_media_find_attr2(m, "fmtp", &fmt);
+    if (attr == NULL)
+	return PJ_SUCCESS;
+
+    /* Parse "fmtp" attribute */
+    status = pjmedia_sdp_attr_get_fmtp(attr, &sdp_fmtp);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Prepare parsing */
+    p = sdp_fmtp.fmt_param.ptr;
+    p_end = p + sdp_fmtp.fmt_param.slen;
+
+    /* Parse */
+    while (p < p_end) {
+	char *token, *start, *end;
+
+	/* Skip whitespaces */
+	while (p < p_end && (*p == ' ' || *p == '\t')) ++p;
+	if (p == p_end)
+	    break;
+
+	/* Get token */
+	start = p;
+	while (p < p_end && *p != ';' && *p != '=') ++p;
+	end = p - 1;
+
+	/* Right trim */
+	while (end >= start && (*end == ' '  || *end == '\t' || 
+				*end == '\r' || *end == '\n' ))
+	    --end;
+
+	/* Forward a char after trimming */
+	++end;
+
+	/* Store token */
+	if (end > start) {
+	    token = (char*)pj_pool_alloc(pool, end - start);
+	    pj_ansi_strncpy(token, start, end - start);
+	    if (*p == '=')
+		/* Got param name */
+		pj_strset(&fmtp->param[fmtp->cnt].name, token, end - start);
+	    else
+		/* Got param value */
+		pj_strset(&fmtp->param[fmtp->cnt++].val, token, end - start);
+	} else if (*p != '=') {
+	    ++fmtp->cnt;
+	}
+
+	/* Next */
+	++p;
+    }
+
+    return PJ_SUCCESS;
+}
+
