Re #1182:
 - Renamed vstreamutil.c to vid_steamutil.c just for filename format consistency reason.
 - Updated sample app simpleua.c and vid_streamutil.c to sync with updated API, e.g: strip session usage, two media ports exported video streams for each dir.
 - Added vid_streamutil.c capability to be able to stream video file (involving transcoding when video codec used in the file different to the video stream codec), also updated AVI player and ffmpeg codecs to be able to read and decode XVID/MPEG4 codec.
 - Fixed bug wrong media type check in stream.c and vid_stream.c in creating stream info from SDP.
 - Minor update: docs, logs, app samples makefiles.



git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3425 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c b/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c
index b1d15c2..e8e4569 100644
--- a/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c
+++ b/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c
@@ -205,6 +205,7 @@
 struct ffmpeg_codec_desc {
     /* Predefined info */
     pjmedia_vid_codec_info       info;
+    pjmedia_format_id		 base_fmt_id;
     func_packetize		 packetize;
     func_unpacketize		 unpacketize;
     func_parse_fmtp		 parse_fmtp;
@@ -245,15 +246,29 @@
 ffmpeg_codec_desc codec_desc[] =
 {
     {
-	{PJMEDIA_FORMAT_H263,	{"H263",4},	PJMEDIA_RTP_PT_H263},
+	{PJMEDIA_FORMAT_H263P,	{"H263-1998",9},    PJMEDIA_RTP_PT_H263},
+	PJMEDIA_FORMAT_H263,
 	&h263_packetize, &h263_unpacketize, &h263_parse_fmtp,
 	{2, { {{"CIF",3}, {"2",1}}, {{"QCIF",4}, {"1",1}}, } },
     },
     {
-	{PJMEDIA_FORMAT_H261,	{"H261",4},	PJMEDIA_RTP_PT_H261},
+	{PJMEDIA_FORMAT_H263,	{"H263",4},	    PJMEDIA_RTP_PT_H263},
+	0,
+	&h263_packetize, &h263_unpacketize, &h263_parse_fmtp,
+	{2, { {{"CIF",3}, {"2",1}}, {{"QCIF",4}, {"1",1}}, } },
     },
     {
-	{PJMEDIA_FORMAT_MJPEG,	{"JPEG",4},	PJMEDIA_RTP_PT_JPEG},
+	{PJMEDIA_FORMAT_H261,	{"H261",4},	    PJMEDIA_RTP_PT_H261},
+    },
+    {
+	{PJMEDIA_FORMAT_MJPEG,	{"JPEG",4},	    PJMEDIA_RTP_PT_JPEG},
+    },
+    {
+	{PJMEDIA_FORMAT_MPEG4,	{"MP4V",4},	    PJMEDIA_RTP_PT_MPV},
+    },
+    {
+	{PJMEDIA_FORMAT_XVID,	{"XVID",4},	    PJMEDIA_RTP_PT_MPV},
+	PJMEDIA_FORMAT_MPEG4,
     },
 };
 
@@ -447,7 +462,7 @@
 
 
 
-static const ffmpeg_codec_desc* find_codec_info(
+static const ffmpeg_codec_desc* find_codec_desc_by_info(
 			const pjmedia_vid_codec_info *info)
 {
     int i;
@@ -468,7 +483,7 @@
 }
 
 
-static int find_codec_info_idx_by_fmt_id(pjmedia_format_id fmt_id)
+static int find_codec_idx_by_fmt_id(pjmedia_format_id fmt_id)
 {
     int i;
     for (i=0; i<PJ_ARRAY_SIZE(codec_desc); ++i) {
@@ -489,6 +504,7 @@
     pj_pool_t *pool;
     AVCodec *c;
     pj_status_t status;
+    unsigned i;
 
     if (ffmpeg_factory.pool != NULL) {
 	/* Already initialized. */
@@ -532,12 +548,13 @@
 	 * supported fps) are in the encoder.
          */
 
+	//PJ_LOG(3, (THIS_FILE, "%s", c->name));
 	status = CodecID_to_pjmedia_format_id(c->id, &fmt_id);
 	/* Skip if format ID is unknown */
 	if (status != PJ_SUCCESS)
 	    continue;
 
-	codec_info_idx = find_codec_info_idx_by_fmt_id(fmt_id);
+	codec_info_idx = find_codec_idx_by_fmt_id(fmt_id);
 	/* Skip if codec is unwanted by this wrapper (not listed in 
 	 * the codec info array)
 	 */
@@ -634,6 +651,59 @@
 	    desc->info.clock_rate = 90000;
     }
 
+    /* Init unassigned encoder/decoder description from base codec */
+    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
+	ffmpeg_codec_desc *desc = &codec_desc[i];
+
+	if (desc->base_fmt_id && (!desc->dec || !desc->enc)) {
+	    ffmpeg_codec_desc *base_desc = NULL;
+	    int base_desc_idx;
+	    pjmedia_dir copied_dir = PJMEDIA_DIR_NONE;
+
+	    base_desc_idx = find_codec_idx_by_fmt_id(desc->base_fmt_id);
+	    if (base_desc_idx != -1)
+		base_desc = &codec_desc[base_desc_idx];
+	    if (!base_desc || !base_desc->enabled)
+		continue;
+
+	    /* Copy description from base codec */
+	    if (!desc->info.dec_fmt_id_cnt) {
+		desc->info.dec_fmt_id_cnt = base_desc->info.dec_fmt_id_cnt;
+		pj_memcpy(desc->info.dec_fmt_id, base_desc->info.dec_fmt_id, 
+			  sizeof(pjmedia_format_id)*desc->info.dec_fmt_id_cnt);
+	    }
+	    if (!desc->info.fps_cnt) {
+		desc->info.fps_cnt = base_desc->info.fps_cnt;
+		pj_memcpy(desc->info.fps, base_desc->info.fps, 
+			  sizeof(desc->info.fps[0])*desc->info.fps_cnt);
+	    }
+	    if (!desc->info.clock_rate) {
+		desc->info.clock_rate = base_desc->info.clock_rate;
+	    }
+	    if (!desc->dec && base_desc->dec) {
+		copied_dir |= PJMEDIA_DIR_DECODING;
+		desc->dec = base_desc->dec;
+	    }
+	    if (!desc->enc && base_desc->enc) {
+		copied_dir |= PJMEDIA_DIR_ENCODING;
+		desc->enc = base_desc->enc;
+	    }
+
+	    desc->info.dir |= copied_dir;
+	    desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE);
+
+	    if (copied_dir != PJMEDIA_DIR_NONE) {
+		const char *dir_name[] = {NULL, "encoder", "decoder", "codec"};
+		PJ_LOG(5, (THIS_FILE, "The %.*s %s is using base codec (%.*s)",
+			   desc->info.encoding_name.slen,
+			   desc->info.encoding_name.ptr,
+			   dir_name[copied_dir],
+			   base_desc->info.encoding_name.slen,
+			   base_desc->info.encoding_name.ptr));
+	    }
+        }
+    }
+
     /* Register codec factory to codec manager. */
     status = pjmedia_vid_codec_mgr_register_factory(mgr, 
 						    &ffmpeg_factory.base);
@@ -690,7 +760,7 @@
     PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL);
     PJ_ASSERT_RETURN(info, PJ_EINVAL);
 
