/* $Id$ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * 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 #include #include #include #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) #define THIS_FILE "vid_dev_test.c" #define LOOP_DURATION 6 static pj_bool_t is_quitting = PJ_FALSE; static pj_status_t vid_event_cb(pjmedia_event *event, void *user_data) { PJ_UNUSED_ARG(user_data); if (event->type == PJMEDIA_EVENT_WND_CLOSED) is_quitting = PJ_TRUE; return PJ_SUCCESS; } static int capture_render_loopback(pj_bool_t active, int cap_dev_id, int rend_dev_id, const pjmedia_format *fmt) { pj_pool_t *pool; pjmedia_vid_port *capture=NULL, *renderer=NULL; pjmedia_vid_dev_info cdi, rdi; pjmedia_vid_port_param param; pjmedia_video_format_detail *vfd; pj_status_t status; int rc = 0, i; pool = pj_pool_create(mem, "vidportloop", 1000, 1000, NULL); status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi); if (status != PJ_SUCCESS) goto on_return; status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi); if (status != PJ_SUCCESS) goto on_return; PJ_LOG(3,(THIS_FILE, " %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps", cdi.name, cdi.driver, rdi.name, rdi.driver, pjmedia_get_video_format_info(NULL, fmt->id)->name, fmt->det.vid.size.w, fmt->det.vid.size.h, fmt->det.vid.fps.num, fmt->det.vid.fps.denum)); pjmedia_vid_port_param_default(¶m); /* Create capture, set it to active (master) */ status = pjmedia_vid_dev_default_param(pool, cap_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 100; goto on_return; } param.vidparam.dir = PJMEDIA_DIR_CAPTURE; param.vidparam.fmt = *fmt; param.active = (active? PJ_TRUE: PJ_FALSE); 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) */ status = pjmedia_vid_dev_default_param(pool, rend_dev_id, ¶m.vidparam); if (status != PJ_SUCCESS) { rc = 120; goto on_return; } param.active = (active? PJ_FALSE: PJ_TRUE); param.vidparam.dir = PJMEDIA_DIR_RENDER; param.vidparam.rend_id = rend_dev_id; param.vidparam.fmt = *fmt; param.vidparam.disp_size = vfd->size; status = pjmedia_vid_port_create(pool, ¶m, &renderer); if (status != PJ_SUCCESS) { rc = 130; goto on_return; } /* Set event handler */ pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer); /* Connect capture to renderer */ status = pjmedia_vid_port_connect( (active? capture: renderer), pjmedia_vid_port_get_passive_port(active? renderer: capture), 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... */ for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) { pj_thread_sleep(100); } on_return: if (status != PJ_SUCCESS) PJ_PERROR(3, (THIS_FILE, status, " error")); if (capture) pjmedia_vid_port_stop(capture); if (renderer) pjmedia_vid_port_stop(renderer); if (capture) pjmedia_vid_port_destroy(capture); if (renderer) { pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer); pjmedia_vid_port_destroy(renderer); } pj_pool_release(pool); return rc; } static int find_device(pjmedia_dir dir, pj_bool_t has_callback) { unsigned i, count = pjmedia_vid_dev_count(); for (i = 0; i < count; ++i) { pjmedia_vid_dev_info cdi; if (pjmedia_vid_dev_get_info(i, &cdi) != PJ_SUCCESS) continue; if ((cdi.dir & dir) != 0 && cdi.has_callback == has_callback) return i; } return -999; } static int vidport_test(void) { int i, j, k, l; int cap_id, rend_id; pjmedia_format_id test_fmts[] = { PJMEDIA_FORMAT_RGBA, PJMEDIA_FORMAT_I420 }; PJ_LOG(3, (THIS_FILE, " Video port tests:")); /* Capturer's role: active/passive. */ for (i = 1; i >= 0; i--) { /* Capturer's device has_callback: TRUE/FALSE. */ for (j = 1; j >= 0; j--) { cap_id = find_device(PJMEDIA_DIR_CAPTURE, j); if (cap_id < 0) continue; /* Renderer's device has callback: TRUE/FALSE. */ for (k = 1; k >= 0; k--) { rend_id = find_device(PJMEDIA_DIR_RENDER, k); if (rend_id < 0) continue; /* Check various formats to test format conversion. */ for (l = 0; l < PJ_ARRAY_SIZE(test_fmts); ++l) { pjmedia_format fmt; PJ_LOG(3,(THIS_FILE, "capturer %s (stream: %s) ===> " "renderer %s (stream: %s)", (i? "active": "passive"), (j? "active": "passive"), (i? "passive": "active"), (k? "active": "passive"))); pjmedia_format_init_video(&fmt, test_fmts[l], 640, 480, 25, 1); capture_render_loopback(i, cap_id, rend_id, &fmt); } } } } return 0; } int vid_port_test(void) { int rc = 0; pj_status_t status; status = pjmedia_vid_dev_subsys_init(mem); if (status != PJ_SUCCESS) return -10; rc = vidport_test(); if (rc != 0) goto on_return; on_return: pjmedia_vid_dev_subsys_shutdown(); return rc; } #endif /* PJMEDIA_HAS_VIDEO */