Migration of current video works from private repository to this repository. This closed #1176
git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3392 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/src/test/mips_test.c b/pjmedia/src/test/mips_test.c
index 392c634..d315606 100644
--- a/pjmedia/src/test/mips_test.c
+++ b/pjmedia/src/test/mips_test.c
@@ -684,7 +684,7 @@
static pj_status_t codec_put_frame(struct pjmedia_port *this_port,
- const pjmedia_frame *frame)
+ pjmedia_frame *frame)
{
struct codec_port *cp = (struct codec_port*)this_port;
pjmedia_frame out_frame;
@@ -1131,13 +1131,13 @@
pj_status_t status;
while (pjmedia_circ_buf_get_len(wp->circbuf) <
- wp->base.info.samples_per_frame * (CIRC_BUF_FRAME_CNT-1))
+ PJMEDIA_PIA_SPF(&wp->base.info) * (CIRC_BUF_FRAME_CNT-1))
{
status = pjmedia_port_get_frame(wp->gen_port, frame);
pj_assert(status==PJ_SUCCESS);
status = pjmedia_circ_buf_write(wp->circbuf, (short*)frame->buf,
- wp->base.info.samples_per_frame);
+ PJMEDIA_PIA_SPF(&wp->base.info));
pj_assert(status==PJ_SUCCESS);
}
@@ -1149,7 +1149,7 @@
pjmedia_circ_buf_get_read_regions(wp->circbuf, ®1, ®1_len,
®2, ®2_len);
- del_cnt = wp->base.info.samples_per_frame;
+ del_cnt = PJMEDIA_PIA_SPF(&wp->base.info);
status = pjmedia_wsola_discard(wp->wsola, reg1, reg1_len, reg2,
reg2_len, &del_cnt);
pj_assert(status==PJ_SUCCESS);
@@ -2010,7 +2010,7 @@
}
static pj_status_t delaybuf_put_frame(struct pjmedia_port *this_port,
- const pjmedia_frame *frame)
+ pjmedia_frame *frame)
{
struct delaybuf_port *dp = (struct delaybuf_port*)this_port;
pj_status_t status;
@@ -2219,7 +2219,7 @@
}
/* Port may decide to use different ptime (e.g. iLBC) */
- samples_per_frame = port->info.samples_per_frame;
+ samples_per_frame = PJMEDIA_PIA_SPF(&port->info);
gen_port = create_gen_port(pool, clock_rate, 1,
samples_per_frame, 100);
diff --git a/pjmedia/src/test/test.c b/pjmedia/src/test/test.c
index 385eee1..bd4e406 100644
--- a/pjmedia/src/test/test.c
+++ b/pjmedia/src/test/test.c
@@ -56,6 +56,14 @@
mem = &caching_pool.factory;
+#if HAS_VID_DEV_TEST
+ DO_TEST(vid_dev_test());
+#endif
+
+#if HAS_VID_CODEC_TEST
+ DO_TEST(vid_codec_test());
+#endif
+
#if HAS_SDP_NEG_TEST
DO_TEST(sdp_neg_test());
#endif
diff --git a/pjmedia/src/test/test.h b/pjmedia/src/test/test.h
index 96dc9d5..085f4c0 100644
--- a/pjmedia/src/test/test.h
+++ b/pjmedia/src/test/test.h
@@ -23,6 +23,8 @@
#include <pjmedia.h>
#include <pjlib.h>
+#define HAS_VID_DEV_TEST 1
+#define HAS_VID_CODEC_TEST 1
#define HAS_SDP_NEG_TEST 1
#define HAS_JBUF_TEST 1
#define HAS_MIPS_TEST 1
@@ -35,6 +37,8 @@
int sdp_neg_test(void);
int mips_test(void);
int codec_test_vectors(void);
+int vid_codec_test(void);
+int vid_dev_test(void);
extern pj_pool_factory *mem;
void app_perror(pj_status_t status, const char *title);
diff --git a/pjmedia/src/test/vid_codec_test.c b/pjmedia/src/test/vid_codec_test.c
new file mode 100644
index 0000000..d32e176
--- /dev/null
+++ b/pjmedia/src/test/vid_codec_test.c
@@ -0,0 +1,359 @@
+#include "test.h"
+#include <pjmedia-codec/ffmpeg_codecs.h>
+#include <pjmedia-videodev/videodev.h>
+#include <pjmedia/vid_codec.h>
+#include <pjmedia/port.h>
+
+#define THIS_FILE "vid_codec.c"
+
+#define BYPASS_CODEC 0
+
+typedef struct codec_port_data_t
+{
+ pjmedia_vid_codec *codec;
+ pjmedia_port *dn_port;
+ pj_uint8_t *enc_buf;
+ pj_size_t enc_buf_size;
+} codec_port_data_t;
+
+static pj_status_t codec_put_frame(pjmedia_port *port,
+ 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;
+#endif
+
+ status = pjmedia_port_put_frame(port_data->dn_port, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ return PJ_SUCCESS;
+
+on_error:
+ pj_perror(3, THIS_FILE, status, "codec_put_frame() error");
+ return status;
+}
+
+static const char* dump_codec_info(const pjmedia_vid_codec_info *info)
+{
+ static char str[80];
+ unsigned i;
+ char *p = str;
+
+ /* Raw format ids */
+ for (i=0; (i<info->dec_fmt_id_cnt) && (p-str+5<sizeof(str)); ++i) {
+ pj_memcpy(p, &info->dec_fmt_id[i], 4);
+ p += 4;
+ *p++ = ' ';
+ }
+ *p = '\0';
+
+ return str;
+}
+
+static int enum_codecs()
+{
+ unsigned i, cnt;
+ pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
+ pj_status_t status;
+
+ PJ_LOG(3, (THIS_FILE, " codec enums"));
+ cnt = PJ_ARRAY_SIZE(info);
+ status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, info, NULL);
+ if (status != PJ_SUCCESS)
+ return 100;
+
+ for (i = 0; i < cnt; ++i) {
+ PJ_LOG(3, (THIS_FILE, " %16.*s %c%c %s",
+ info[i].encoding_name.slen, info[i].encoding_name.ptr,
+ (info[i].dir & PJMEDIA_DIR_ENCODING? 'E' : ' '),
+ (info[i].dir & PJMEDIA_DIR_DECODING? 'D' : ' '),
+ dump_codec_info(&info[i])));
+ }
+
+ return PJ_SUCCESS;
+}
+
+static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
+ pjmedia_format_id raw_fmt_id)
+{
+
+ pjmedia_vid_codec *codec=NULL;
+ pjmedia_port codec_port;
+ codec_port_data_t codec_port_data;
+ pjmedia_vid_codec_param codec_param;
+ const pjmedia_vid_codec_info *codec_info;
+
+ pjmedia_vid_dev_index cap_idx, rdr_idx;
+ pjmedia_vid_port *capture=NULL, *renderer=NULL;
+ pjmedia_vid_port_param vport_param;
+ pjmedia_video_format_detail *vfd;
+ pj_status_t status;
+ int rc = 0;
+
+ PJ_LOG(3, (THIS_FILE, " encode decode test"));
+
+ /* Lookup codec */
+ {
+ pj_str_t codec_id_st;
+ unsigned info_cnt = 1;
+
+ /* 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 = 205; goto on_return;
+ }
+ }
+
+ /* Lookup colorbar source */
+ status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx);
+ if (status != PJ_SUCCESS) {
+ rc = 206; goto on_return;
+ }
+
+ /* Lookup SDL renderer */
+ status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx);
+ if (status != PJ_SUCCESS) {
+ rc = 207; goto on_return;
+ }
+
+ /* Raw format ID "not specified", lets find common format among the codec
+ * and the video devices
+ */
+ if (raw_fmt_id == 0) {
+ pjmedia_vid_dev_info cap_info, rdr_info;
+ unsigned i, j, k;
+
+ pjmedia_vid_dev_get_info(cap_idx, &cap_info);
+ pjmedia_vid_dev_get_info(rdr_idx, &rdr_info);
+
+ for (i=0; i<codec_info->dec_fmt_id_cnt && !raw_fmt_id; ++i) {
+ for (j=0; j<cap_info.fmt_cnt && !raw_fmt_id; ++j) {
+ if (codec_info->dec_fmt_id[i]==(int)cap_info.fmt[j].id) {
+ for (k=0; k<rdr_info.fmt_cnt && !raw_fmt_id; ++k) {
+ if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
+ {
+ raw_fmt_id = codec_info->dec_fmt_id[i];
+ }
+ }
+ }
+ }
+ }
+
+ if (raw_fmt_id == 0) {
+ PJ_LOG(3, (THIS_FILE, " No common format ID among the codec "
+ "and the video devices"));
+ status = PJ_ENOTFOUND;
+ rc = 210;
+ goto on_return;
+ }
+ }
+
+ pjmedia_vid_port_param_default(&vport_param);
+
+ /* Create capture, set it to active (master) */
+ status = pjmedia_vid_dev_default_param(pool, cap_idx,
+ &vport_param.vidparam);
+ if (status != PJ_SUCCESS) {
+ rc = 220; goto on_return;
+ }
+ vport_param.vidparam.fmt.id = raw_fmt_id;
+ vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
+ vport_param.active = PJ_TRUE;
+
+ if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
+ rc = 221; goto on_return;
+ }
+
+ vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
+ PJ_TRUE);
+ if (vfd == NULL) {
+ rc = 225; goto on_return;
+ }
+
+ status = pjmedia_vid_port_create(pool, &vport_param, &capture);
+ if (status != PJ_SUCCESS) {
+ rc = 226; goto on_return;
+ }
+
+ /* Create renderer, set it to passive (slave) */
+ vport_param.active = PJ_FALSE;
+ vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
+ vport_param.vidparam.rend_id = rdr_idx;
+ vport_param.vidparam.disp_size = vfd->size;
+
+ status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
+ if (status != PJ_SUCCESS) {
+ 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;
+ }
+
+
+ /* Connect capture to codec port */
+ status = pjmedia_vid_port_connect(capture,
+ &codec_port,
+ PJ_FALSE);
+ if (status != PJ_SUCCESS) {
+ rc = 270; goto on_return;
+ }
+
+ 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_param.dec_fmt.det.vid.size.w,
+ codec_param.dec_fmt.det.vid.size.h
+ ));
+
+ /* Start streaming.. */
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 275; goto on_return;
+ }
+ status = pjmedia_vid_port_start(capture);
+ if (status != PJ_SUCCESS) {
+ rc = 280; goto on_return;
+ }
+
+ /* Sleep while the video is being displayed... */
+ pj_thread_sleep(10000);
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(3, (THIS_FILE, status, " error"));
+ }
+ if (capture) {
+ pjmedia_vid_port_stop(capture);
+ pjmedia_vid_port_destroy(capture);
+ }
+ if (renderer) {
+ pjmedia_vid_port_stop(renderer);
+ pjmedia_vid_port_destroy(renderer);
+ }
+ if (codec) {
+ codec->op->close(codec);
+ pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
+ }
+
+ return rc;
+}
+
+int vid_codec_test(void)
+{
+ pj_pool_t *pool;
+ int rc = 0;
+ pj_status_t status;
+
+ PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
+
+ pool = pj_pool_create(mem, "Vid codec test", 256, 256, 0);
+
+ status = pjmedia_vid_subsys_init(mem);
+ if (status != PJ_SUCCESS)
+ return -10;
+
+ status = pjmedia_codec_ffmpeg_init(NULL, mem);
+ if (status != PJ_SUCCESS)
+ return -20;
+
+ rc = enum_codecs();
+ if (rc != 0)
+ goto on_return;
+
+ rc = encode_decode_test(pool, "mjpeg", 0);
+ if (rc != 0)
+ goto on_return;
+
+on_return:
+ pjmedia_codec_ffmpeg_deinit();
+ pjmedia_vid_subsys_shutdown();
+ pj_pool_release(pool);
+
+ return rc;
+}
+
+
diff --git a/pjmedia/src/test/vid_dev_test.c b/pjmedia/src/test/vid_dev_test.c
new file mode 100644
index 0000000..007ef3b
--- /dev/null
+++ b/pjmedia/src/test/vid_dev_test.c
@@ -0,0 +1,529 @@
+/* $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
+ */
+#include "test.h"
+#include <pjmedia-audiodev/audiodev.h>
+#include <pjmedia-codec/ffmpeg_codecs.h>
+#include <pjmedia/vid_codec.h>
+#include <pjmedia_videodev.h>
+
+#define THIS_FILE "vid_dev_test.c"
+
+pj_status_t pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr,
+ pj_pool_t *pool);
+
+typedef struct codec_port_data_t
+{
+ pjmedia_vid_codec *codec;
+ pjmedia_port *src_port;
+ pj_uint8_t *enc_buf;
+ pj_size_t enc_buf_size;
+
+ pjmedia_converter *conv;
+} codec_port_data_t;
+
+typedef struct avi_port_t
+{
+ pjmedia_vid_port *vid_port;
+ pjmedia_aud_stream *aud_stream;
+ pj_bool_t is_running;
+} avi_port_t;
+
+static int enum_devs(void)
+{
+ unsigned i, dev_cnt;
+ pj_status_t status;
+
+ PJ_LOG(3, (THIS_FILE, " device enums"));
+ dev_cnt = pjmedia_vid_dev_count();
+ for (i = 0; i < dev_cnt; ++i) {
+ pjmedia_vid_dev_info info;
+ status = pjmedia_vid_dev_get_info(i, &info);
+ if (status == PJ_SUCCESS) {
+ PJ_LOG(3, (THIS_FILE, "%3d: %s - %s", i, info.driver, info.name));
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t avi_play_cb(void *user_data, pjmedia_frame *frame)
+{
+ return pjmedia_port_get_frame((pjmedia_port*)user_data, frame);
+}
+
+static pj_status_t avi_event_cb(pjmedia_vid_stream *stream,
+ void *user_data,
+ pjmedia_vid_event *event)
+{
+ avi_port_t *ap = (avi_port_t *)user_data;
+
+ PJ_UNUSED_ARG(stream);
+
+ if (event->event_type != PJMEDIA_EVENT_MOUSEBUTTONDOWN)
+ return PJ_SUCCESS;
+
+ if (ap->is_running) {
+ pjmedia_vid_port_stop(ap->vid_port);
+ if (ap->aud_stream)
+ pjmedia_aud_stream_stop(ap->aud_stream);
+ } else {
+ pjmedia_vid_port_start(ap->vid_port);
+ if (ap->aud_stream)
+ pjmedia_aud_stream_start(ap->aud_stream);
+ }
+ ap->is_running = !ap->is_running;
+
+ /* We handled the event on our own, so return non-PJ_SUCCESS here */
+ return -1;
+}
+
+static pj_status_t codec_get_frame(pjmedia_port *port,
+ 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 (port_data->conv) {
+ pj_size_t frame_size = frame->size;
+
+ status = pjmedia_port_get_frame(port_data->src_port, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ status = codec->op->decode(codec, frame, frame->size, &enc_frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ frame->size = frame_size;
+ status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ return PJ_SUCCESS;
+ }
+
+ status = pjmedia_port_get_frame(port_data->src_port, &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;
+
+ return PJ_SUCCESS;
+
+on_error:
+ pj_perror(3, THIS_FILE, status, "codec_get_frame() error");
+ return status;
+}
+
+static int aviplay_test(pj_pool_t *pool)
+{
+ pjmedia_vid_port *renderer=NULL;
+ pjmedia_vid_port_param param;
+ pjmedia_aud_param aparam;
+ pjmedia_video_format_detail *vfd;
+ pjmedia_audio_format_detail *afd;
+ pjmedia_aud_stream *strm = NULL;
+ pj_status_t status;
+ int rc = 0;
+ pjmedia_avi_streams *avi_streams;
+ pjmedia_avi_stream *vid_stream, *aud_stream;
+ pjmedia_port *vid_port = NULL, *aud_port = NULL;
+ pjmedia_vid_codec *codec=NULL;
+ avi_port_t avi_port;
+#if PJ_WIN32
+ const char *fname = "C:\\Users\\Liong Sauw Ming\\Desktop\\piratesmjpg.avi";
+#else
+ const char *fname = "/home/bennylp/Desktop/installer/video/movies/pirates.avi";
+#endif
+
+ pj_bzero(&avi_port, sizeof(avi_port));
+
+ status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(2,("", status, " Error playing %s (ignored)", fname));
+ rc = 210; goto on_return;
+ }
+
+ vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
+ 0,
+ PJMEDIA_TYPE_VIDEO);
+ vid_port = pjmedia_avi_stream_get_port(vid_stream);
+
+ if (vid_port) {
+ pjmedia_vid_port_param_default(¶m);
+
+ status = pjmedia_vid_dev_default_param(pool,
+ PJMEDIA_VID_DEFAULT_RENDER_DEV,
+ ¶m.vidparam);
+ if (status != PJ_SUCCESS) {
+ rc = 220; goto on_return;
+ }
+
+ /* Create renderer, set it to active */
+ param.active = PJ_TRUE;
+ param.vidparam.dir = PJMEDIA_DIR_RENDER;
+ vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
+ PJ_TRUE);
+ pjmedia_format_init_video(¶m.vidparam.fmt,
+ vid_port->info.fmt.id,
+ vfd->size.w, vfd->size.h,
+ vfd->fps.num, vfd->fps.denum);
+
+ if (vid_port->info.fmt.id == PJMEDIA_FORMAT_MJPEG ||
+ vid_port->info.fmt.id == PJMEDIA_FORMAT_H263)
+ {
+ /* Prepare codec */
+ pj_str_t codec_id_st;
+ unsigned info_cnt = 1, i, k;
+ 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;
+ pjmedia_vid_dev_info rdr_info;
+ pjmedia_port codec_port;
+ codec_port_data_t codec_port_data;
+ pjmedia_vid_codec_param codec_param;
+ struct {
+ pj_uint32_t pjmedia_id;
+ const char *codec_id;
+ } codec_fmts[] =
+ {{PJMEDIA_FORMAT_MJPEG, "mjpeg"},
+ {PJMEDIA_FORMAT_H263, "h263"}};
+ const char *codec_id = NULL;
+
+
+ status = pjmedia_codec_ffmpeg_init(NULL, mem);
+ if (status != PJ_SUCCESS)
+ return -20;
+
+ /* Lookup codec */
+ for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
+ if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
+ codec_id = codec_fmts[i].codec_id;
+ break;
+ }
+ }
+ if (!codec_id) {
+ rc = 242; goto on_return;
+ }
+ 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_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
+ for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
+ for (k=0; k<rdr_info.fmt_cnt; ++k) {
+ if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
+ {
+ param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
+ }
+ }
+ }
+
+ /* 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;
+ }
+
+ pjmedia_format_copy(&codec_param.dec_fmt, ¶m.vidparam.fmt);
+
+ 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);
+
+ /* 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;
+ }
+ pj_bzero(&codec_port_data, sizeof(codec_port_data));
+ codec_port_data.codec = codec;
+ codec_port_data.src_port = vid_port;
+ codec_port_data.enc_buf = enc_buf;
+ codec_port_data.enc_buf_size = enc_buf_size;
+
+ codec_port.get_frame = &codec_get_frame;
+ codec_port.port_data.pdata = &codec_port_data;
+
+ if (vid_port->info.fmt.id == PJMEDIA_FORMAT_MJPEG) {
+ pjmedia_conversion_param conv_param;
+
+ status = pjmedia_libswscale_converter_init(NULL, pool);
+
+ pjmedia_format_copy(&conv_param.src, ¶m.vidparam.fmt);
+ pjmedia_format_copy(&conv_param.dst, ¶m.vidparam.fmt);
+ conv_param.dst.id = PJMEDIA_FORMAT_I420;
+ param.vidparam.fmt.id = conv_param.dst.id;
+
+ status = pjmedia_converter_create(NULL, pool, &conv_param,
+ &codec_port_data.conv);
+ if (status != PJ_SUCCESS) {
+ rc = 270; goto on_return;
+ }
+ }
+
+ status = pjmedia_vid_port_create(pool, ¶m, &renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 230; goto on_return;
+ }
+
+ status = pjmedia_vid_port_connect(renderer, &codec_port,
+ PJ_FALSE);
+ } else {
+ status = pjmedia_vid_port_create(pool, ¶m, &renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 230; goto on_return;
+ }
+
+ /* Connect avi port to renderer */
+ status = pjmedia_vid_port_connect(renderer, vid_port,
+ PJ_FALSE);
+ }
+
+ if (status != PJ_SUCCESS) {
+ rc = 240; goto on_return;
+ }
+ }
+
+ aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
+ 0,
+ PJMEDIA_TYPE_AUDIO);
+ aud_port = pjmedia_avi_stream_get_port(aud_stream);
+
+ if (aud_port) {
+ status = pjmedia_aud_dev_default_param(
+ PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV,
+ &aparam);
+ if (status != PJ_SUCCESS) {
+ rc = 310; goto on_return;
+ }
+
+ aparam.dir = PJMEDIA_DIR_PLAYBACK;
+ afd = pjmedia_format_get_audio_format_detail(&aud_port->info.fmt,
+ PJ_TRUE);
+ aparam.clock_rate = afd->clock_rate;
+ aparam.channel_count = afd->channel_count;
+ aparam.bits_per_sample = afd->bits_per_sample;
+ aparam.samples_per_frame = afd->frame_time_usec * aparam.clock_rate *
+ aparam.channel_count / 1000000;
+
+ status = pjmedia_aud_stream_create(&aparam, NULL, &avi_play_cb,
+ aud_port,
+ &strm);
+ if (status != PJ_SUCCESS) {
+ rc = 320; goto on_return;
+ }
+
+ /* Start audio streaming.. */
+ status = pjmedia_aud_stream_start(strm);
+ if (status != PJ_SUCCESS) {
+ rc = 330; goto on_return;
+ }
+ }
+
+ if (vid_port) {
+ pjmedia_vid_cb cb;
+
+ pj_bzero(&cb, sizeof(cb));
+ cb.on_event_cb = avi_event_cb;
+ avi_port.aud_stream = strm;
+ avi_port.vid_port = renderer;
+ avi_port.is_running = PJ_TRUE;
+ pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
+
+ /* Start video streaming.. */
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 270; goto on_return;
+ }
+ }
+
+ pj_thread_sleep(150000);
+
+on_return:
+ if (strm) {
+ pjmedia_aud_stream_stop(strm);
+ pjmedia_aud_stream_destroy(strm);
+ }
+ if (renderer)
+ pjmedia_vid_port_destroy(renderer);
+ if (vid_port)
+ pjmedia_port_destroy(vid_port);
+ if (codec) {
+ codec->op->close(codec);
+ pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
+ }
+
+ return rc;
+}
+
+static int loopback_test(pj_pool_t *pool)
+{
+ pjmedia_vid_port *capture=NULL, *renderer=NULL;
+ pjmedia_vid_port_param param;
+ pjmedia_video_format_detail *vfd;
+ pj_status_t status;
+ int rc = 0;
+
+ PJ_LOG(3, (THIS_FILE, " loopback test"));
+
+ pjmedia_vid_port_param_default(¶m);
+
+ /* Create capture, set it to active (master) */
+ status = pjmedia_vid_dev_default_param(pool,
+ PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
+// 3, /* Hard-coded capture device */
+ ¶m.vidparam);
+ if (status != PJ_SUCCESS) {
+ rc = 100; goto on_return;
+ }
+ param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
+ param.active = PJ_TRUE;
+
+ if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
+ rc = 103; goto on_return;
+ }
+
+ vfd = pjmedia_format_get_video_format_detail(¶m.vidparam.fmt, PJ_TRUE);
+ if (vfd == NULL) {
+ rc = 105; goto on_return;
+ }
+
+ status = pjmedia_vid_port_create(pool, ¶m, &capture);
+ if (status != PJ_SUCCESS) {
+ rc = 110; goto on_return;
+ }
+
+ /* Create renderer, set it to passive (slave) */
+ param.active = PJ_FALSE;
+ param.vidparam.dir = PJMEDIA_DIR_RENDER;
+ param.vidparam.rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+// param.vidparam.rend_id = 6; /* Hard-coded render device */
+ param.vidparam.disp_size = vfd->size;
+
+ status = pjmedia_vid_port_create(pool, ¶m, &renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 130; goto on_return;
+ }
+
+ /* Connect capture to renderer */
+ status = pjmedia_vid_port_connect(capture,
+ pjmedia_vid_port_get_passive_port(renderer),
+ PJ_FALSE);
+ if (status != PJ_SUCCESS) {
+ rc = 140; goto on_return;
+ }
+
+ /* Start streaming.. */
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 150; goto on_return;
+ }
+ status = pjmedia_vid_port_start(capture);
+ if (status != PJ_SUCCESS) {
+ rc = 160; goto on_return;
+ }
+
+ /* Sleep while the webcam is being displayed... */
+ pj_thread_sleep(20000);
+
+on_return:
+ PJ_PERROR(3, (THIS_FILE, status, " error"));
+ if (capture)
+ pjmedia_vid_port_destroy(capture);
+ if (renderer)
+ pjmedia_vid_port_destroy(renderer);
+
+ return rc;
+}
+
+int vid_dev_test(void)
+{
+ pj_pool_t *pool;
+ int rc = 0;
+ pj_status_t status;
+
+ PJ_LOG(3, (THIS_FILE, "Video device tests.."));
+
+ pool = pj_pool_create(mem, "Viddev test", 256, 256, 0);
+
+ status = pjmedia_vid_subsys_init(mem);
+ if (status != PJ_SUCCESS)
+ return -10;
+
+ status = pjmedia_aud_subsys_init(mem);
+ if (status != PJ_SUCCESS) {
+ return -20;
+ }
+
+ rc = enum_devs();
+ if (rc != 0)
+ goto on_return;
+
+ rc = aviplay_test(pool);
+ //if (rc != 0)
+ // goto on_return;
+ // Ignore error
+ rc = 0;
+
+ rc = loopback_test(pool);
+ if (rc != 0)
+ goto on_return;
+
+on_return:
+ pjmedia_aud_subsys_shutdown();
+ pjmedia_vid_subsys_shutdown();
+ pj_pool_release(pool);
+
+ return rc;
+}
+
+