-    desc = find_codec_info(info);
+    desc = find_codec_desc_by_info(info);
     if (!desc) {
         return PJMEDIA_CODEC_EUNSUP;
     }
@@ -710,7 +780,7 @@
     PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL);
     PJ_ASSERT_RETURN(info && attr, PJ_EINVAL);
 
-    desc = find_codec_info(info);
+    desc = find_codec_desc_by_info(info);
     if (!desc) {
         return PJMEDIA_CODEC_EUNSUP;
     }
@@ -741,16 +811,20 @@
 				       unsigned *count, 
 				       pjmedia_vid_codec_info codecs[])
 {
-    unsigned i;
+    unsigned i, max_cnt;
 
     PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
     PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
 
-    *count = PJ_MIN(*count, PJ_ARRAY_SIZE(codec_desc));
+    max_cnt = PJ_MIN(*count, PJ_ARRAY_SIZE(codec_desc));
+    *count = 0;
 
-    for (i=0; i<*count; ++i) {
-        pj_memcpy(&codecs[i], &codec_desc[i].info, 
-		  sizeof(pjmedia_vid_codec_info));
+    for (i=0; i<max_cnt; ++i) {
+	if (codec_desc[i].enabled) {
+	    pj_memcpy(&codecs[*count], &codec_desc[i].info, 
+		      sizeof(pjmedia_vid_codec_info));
+	    (*count)++;
+	}
     }
 
     return PJ_SUCCESS;
@@ -772,7 +846,7 @@
     PJ_ASSERT_RETURN(factory && info && p_codec, PJ_EINVAL);
     PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
 
-    desc = find_codec_info(info);
+    desc = find_codec_desc_by_info(info);
     if (!desc) {
         return PJMEDIA_CODEC_EUNSUP;
     }
@@ -927,9 +1001,10 @@
             codec = ff->dec;
 
             /* Decoding only attributes */
-	    // this setting will be automatically fetched from the bitstream.
-            //ctx->coded_width = ff->param.dec_fmt.det.vid.size.w;
-            //ctx->coded_height = ff->param.dec_fmt.det.vid.size.h;
+
+	    /* Width/height may be overriden by ffmpeg after first decoding. */
+            ctx->width = ctx->coded_width = ff->param.dec_fmt.det.vid.size.w;
+            ctx->height = ctx->coded_height = ff->param.dec_fmt.det.vid.size.h;
 
             /* For decoder, be more flexible */
             if (ff->param.dir!=PJMEDIA_DIR_ENCODING_DECODING || 
@@ -1198,7 +1273,7 @@
     PJ_ASSERT_RETURN(ff->dec_ctx, PJ_EINVALIDOP);
 
     /* Validate output buffer size */
-    PJ_ASSERT_RETURN(ff->dec_vafp.framebytes <= output_buf_len, PJ_ETOOSMALL);
+    //PJ_ASSERT_RETURN(ff->dec_vafp.framebytes <= output_buf_len, PJ_ETOOSMALL);
 
     /* Init frame to receive the decoded data, the ffmpeg codec context will
      * automatically provide the decoded buffer (single buffer used for the
@@ -1310,8 +1385,8 @@
 	}
 
 	/* Check provided buffer size after format changed */
-	if (vafp->framebytes > output_buf_len)
-	    return PJ_ETOOSMALL;
+	//if (vafp->framebytes > output_buf_len)
+	    //return PJ_ETOOSMALL;
 
 	/* Get the decoded data */
 	for (i = 0; i < ff->dec_vfi->plane_cnt; ++i) {
diff --git a/pjmedia/src/pjmedia/avi_player.c b/pjmedia/src/pjmedia/avi_player.c
index b41d742..d7ed12f 100644
--- a/pjmedia/src/pjmedia/avi_player.c
+++ b/pjmedia/src/pjmedia/avi_player.c
@@ -339,6 +339,7 @@
             /* Check supported video formats here */
             if (avi_hdr.strl_hdr[i].flags & AVISF_VIDEO_PALCHANGES ||
                 (avi_hdr.strl_hdr[i].codec != PJMEDIA_FORMAT_MJPEG &&
+                 avi_hdr.strl_hdr[i].codec != PJMEDIA_FORMAT_XVID &&
                  avi_hdr.strl_hdr[i].codec != PJMEDIA_FORMAT_UYVY &&
                  avi_hdr.strl_hdr[i].codec != PJMEDIA_FORMAT_YUY2 &&
                  avi_hdr.strl_hdr[i].codec != PJMEDIA_FORMAT_IYUV &&
diff --git a/pjmedia/src/pjmedia/ffmpeg_util.c b/pjmedia/src/pjmedia/ffmpeg_util.c
index a2def0e..e3878ac 100644
--- a/pjmedia/src/pjmedia/ffmpeg_util.c
+++ b/pjmedia/src/pjmedia/ffmpeg_util.c
@@ -51,12 +51,16 @@
     enum CodecID	codec_id;
 } ffmpeg_codec_table[] =
 {
-    {PJMEDIA_FORMAT_H261,  CODEC_ID_H261},
-    {PJMEDIA_FORMAT_H263,  CODEC_ID_H263},
-    {PJMEDIA_FORMAT_MPEG1VIDEO,  CODEC_ID_MPEG1VIDEO},
-    {PJMEDIA_FORMAT_MPEG2VIDEO,  CODEC_ID_MPEG2VIDEO},
-    {PJMEDIA_FORMAT_MPEG4,  CODEC_ID_MPEG4},    
-    {PJMEDIA_FORMAT_MJPEG,  CODEC_ID_MJPEG},
+    {PJMEDIA_FORMAT_H261,	CODEC_ID_H261},
+    {PJMEDIA_FORMAT_H263,	CODEC_ID_H263},
+    {PJMEDIA_FORMAT_H263P,	CODEC_ID_H263P},
+    {PJMEDIA_FORMAT_MPEG1VIDEO,	CODEC_ID_MPEG1VIDEO},
+    {PJMEDIA_FORMAT_MPEG2VIDEO, CODEC_ID_MPEG2VIDEO},
+    {PJMEDIA_FORMAT_MPEG4,	CODEC_ID_MPEG4},
+    {PJMEDIA_FORMAT_MJPEG,	CODEC_ID_MJPEG},
+#if LIBAVCODEC_VERSION_MAJOR < 53
+    {PJMEDIA_FORMAT_XVID,	CODEC_ID_XVID},
+#endif
 };
 
 static int pjmedia_ffmpeg_ref_cnt;
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index f8468a2..a5c3f71 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -3034,7 +3034,7 @@
 	return PJMEDIA_SDP_EMISSINGCONN;
 
     /* Media type must be audio */
-    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0)
+    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) != 0)
 	return PJMEDIA_EINVALIMEDIATYPE;
 
     /* Get codec manager. */
diff --git a/pjmedia/src/pjmedia/vid_codec.c b/pjmedia/src/pjmedia/vid_codec.c
index 567418b..8dd009c 100644
--- a/pjmedia/src/pjmedia/vid_codec.c
+++ b/pjmedia/src/pjmedia/vid_codec.c
@@ -68,6 +68,38 @@
 
 
 /*
+ * Duplicate video codec parameter.
+ */
+PJ_DEF(pjmedia_vid_codec_param*) pjmedia_vid_codec_param_clone(
+					pj_pool_t *pool, 
+					const pjmedia_vid_codec_param *src)
+{
+    pjmedia_vid_codec_param *p;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(pool && src, NULL);
+
+    p = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec_param);
+
+    /* Update codec param */
+    pj_memcpy(p, src, sizeof(pjmedia_vid_codec_param));
+    for (i = 0; i < src->dec_fmtp.cnt; ++i) {
+	pj_strdup(pool, &p->dec_fmtp.param[i].name, 
+		  &src->dec_fmtp.param[i].name);
+	pj_strdup(pool, &p->dec_fmtp.param[i].val, 
+		  &src->dec_fmtp.param[i].val);
+    }
+    for (i = 0; i < src->enc_fmtp.cnt; ++i) {
+	pj_strdup(pool, &p->enc_fmtp.param[i].name, 
+		  &src->enc_fmtp.param[i].name);
+	pj_strdup(pool, &p->enc_fmtp.param[i].val, 
+		  &src->enc_fmtp.param[i].val);
+    }
+
+    return p;
+}
+
+/*
  * Initialize codec manager.
  */
 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_create(
@@ -305,6 +337,35 @@
 }
 
 
+PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_codec_info2(
+				    pjmedia_vid_codec_mgr *mgr,
+				    pjmedia_format_id fmt_id,
+				    const pjmedia_vid_codec_info **p_info)
+{
+    unsigned i;
+
+    PJ_ASSERT_RETURN(p_info, PJ_EINVAL);
+
+    if (!mgr) mgr = def_vid_codec_mgr;
+    PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
+
+    pj_mutex_lock(mgr->mutex);
+
+    for (i=0; i<mgr->codec_cnt; ++i) {
+	if (mgr->codec_desc[i].info.fmt_id == fmt_id) {
+	    *p_info = &mgr->codec_desc[i].info;
+
+	    pj_mutex_unlock(mgr->mutex);
+	    return PJ_SUCCESS;
+	}
+    }
+
+    pj_mutex_unlock(mgr->mutex);
+
+    return PJMEDIA_CODEC_EUNSUP;
+}
+
+
 /*
  * Convert codec info struct into a unique codec identifier.
  * A codec identifier looks something like "L16/44100/2".
@@ -632,23 +693,11 @@
 	return PJ_SUCCESS;
     }
 
-    p = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec_param);
-    p = codec_desc->def_param;
-
-    /* Update codec param */
-    pj_memcpy(p, param, sizeof(pjmedia_vid_codec_param));
-    for (i = 0; i < param->dec_fmtp.cnt; ++i) {
-	pj_strdup(pool, &p->dec_fmtp.param[i].name, 
-		  &param->dec_fmtp.param[i].name);
-	pj_strdup(pool, &p->dec_fmtp.param[i].val, 
-		  &param->dec_fmtp.param[i].val);
-    }
-    for (i = 0; i < param->enc_fmtp.cnt; ++i) {
-	pj_strdup(pool, &p->enc_fmtp.param[i].name, 
-		  &param->enc_fmtp.param[i].name);
-	pj_strdup(pool, &p->enc_fmtp.param[i].val, 
-		  &param->enc_fmtp.param[i].val);
-    }
+    /* Update codec default param */
+    p = pjmedia_vid_codec_param_clone(pool, param);
+    if (!p)
+	return PJ_EINVAL;
+    codec_desc->def_param = p;
 
     pj_mutex_unlock(mgr->mutex);
 
diff --git a/pjmedia/src/pjmedia/vid_stream.c b/pjmedia/src/pjmedia/vid_stream.c
index adbc980..f6c49d0 100644
--- a/pjmedia/src/pjmedia/vid_stream.c
+++ b/pjmedia/src/pjmedia/vid_stream.c
@@ -84,6 +84,7 @@
 {
     pjmedia_endpt	    *endpt;	    /**< Media endpoint.	    */
     pjmedia_vid_codec_mgr   *codec_mgr;	    /**< Codec manager.		    */
+    pjmedia_vid_stream_info  info;	    /**< Stream info.		    */
 
     pjmedia_vid_channel	    *enc;	    /**< Encoding channel.	    */
     pjmedia_vid_channel	    *dec;	    /**< Decoding channel.	    */
@@ -128,15 +129,11 @@
 #endif
 
 #if TRACE_JB
-    pj_oshandle_t	    trace_jb_fd;	    /**< Jitter tracing file handle.*/
-    char		   *trace_jb_buf;	    /**< Jitter tracing buffer.	    */
+    pj_oshandle_t	     trace_jb_fd;   /**< Jitter tracing file handle.*/
+    char		    *trace_jb_buf;  /**< Jitter tracing buffer.	    */
 #endif
 
-    pjmedia_vid_codec	    *codec;	            /**< Codec instance being used. */
-    pjmedia_vid_codec_info   codec_info;           /**< Codec param.		    */
-    pjmedia_vid_codec_param  codec_param;          /**< Codec param.		    */
-
-    pjmedia_vid_stream_info     info;
+    pjmedia_vid_codec	    *codec;	    /**< Codec instance being used. */
 };
 
 
@@ -626,11 +623,7 @@
     if (seq_st.status.flag.restart) {
 	status = pjmedia_jbuf_reset(stream->jb);
 	PJ_LOG(4,(channel->port.info.name.ptr, "Jitter buffer reset"));
-
     } else {
-
-	/* Video stream */
-
 	/* Just put the payload into jitter buffer */
 	pjmedia_jbuf_put_frame3(stream->jb, payload, payloadlen, 0, 
 				pj_ntohs(hdr->seq), pj_ntohl(hdr->ts), NULL);
@@ -927,10 +920,11 @@
     /* Check if the decoder format is changed */
     if (frame->bit_info & PJMEDIA_VID_CODEC_EVENT_FMT_CHANGED) {
 	/* Update param from codec */
-	stream->codec->op->get_param(stream->codec, &stream->codec_param);
+	stream->codec->op->get_param(stream->codec, stream->info.codec_param);
 
 	/* Update decoding channel port info */
-	stream->dec->port.info.fmt = stream->codec_param.dec_fmt;
+	pjmedia_format_copy(&stream->dec->port.info.fmt,
+			    &stream->info.codec_param->dec_fmt);
     }
     
     return PJ_SUCCESS;
@@ -964,10 +958,10 @@
 
     /* Init vars */
     if (dir==PJMEDIA_DIR_DECODING) {
-	type_name = "vstrmdec";
+	type_name = "vstdec";
 	fmt = &info->codec_param->dec_fmt;
     } else {
-	type_name = "vstrmenc";
+	type_name = "vstenc";
 	fmt = &info->codec_param->enc_fmt;
     }
 
@@ -1053,6 +1047,9 @@
     stream = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_stream);
     PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
 
+    /* Copy stream info */
+    pj_memcpy(&stream->info, info, sizeof(*info));
+
     /* Get codec manager */
     stream->codec_mgr = pjmedia_vid_codec_mgr_instance();
     PJ_ASSERT_RETURN(stream->codec_mgr, PJMEDIA_CODEC_EFAILED);
@@ -1063,7 +1060,6 @@
 					 "vstrm%p", stream);
 
     /* Create and initialize codec: */
