blob: f991bb54d6f4b08128bfd47e65f95be3aca848b0 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "test.h"
21#include <pjmedia-audiodev/audiodev.h>
22#include <pjmedia-codec/ffmpeg_vid_codecs.h>
23#include <pjmedia/vid_codec.h>
24#include <pjmedia_videodev.h>
25
26
27#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
28
29
30#define THIS_FILE "vid_dev_test.c"
31#define LOOP_DURATION 10
32
33static pj_bool_t is_quitting = PJ_FALSE;
34
35static const char *vid_dir_name(pjmedia_dir dir)
36{
37 switch (dir) {
38 case PJMEDIA_DIR_CAPTURE:
39 return "capture";
40 case PJMEDIA_DIR_RENDER:
41 return "render";
42 case PJMEDIA_DIR_CAPTURE_RENDER:
43 return "capture & render";
44 default:
45 return "unknown";
46 }
47}
48
49static int enum_devs(void)
50{
51 unsigned i, dev_cnt;
52 pj_status_t status;
53
54 PJ_LOG(3, (THIS_FILE, " Enum video devices:"));
55 dev_cnt = pjmedia_vid_dev_count();
56 for (i = 0; i < dev_cnt; ++i) {
57 pjmedia_vid_dev_info di;
58 status = pjmedia_vid_dev_get_info(i, &di);
59 if (status == PJ_SUCCESS) {
60 unsigned j;
61
62 PJ_LOG(3, (THIS_FILE, " %3d: %s (%s) - %s", i, di.name, di.driver,
63 vid_dir_name(di.dir)));
64
65 PJ_LOG(3,(THIS_FILE, " Supported formats:"));
66 for (j=0; j<di.fmt_cnt; ++j) {
67 const pjmedia_video_format_info *vfi;
68
69 vfi = pjmedia_get_video_format_info(NULL, di.fmt[j].id);
70 PJ_LOG(3,(THIS_FILE, " %s",
71 (vfi ? vfi->name : "unknown")));
72 }
73 }
74 }
75
76 return PJ_SUCCESS;
77}
78
79static pj_status_t vid_event_cb(pjmedia_event *event,
80 void *user_data)
81{
82 PJ_UNUSED_ARG(user_data);
83
84 if (event->type == PJMEDIA_EVENT_WND_CLOSED)
85 is_quitting = PJ_TRUE;
86
87 return PJ_SUCCESS;
88}
89
90static int capture_render_loopback(int cap_dev_id, int rend_dev_id,
91 const pjmedia_format *fmt)
92{
93 pj_pool_t *pool;
94 pjmedia_vid_port *capture=NULL, *renderer=NULL;
95 pjmedia_vid_dev_info cdi, rdi;
96 pjmedia_vid_port_param param;
97 pjmedia_video_format_detail *vfd;
98 pj_status_t status;
99 int rc = 0, i;
100
101 pool = pj_pool_create(mem, "vidloop", 1000, 1000, NULL);
102
103 status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi);
104 if (status != PJ_SUCCESS)
105 goto on_return;
106
107 status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi);
108 if (status != PJ_SUCCESS)
109 goto on_return;
110
111 PJ_LOG(3,(THIS_FILE,
112 " %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps",
113 cdi.name, cdi.driver, rdi.name, rdi.driver,
114 pjmedia_get_video_format_info(NULL, fmt->id)->name,
115 fmt->det.vid.size.w, fmt->det.vid.size.h,
116 fmt->det.vid.fps.num, fmt->det.vid.fps.denum));
117
118 pjmedia_vid_port_param_default(&param);
119
120 /* Create capture, set it to active (master) */
121 status = pjmedia_vid_dev_default_param(pool, cap_dev_id,
122 &param.vidparam);
123 if (status != PJ_SUCCESS) {
124 rc = 100; goto on_return;
125 }
126 param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
127 param.vidparam.fmt = *fmt;
128 param.active = PJ_TRUE;
129
130 if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
131 rc = 103; goto on_return;
132 }
133
134 vfd = pjmedia_format_get_video_format_detail(&param.vidparam.fmt, PJ_TRUE);
135 if (vfd == NULL) {
136 rc = 105; goto on_return;
137 }
138
139 status = pjmedia_vid_port_create(pool, &param, &capture);
140 if (status != PJ_SUCCESS) {
141 rc = 110; goto on_return;
142 }
143
144 /* Create renderer, set it to passive (slave) */
145 status = pjmedia_vid_dev_default_param(pool, rend_dev_id,
146 &param.vidparam);
147 if (status != PJ_SUCCESS) {
148 rc = 120; goto on_return;
149 }
150
151 param.active = PJ_FALSE;
152 param.vidparam.dir = PJMEDIA_DIR_RENDER;
153 param.vidparam.rend_id = rend_dev_id;
154 param.vidparam.fmt = *fmt;
155 param.vidparam.disp_size = vfd->size;
156
157 status = pjmedia_vid_port_create(pool, &param, &renderer);
158 if (status != PJ_SUCCESS) {
159 rc = 130; goto on_return;
160 }
161
162 /* Set event handler */
163 pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer);
164
165 /* Connect capture to renderer */
166 status = pjmedia_vid_port_connect(
167 capture,
168 pjmedia_vid_port_get_passive_port(renderer),
169 PJ_FALSE);
170 if (status != PJ_SUCCESS) {
171 rc = 140; goto on_return;
172 }
173
174 /* Start streaming.. */
175 status = pjmedia_vid_port_start(renderer);
176 if (status != PJ_SUCCESS) {
177 rc = 150; goto on_return;
178 }
179 status = pjmedia_vid_port_start(capture);
180 if (status != PJ_SUCCESS) {
181 rc = 160; goto on_return;
182 }
183
184 /* Sleep while the webcam is being displayed... */
185 for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) {
186 pj_thread_sleep(100);
187 }
188
189on_return:
190 if (status != PJ_SUCCESS)
191 PJ_PERROR(3, (THIS_FILE, status, " error"));
192
193 if (capture)
194 pjmedia_vid_port_stop(capture);
195 if (renderer)
196 pjmedia_vid_port_stop(renderer);
197 if (capture)
198 pjmedia_vid_port_destroy(capture);
199 if (renderer) {
200 pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer);
201 pjmedia_vid_port_destroy(renderer);
202 }
203
204 pj_pool_release(pool);
205 return rc;
206}
207
208static int loopback_test(void)
209{
210 unsigned count, i;
211 pjmedia_format_id test_fmts[] = {
212 PJMEDIA_FORMAT_YUY2
213 };
214 pjmedia_rect_size test_sizes[] = {
215 {176,144}, /* QCIF */
216 {352,288}, /* CIF */
217 {704,576} /* 4CIF */
218 };
219 pjmedia_ratio test_fpses[] = {
220 {25, 1},
221 {30, 1},
222 };
223 pj_status_t status;
224
225 PJ_LOG(3, (THIS_FILE, " Loopback tests (prepare you webcams):"));
226
227 count = pjmedia_vid_dev_count();
228 for (i=0; i<count; ++i) {
229 pjmedia_vid_dev_info cdi;
230 unsigned j;
231
232 status = pjmedia_vid_dev_get_info(i, &cdi);
233 if (status != PJ_SUCCESS)
234 return -300;
235
236 /* Only interested with capture device */
237 if ((cdi.dir & PJMEDIA_DIR_CAPTURE) == 0)
238 continue;
239
240 for (j=i+1; j<count; ++j) {
241 pjmedia_vid_dev_info rdi;
242 unsigned k;
243
244 status = pjmedia_vid_dev_get_info(j, &rdi);
245 if (status != PJ_SUCCESS)
246 return -310;
247
248 /* Only interested with render device */
249 if ((rdi.dir & PJMEDIA_DIR_RENDER) == 0)
250 continue;
251
252 /* Test with the format, size, and fps combinations */
253 for (k=0; k<PJ_ARRAY_SIZE(test_fmts); ++k) {
254 unsigned l;
255
256 for (l=0; l<PJ_ARRAY_SIZE(test_sizes); ++l) {
257 unsigned m;
258
259 for (m=0; m<PJ_ARRAY_SIZE(test_fpses); ++m) {
260 pjmedia_format fmt;
261
262 pjmedia_format_init_video(&fmt, test_fmts[k],
263 test_sizes[l].w,
264 test_sizes[l].h,
265 test_fpses[m].num,
266 test_fpses[m].denum);
267
268 capture_render_loopback(i, j, &fmt);
269 }
270 }
271 } /* k */
272
273 }
274 }
275
276 return 0;
277}
278
279int vid_dev_test(void)
280{
281 int rc = 0;
282 pj_status_t status;
283
284 status = pjmedia_vid_dev_subsys_init(mem);
285 if (status != PJ_SUCCESS)
286 return -10;
287
288 rc = enum_devs();
289 if (rc != 0)
290 goto on_return;
291
292 rc = loopback_test();
293 if (rc != 0)
294 goto on_return;
295
296on_return:
297 pjmedia_vid_dev_subsys_shutdown();
298
299 return rc;
300}
301
302
303#endif /* PJMEDIA_HAS_VIDEO */