Re #1478: Add support to play encoded AVI file (H264 or MPEG4).



git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@4034 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/src/pjmedia-videodev/avi_dev.c b/pjmedia/src/pjmedia-videodev/avi_dev.c
index 770f4f2..478254d 100644
--- a/pjmedia/src/pjmedia-videodev/avi_dev.c
+++ b/pjmedia/src/pjmedia-videodev/avi_dev.c
@@ -22,6 +22,7 @@
 #include <pj/log.h>
 #include <pj/os.h>
 #include <pj/rand.h>
+#include <pjmedia/vid_codec.h>
 
 #if defined(PJMEDIA_VIDEO_DEV_HAS_AVI) && PJMEDIA_VIDEO_DEV_HAS_AVI != 0
 
@@ -68,6 +69,9 @@
 
     pjmedia_vid_dev_cb		     vid_cb;	    /**< Stream callback.   */
     void			    *user_data;	    /**< Application data.  */
+    pjmedia_vid_codec               *codec;
+    pj_uint8_t                      *enc_buf;
+    pj_size_t                        enc_buf_size;
 };
 
 
@@ -432,7 +436,7 @@
 
     adi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
     adi->info.fmt_cnt = 1;
-    adi->info.fmt[0] = adi->vid->info.fmt;
+    pjmedia_format_copy(&adi->info.fmt[0], &adi->vid->info.fmt);
 
     /* Set out vars */
     if (p_id)
@@ -465,6 +469,9 @@
     pj_pool_t *pool = NULL;
     struct avi_dev_info *adi;
     struct avi_dev_strm *strm;
+    pjmedia_format avi_fmt;
+    const pjmedia_video_format_info *vfi;
+    pj_status_t status = PJ_SUCCESS;
 
     PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
     PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
@@ -490,8 +497,56 @@
     strm->user_data = user_data;
     strm->adi = adi;
 
-    /* Override format (hack?) */
-    pj_memcpy(&param->fmt, &adi->vid->info.fmt, sizeof(pjmedia_format));
+    pjmedia_format_copy(&avi_fmt, &adi->vid->info.fmt);
+    vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
+    /* Check whether the frame is encoded. */
+    if (!vfi || vfi->bpp == 0) {
+        /* Yes, prepare codec */
+        const pjmedia_vid_codec_info *codec_info;
+        pjmedia_vid_codec_param codec_param;
+	pjmedia_video_apply_fmt_param vafp;
+
+        /* Lookup codec */
+        status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
+                                                       avi_fmt.id,
+                                                       &codec_info);
+        if (status != PJ_SUCCESS || !codec_info)
+            goto on_error;
+
+        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
+                                                         &codec_param);
+        if (status != PJ_SUCCESS)
+            goto on_error;
+
+        /* Open codec */
+        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
+                                                   &strm->codec);
+        if (status != PJ_SUCCESS)
+            goto on_error;
+
+        status = pjmedia_vid_codec_init(strm->codec, strm->pool);
+        if (status != PJ_SUCCESS)
+            goto on_error;
+
+        codec_param.dir = PJMEDIA_DIR_DECODING;
+        codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
+        status = pjmedia_vid_codec_open(strm->codec, &codec_param);
+        if (status != PJ_SUCCESS)
+            goto on_error;
+
+	/* Allocate buffer */
+        avi_fmt.id = codec_info->dec_fmt_id[0];
+        vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
+	pj_bzero(&vafp, sizeof(vafp));
+	vafp.size = avi_fmt.det.vid.size;
+	status = vfi->apply_fmt(vfi, &vafp);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+
+	strm->enc_buf = pj_pool_alloc(strm->pool, vafp.framebytes);
+	strm->enc_buf_size = vafp.framebytes;
+    }
+    pjmedia_format_copy(&param->fmt, &avi_fmt);
 
     /* Done */
     strm->base.op = &stream_op;
@@ -499,6 +554,10 @@
     *p_vid_strm = &strm->base;
 
     return PJ_SUCCESS;
+
+on_error:
+    avi_dev_strm_destroy(&strm->base);
+    return status;
 }
 
 /* API: Get stream info. */
@@ -551,7 +610,22 @@
                                          pjmedia_frame *frame)
 {
     struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
-    return pjmedia_port_get_frame(stream->adi->vid, frame);
+    
+    if (stream->codec) {
+        pjmedia_frame enc_frame;
+        pj_status_t status;
+
+        enc_frame.buf = stream->enc_buf;
+        enc_frame.size = stream->enc_buf_size;
+        status = pjmedia_port_get_frame(stream->adi->vid, &enc_frame);
+        if (status != PJ_SUCCESS)
+            return status;
+
+        return pjmedia_vid_codec_decode(stream->codec, 1, &enc_frame,
+                                        frame->size, frame);
+    } else {
+        return pjmedia_port_get_frame(stream->adi->vid, frame);
+    }
 }
 
 /* API: Start stream. */
@@ -588,6 +662,11 @@
 
     avi_dev_strm_stop(strm);
 
+    if (stream->codec) {
+        pjmedia_vid_codec_close(stream->codec);
+        stream->codec = NULL;
+    }
+
     stream->adi->strm = NULL;
     stream->adi = NULL;
     pj_pool_release(stream->pool);