-    stream->codec_info = info->codec_info;
     status = pjmedia_vid_codec_mgr_alloc_codec(stream->codec_mgr, 
 					       &info->codec_info,
 					       &stream->codec);
@@ -1072,18 +1068,27 @@
 
 
     /* Get codec param: */
-    if (info->codec_param)
-	stream->codec_param = *info->codec_param;
-    else {
+    if (info->codec_param) {
+	stream->info.codec_param = pjmedia_vid_codec_param_clone(
+							pool,
+							info->codec_param);
+    } else {
+	pjmedia_vid_codec_param def_param;
+
 	status = pjmedia_vid_codec_mgr_get_default_param(stream->codec_mgr, 
 						         &info->codec_info,
-						         &stream->codec_param);
+						         &def_param);
 	if (status != PJ_SUCCESS)
 	    return status;
+	stream->info.codec_param = pjmedia_vid_codec_param_clone(
+							pool,
+							&def_param);
+	pj_assert(stream->info.codec_param);
     }
 
     vfd_enc = pjmedia_format_get_video_format_detail(
-                                            &stream->codec_param.enc_fmt, 1);
+					&stream->info.codec_param->enc_fmt,
+					PJ_TRUE);
 
     /* Init stream: */
     stream->endpt = endpt;
@@ -1116,14 +1121,15 @@
 	return status;
 
     /* Init codec param */
-    stream->codec_param.dir = info->dir;
-    stream->codec_param.enc_mtu = PJMEDIA_MAX_MTU - sizeof(pjmedia_rtp_hdr);
+    stream->info.codec_param->dir = info->dir;
+    stream->info.codec_param->enc_mtu = PJMEDIA_MAX_MTU - 
+					sizeof(pjmedia_rtp_hdr);
 
     /* Init and open the codec. */
     status = stream->codec->op->init(stream->codec, pool);
     if (status != PJ_SUCCESS)
 	return status;
-    status = stream->codec->op->open(stream->codec, &stream->codec_param);
+    status = stream->codec->op->open(stream->codec, stream->info.codec_param);
     if (status != PJ_SUCCESS)
 	return status;
 
@@ -1139,9 +1145,9 @@
 
     /* Validate the frame size */
     if (stream->frame_size == 0 || 
-	stream->frame_size > PJMEDIA_MAX_VIDEO_FRAME_SIZE)
+	stream->frame_size > PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE)
     {
-	stream->frame_size = PJMEDIA_MAX_VIDEO_FRAME_SIZE;
+	stream->frame_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
     }
 
     /* Get frame length in timestamp unit */
@@ -1150,7 +1156,7 @@
 
     /* Create decoder channel */
     status = create_channel( pool, stream, PJMEDIA_DIR_DECODING, 
-			     info->codec_info.pt, info, &stream->dec);
+			     info->rx_pt, info, &stream->dec);
     if (status != PJ_SUCCESS)
 	return status;
 
@@ -1407,34 +1413,6 @@
 
 
 /*
- * Start stream.
- */
-PJ_DEF(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
-{
-
-    PJ_ASSERT_RETURN(stream && stream->enc && stream->dec, PJ_EINVALIDOP);
-
-    if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) {
-	stream->enc->paused = 0;
-	//pjmedia_snd_stream_start(stream->enc->snd_stream);
-	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream started"));
-    } else {
-	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
-    }
-
-    if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) {
-	stream->dec->paused = 0;
-	//pjmedia_snd_stream_start(stream->dec->snd_stream);
-	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream started"));
-    } else {
-	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/*
  * Get stream statistics.
  */
 PJ_DEF(pj_status_t) pjmedia_vid_stream_get_stat(
@@ -1491,6 +1469,48 @@
     return pjmedia_jbuf_get_state(stream->jb, state);
 }
 
+
+/*
+ * Get the stream info.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_get_info(
+					    const pjmedia_vid_stream *stream,
+					    pjmedia_vid_stream_info *info)
+{
+    PJ_ASSERT_RETURN(stream && info, PJ_EINVAL);
+    pj_memcpy(info, &stream->info, sizeof(*info));
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Start stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
+{
+
+    PJ_ASSERT_RETURN(stream && stream->enc && stream->dec, PJ_EINVALIDOP);
+
+    if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) {
+	stream->enc->paused = 0;
+	//pjmedia_snd_stream_start(stream->enc->snd_stream);
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream started"));
+    } else {
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
+    }
+
+    if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) {
+	stream->dec->paused = 0;
+	//pjmedia_snd_stream_start(stream->dec->snd_stream);
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream started"));
+    } else {
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
+    }
+
+    return PJ_SUCCESS;
+}
+
+
 /*
  * Pause stream.
  */
@@ -1578,6 +1598,7 @@
      * For dynamic payload types, MUST get the rtpmap.
      */
     pt = pj_strtoul(&local_m->desc.fmt[0]);
+    si->rx_pt = pt;
     if (pt < 96) {
 	const pjmedia_vid_codec_info *p_info;
 
@@ -1659,7 +1680,7 @@
 				   &si->codec_param->enc_fmtp);
 
     /* Get local fmtp for our decoder. */
-    pjmedia_stream_info_parse_fmtp(pool, local_m, pt,
+    pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
 				   &si->codec_param->dec_fmtp);
 
     /* When direction is NONE (it means SDP negotiation has failed) we don't
@@ -1717,7 +1738,7 @@
 	return PJMEDIA_SDP_EMISSINGCONN;
 
     /* Media type must be audio */
-    if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) == 0)
+    if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) != 0)
 	return PJMEDIA_EINVALIMEDIATYPE;
 
 
diff --git a/pjmedia/src/test/vid_codec_test.c b/pjmedia/src/test/vid_codec_test.c
index d32e176..dfff891 100644
--- a/pjmedia/src/test/vid_codec_test.c
+++ b/pjmedia/src/test/vid_codec_test.c
@@ -20,18 +20,21 @@
 			           pjmedia_frame *frame)
 {
     codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
-    pjmedia_vid_codec *codec = port_data->codec;
-    pjmedia_frame enc_frame;
     pj_status_t status;
 
-    enc_frame.buf = port_data->enc_buf;
-    enc_frame.size = port_data->enc_buf_size;
-
 #if !BYPASS_CODEC
-    status = codec->op->encode(codec, frame, enc_frame.size, &enc_frame);
-    if (status != PJ_SUCCESS) goto on_error;
-    status = codec->op->decode(codec, &enc_frame, frame->size, frame);
-    if (status != PJ_SUCCESS) goto on_error;
+    {
+	pjmedia_vid_codec *codec = port_data->codec;
+	pjmedia_frame enc_frame;
+
+	enc_frame.buf = port_data->enc_buf;
+	enc_frame.size = port_data->enc_buf_size;
+
+	status = codec->op->encode(codec, frame, enc_frame.size, &enc_frame);
+	if (status != PJ_SUCCESS) goto on_error;
+	status = codec->op->decode(codec, &enc_frame, frame->size, frame);
+	if (status != PJ_SUCCESS) goto on_error;
+    }
 #endif
 
     status = pjmedia_port_put_frame(port_data->dn_port, frame);
@@ -87,6 +90,7 @@
 static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
                               pjmedia_format_id raw_fmt_id)
 {
+    const pj_str_t port_name = {"codec", 5};
 
     pjmedia_vid_codec *codec=NULL;
     pjmedia_port codec_port;
@@ -162,6 +166,50 @@
         }
     }
 
+    /* Prepare codec */
+    {
+        pj_str_t codec_id_st;
+        unsigned info_cnt = 1;
+        const pjmedia_vid_codec_info *codec_info;
+
+        /* Lookup codec */
+        pj_cstr(&codec_id_st, codec_id);
+        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, 
+                                                         &info_cnt, 
+                                                         &codec_info, NULL);
+        if (status != PJ_SUCCESS) {
+            rc = 245; goto on_return;
+        }
+        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
+                                                         &codec_param);
+        if (status != PJ_SUCCESS) {
+            rc = 246; goto on_return;
+        }
+
+#if !BYPASS_CODEC
+
+        /* Open codec */
+        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
+                                                   &codec);
+        if (status != PJ_SUCCESS) {
+	    rc = 250; goto on_return;
+        }
+
+        status = codec->op->init(codec, pool);
+        if (status != PJ_SUCCESS) {
+	    rc = 251; goto on_return;
+        }
+
+	codec_param.dec_fmt.id = raw_fmt_id;
+        status = codec->op->open(codec, &codec_param);
+        if (status != PJ_SUCCESS) {
+	    rc = 252; goto on_return;
+        }
+
+#endif /* !BYPASS_CODEC */
+    }
+
+
     pjmedia_vid_port_param_default(&vport_param);
 
     /* Create capture, set it to active (master) */
@@ -170,6 +218,7 @@
     if (status != PJ_SUCCESS) {
 	rc = 220; goto on_return;
     }
+    pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt);
     vport_param.vidparam.fmt.id = raw_fmt_id;
     vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
     vport_param.active = PJ_TRUE;
@@ -200,76 +249,24 @@
 	rc = 230; goto on_return;
     }
 
-    /* Prepare codec */
-    {
-        pj_str_t codec_id_st;
-        unsigned info_cnt = 1;
-        const pjmedia_vid_codec_info *codec_info;
-        pj_str_t port_name = {"codec", 5};
-        pj_uint8_t *enc_buf = NULL;
-        pj_size_t enc_buf_size = 0;
-
-
-        /* Lookup codec */
-        pj_cstr(&codec_id_st, codec_id);
-        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st, 
-                                                         &info_cnt, 
-                                                         &codec_info, NULL);
-        if (status != PJ_SUCCESS) {
-            rc = 245; goto on_return;
-        }
-        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
-                                                         &codec_param);
-        if (status != PJ_SUCCESS) {
-            rc = 246; goto on_return;
-        }
-
-        pjmedia_format_copy(&codec_param.dec_fmt, &vport_param.vidparam.fmt);
-
-#if !BYPASS_CODEC
-
-        /* Open codec */
-        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
-                                                   &codec);
-        if (status != PJ_SUCCESS) {
-	    rc = 250; goto on_return;
-        }
-
-        status = codec->op->init(codec, pool);
-        if (status != PJ_SUCCESS) {
-	    rc = 251; goto on_return;
-        }
-
-        status = codec->op->open(codec, &codec_param);
-        if (status != PJ_SUCCESS) {
-	    rc = 252; goto on_return;
-        }
-
-        /* Alloc encoding buffer */
-        enc_buf_size =  codec_param.dec_fmt.det.vid.size.w *
-                        codec_param.dec_fmt.det.vid.size.h * 4
-                        + 16; /*< padding, just in case */
-        enc_buf = pj_pool_alloc(pool,enc_buf_size);
-
-#endif /* !BYPASS_CODEC */
-
-        /* Init codec port */
-        pj_bzero(&codec_port, sizeof(codec_port));
-        status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
-                                         PJMEDIA_DIR_ENCODING, 
-                                         &codec_param.dec_fmt);
-        if (status != PJ_SUCCESS) {
-	    rc = 260; goto on_return;
-        }
-        codec_port_data.codec = codec;
-        codec_port_data.dn_port = pjmedia_vid_port_get_passive_port(renderer);
-        codec_port_data.enc_buf = enc_buf;
-        codec_port_data.enc_buf_size = enc_buf_size;
-
-        codec_port.put_frame = &codec_put_frame;
-        codec_port.port_data.pdata = &codec_port_data;
+    /* Init codec port */
+    pj_bzero(&codec_port, sizeof(codec_port));
+    status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
+                                     PJMEDIA_DIR_ENCODING, 
+                                     &codec_param.dec_fmt);
+    if (status != PJ_SUCCESS) {
+	rc = 260; goto on_return;
     }
 
+    codec_port_data.codec = codec;
+    codec_port_data.dn_port = pjmedia_vid_port_get_passive_port(renderer);
+    codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
+				   codec_param.dec_fmt.det.vid.size.h * 4;
+    codec_port_data.enc_buf = pj_pool_alloc(pool, 
+					    codec_port_data.enc_buf_size);
+
+    codec_port.put_frame = &codec_put_frame;
+    codec_port.port_data.pdata = &codec_port_data;
 
     /* Connect capture to codec port */
     status = pjmedia_vid_port_connect(capture,
@@ -279,15 +276,27 @@
 	rc = 270; goto on_return;
     }
 
-    PJ_LOG(3, (THIS_FILE, "  starting codec test:  %c%c%c%c<->%s %dx%d",
+#if BYPASS_CODEC
+    PJ_LOG(3, (THIS_FILE, "  starting loopback test: %c%c%c%c %dx%d",
+        ((raw_fmt_id & 0x000000FF) >> 0),
+        ((raw_fmt_id & 0x0000FF00) >> 8),
+        ((raw_fmt_id & 0x00FF0000) >> 16),
+        ((raw_fmt_id & 0xFF000000) >> 24),
+        codec_param.dec_fmt.det.vid.size.w,
+        codec_param.dec_fmt.det.vid.size.h
+        ));
+#else
+    PJ_LOG(3, (THIS_FILE, "  starting codec test: %c%c%c%c<->%.*s %dx%d",
         ((codec_param.dec_fmt.id & 0x000000FF) >> 0),
         ((codec_param.dec_fmt.id & 0x0000FF00) >> 8),
         ((codec_param.dec_fmt.id & 0x00FF0000) >> 16),
         ((codec_param.dec_fmt.id & 0xFF000000) >> 24),
-        codec_id, 
+	codec_info->encoding_name.slen,
+	codec_info->encoding_name.ptr,
         codec_param.dec_fmt.det.vid.size.w,
         codec_param.dec_fmt.det.vid.size.h
         ));
+#endif
 
     /* Start streaming.. */
     status = pjmedia_vid_port_start(renderer);
@@ -327,6 +336,10 @@
     pj_pool_t *pool;
     int rc = 0;
     pj_status_t status;
+    int orig_log_level;
+    
+    orig_log_level = pj_log_get_level();
+    pj_log_set_level(6);
 
     PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
 
@@ -344,7 +357,7 @@
     if (rc != 0)
 	goto on_return;
 
-    rc = encode_decode_test(pool, "mjpeg", 0);
+    rc = encode_decode_test(pool, "h263", 0);
     if (rc != 0)
 	goto on_return;
 
@@ -352,6 +365,7 @@
     pjmedia_codec_ffmpeg_deinit();
     pjmedia_vid_subsys_shutdown();
     pj_pool_release(pool);
+    pj_log_set_level(orig_log_level);
 
     return rc;
 }
diff --git a/pjmedia/src/test/vid_dev_test.c b/pjmedia/src/test/vid_dev_test.c
index c52a4ab..e393275 100644
--- a/pjmedia/src/test/vid_dev_test.c
+++ b/pjmedia/src/test/vid_dev_test.c
@@ -57,7 +57,7 @@
     return PJ_SUCCESS;
 }
 
-static pj_status_t vid_event_cb(pjmedia_vid_stream *stream,
+static pj_status_t vid_event_cb(pjmedia_vid_dev_stream *stream,
 				void *user_data,
 				pjmedia_vid_event *event)
 {