blob: 007ef3ba8ea03f4cd5ceadf1a113db5a81b34012 [file] [log] [blame]
Benny Prijonoc45d9512010-12-10 11:04:30 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2009 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_codecs.h>
23#include <pjmedia/vid_codec.h>
24#include <pjmedia_videodev.h>
25
26#define THIS_FILE "vid_dev_test.c"
27
28pj_status_t pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr,
29 pj_pool_t *pool);
30
31typedef struct codec_port_data_t
32{
33 pjmedia_vid_codec *codec;
34 pjmedia_port *src_port;
35 pj_uint8_t *enc_buf;
36 pj_size_t enc_buf_size;
37
38 pjmedia_converter *conv;
39} codec_port_data_t;
40
41typedef struct avi_port_t
42{
43 pjmedia_vid_port *vid_port;
44 pjmedia_aud_stream *aud_stream;
45 pj_bool_t is_running;
46} avi_port_t;
47
48static int enum_devs(void)
49{
50 unsigned i, dev_cnt;
51 pj_status_t status;
52
53 PJ_LOG(3, (THIS_FILE, " device enums"));
54 dev_cnt = pjmedia_vid_dev_count();
55 for (i = 0; i < dev_cnt; ++i) {
56 pjmedia_vid_dev_info info;
57 status = pjmedia_vid_dev_get_info(i, &info);
58 if (status == PJ_SUCCESS) {
59 PJ_LOG(3, (THIS_FILE, "%3d: %s - %s", i, info.driver, info.name));
60 }
61 }
62
63 return PJ_SUCCESS;
64}
65
66static pj_status_t avi_play_cb(void *user_data, pjmedia_frame *frame)
67{
68 return pjmedia_port_get_frame((pjmedia_port*)user_data, frame);
69}
70
71static pj_status_t avi_event_cb(pjmedia_vid_stream *stream,
72 void *user_data,
73 pjmedia_vid_event *event)
74{
75 avi_port_t *ap = (avi_port_t *)user_data;
76
77 PJ_UNUSED_ARG(stream);
78
79 if (event->event_type != PJMEDIA_EVENT_MOUSEBUTTONDOWN)
80 return PJ_SUCCESS;
81
82 if (ap->is_running) {
83 pjmedia_vid_port_stop(ap->vid_port);
84 if (ap->aud_stream)
85 pjmedia_aud_stream_stop(ap->aud_stream);
86 } else {
87 pjmedia_vid_port_start(ap->vid_port);
88 if (ap->aud_stream)
89 pjmedia_aud_stream_start(ap->aud_stream);
90 }
91 ap->is_running = !ap->is_running;
92
93 /* We handled the event on our own, so return non-PJ_SUCCESS here */
94 return -1;
95}
96
97static pj_status_t codec_get_frame(pjmedia_port *port,
98 pjmedia_frame *frame)
99{
100 codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
101 pjmedia_vid_codec *codec = port_data->codec;
102 pjmedia_frame enc_frame;
103 pj_status_t status;
104
105 enc_frame.buf = port_data->enc_buf;
106 enc_frame.size = port_data->enc_buf_size;
107
108 if (port_data->conv) {
109 pj_size_t frame_size = frame->size;
110
111 status = pjmedia_port_get_frame(port_data->src_port, frame);
112 if (status != PJ_SUCCESS) goto on_error;
113
114 status = codec->op->decode(codec, frame, frame->size, &enc_frame);
115 if (status != PJ_SUCCESS) goto on_error;
116
117 frame->size = frame_size;
118 status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame);
119 if (status != PJ_SUCCESS) goto on_error;
120
121 return PJ_SUCCESS;
122 }
123
124 status = pjmedia_port_get_frame(port_data->src_port, &enc_frame);
125 if (status != PJ_SUCCESS) goto on_error;
126
127 status = codec->op->decode(codec, &enc_frame, frame->size, frame);
128 if (status != PJ_SUCCESS) goto on_error;
129
130 return PJ_SUCCESS;
131
132on_error:
133 pj_perror(3, THIS_FILE, status, "codec_get_frame() error");
134 return status;
135}
136
137static int aviplay_test(pj_pool_t *pool)
138{
139 pjmedia_vid_port *renderer=NULL;
140 pjmedia_vid_port_param param;
141 pjmedia_aud_param aparam;
142 pjmedia_video_format_detail *vfd;
143 pjmedia_audio_format_detail *afd;
144 pjmedia_aud_stream *strm = NULL;
145 pj_status_t status;
146 int rc = 0;
147 pjmedia_avi_streams *avi_streams;
148 pjmedia_avi_stream *vid_stream, *aud_stream;
149 pjmedia_port *vid_port = NULL, *aud_port = NULL;
150 pjmedia_vid_codec *codec=NULL;
151 avi_port_t avi_port;
152#if PJ_WIN32
153 const char *fname = "C:\\Users\\Liong Sauw Ming\\Desktop\\piratesmjpg.avi";
154#else
155 const char *fname = "/home/bennylp/Desktop/installer/video/movies/pirates.avi";
156#endif
157
158 pj_bzero(&avi_port, sizeof(avi_port));
159
160 status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
161 if (status != PJ_SUCCESS) {
162 PJ_PERROR(2,("", status, " Error playing %s (ignored)", fname));
163 rc = 210; goto on_return;
164 }
165
166 vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
167 0,
168 PJMEDIA_TYPE_VIDEO);
169 vid_port = pjmedia_avi_stream_get_port(vid_stream);
170
171 if (vid_port) {
172 pjmedia_vid_port_param_default(&param);
173
174 status = pjmedia_vid_dev_default_param(pool,
175 PJMEDIA_VID_DEFAULT_RENDER_DEV,
176 &param.vidparam);
177 if (status != PJ_SUCCESS) {
178 rc = 220; goto on_return;
179 }
180
181 /* Create renderer, set it to active */
182 param.active = PJ_TRUE;
183 param.vidparam.dir = PJMEDIA_DIR_RENDER;
184 vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
185 PJ_TRUE);
186 pjmedia_format_init_video(&param.vidparam.fmt,
187 vid_port->info.fmt.id,
188 vfd->size.w, vfd->size.h,
189 vfd->fps.num, vfd->fps.denum);
190
191 if (vid_port->info.fmt.id == PJMEDIA_FORMAT_MJPEG ||
192 vid_port->info.fmt.id == PJMEDIA_FORMAT_H263)
193 {
194 /* Prepare codec */
195 pj_str_t codec_id_st;
196 unsigned info_cnt = 1, i, k;
197 const pjmedia_vid_codec_info *codec_info;
198 pj_str_t port_name = {"codec", 5};
199 pj_uint8_t *enc_buf = NULL;
200 pj_size_t enc_buf_size = 0;
201 pjmedia_vid_dev_info rdr_info;
202 pjmedia_port codec_port;
203 codec_port_data_t codec_port_data;
204 pjmedia_vid_codec_param codec_param;
205 struct {
206 pj_uint32_t pjmedia_id;
207 const char *codec_id;
208 } codec_fmts[] =
209 {{PJMEDIA_FORMAT_MJPEG, "mjpeg"},
210 {PJMEDIA_FORMAT_H263, "h263"}};
211 const char *codec_id = NULL;
212
213
214 status = pjmedia_codec_ffmpeg_init(NULL, mem);
215 if (status != PJ_SUCCESS)
216 return -20;
217
218 /* Lookup codec */
219 for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
220 if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
221 codec_id = codec_fmts[i].codec_id;
222 break;
223 }
224 }
225 if (!codec_id) {
226 rc = 242; goto on_return;
227 }
228 pj_cstr(&codec_id_st, codec_id);
229 status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
230 &codec_id_st,
231 &info_cnt,
232 &codec_info,
233 NULL);
234 if (status != PJ_SUCCESS) {
235 rc = 245; goto on_return;
236 }
237 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
238 &codec_param);
239 if (status != PJ_SUCCESS) {
240 rc = 246; goto on_return;
241 }
242
243 pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
244 for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
245 for (k=0; k<rdr_info.fmt_cnt; ++k) {
246 if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
247 {
248 param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
249 }
250 }
251 }
252
253 /* Open codec */
254 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
255 &codec);
256 if (status != PJ_SUCCESS) {
257 rc = 250; goto on_return;
258 }
259
260 status = codec->op->init(codec, pool);
261 if (status != PJ_SUCCESS) {
262 rc = 251; goto on_return;
263 }
264
265 pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
266
267 status = codec->op->open(codec, &codec_param);
268 if (status != PJ_SUCCESS) {
269 rc = 252; goto on_return;
270 }
271
272 /* Alloc encoding buffer */
273 enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
274 codec_param.dec_fmt.det.vid.size.h * 4
275 + 16; /*< padding, just in case */
276 enc_buf = pj_pool_alloc(pool,enc_buf_size);
277
278 /* Init codec port */
279 pj_bzero(&codec_port, sizeof(codec_port));
280 status = pjmedia_port_info_init2(&codec_port.info, &port_name,
281 0x1234,
282 PJMEDIA_DIR_ENCODING,
283 &codec_param.dec_fmt);
284 if (status != PJ_SUCCESS) {
285 rc = 260; goto on_return;
286 }
287 pj_bzero(&codec_port_data, sizeof(codec_port_data));
288 codec_port_data.codec = codec;
289 codec_port_data.src_port = vid_port;
290 codec_port_data.enc_buf = enc_buf;
291 codec_port_data.enc_buf_size = enc_buf_size;
292
293 codec_port.get_frame = &codec_get_frame;
294 codec_port.port_data.pdata = &codec_port_data;
295
296 if (vid_port->info.fmt.id == PJMEDIA_FORMAT_MJPEG) {
297 pjmedia_conversion_param conv_param;
298
299 status = pjmedia_libswscale_converter_init(NULL, pool);
300
301 pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
302 pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
303 conv_param.dst.id = PJMEDIA_FORMAT_I420;
304 param.vidparam.fmt.id = conv_param.dst.id;
305
306 status = pjmedia_converter_create(NULL, pool, &conv_param,
307 &codec_port_data.conv);
308 if (status != PJ_SUCCESS) {
309 rc = 270; goto on_return;
310 }
311 }
312
313 status = pjmedia_vid_port_create(pool, &param, &renderer);
314 if (status != PJ_SUCCESS) {
315 rc = 230; goto on_return;
316 }
317
318 status = pjmedia_vid_port_connect(renderer, &codec_port,
319 PJ_FALSE);
320 } else {
321 status = pjmedia_vid_port_create(pool, &param, &renderer);
322 if (status != PJ_SUCCESS) {
323 rc = 230; goto on_return;
324 }
325
326 /* Connect avi port to renderer */
327 status = pjmedia_vid_port_connect(renderer, vid_port,
328 PJ_FALSE);
329 }
330
331 if (status != PJ_SUCCESS) {
332 rc = 240; goto on_return;
333 }
334 }
335
336 aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
337 0,
338 PJMEDIA_TYPE_AUDIO);
339 aud_port = pjmedia_avi_stream_get_port(aud_stream);
340
341 if (aud_port) {
342 status = pjmedia_aud_dev_default_param(
343 PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV,
344 &aparam);
345 if (status != PJ_SUCCESS) {
346 rc = 310; goto on_return;
347 }
348
349 aparam.dir = PJMEDIA_DIR_PLAYBACK;
350 afd = pjmedia_format_get_audio_format_detail(&aud_port->info.fmt,
351 PJ_TRUE);
352 aparam.clock_rate = afd->clock_rate;
353 aparam.channel_count = afd->channel_count;
354 aparam.bits_per_sample = afd->bits_per_sample;
355 aparam.samples_per_frame = afd->frame_time_usec * aparam.clock_rate *
356 aparam.channel_count / 1000000;
357
358 status = pjmedia_aud_stream_create(&aparam, NULL, &avi_play_cb,
359 aud_port,
360 &strm);
361 if (status != PJ_SUCCESS) {
362 rc = 320; goto on_return;
363 }
364
365 /* Start audio streaming.. */
366 status = pjmedia_aud_stream_start(strm);
367 if (status != PJ_SUCCESS) {
368 rc = 330; goto on_return;
369 }
370 }
371
372 if (vid_port) {
373 pjmedia_vid_cb cb;
374
375 pj_bzero(&cb, sizeof(cb));
376 cb.on_event_cb = avi_event_cb;
377 avi_port.aud_stream = strm;
378 avi_port.vid_port = renderer;
379 avi_port.is_running = PJ_TRUE;
380 pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
381
382 /* Start video streaming.. */
383 status = pjmedia_vid_port_start(renderer);
384 if (status != PJ_SUCCESS) {
385 rc = 270; goto on_return;
386 }
387 }
388
389 pj_thread_sleep(150000);
390
391on_return:
392 if (strm) {
393 pjmedia_aud_stream_stop(strm);
394 pjmedia_aud_stream_destroy(strm);
395 }
396 if (renderer)
397 pjmedia_vid_port_destroy(renderer);
398 if (vid_port)
399 pjmedia_port_destroy(vid_port);
400 if (codec) {
401 codec->op->close(codec);
402 pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
403 }
404
405 return rc;
406}
407
408static int loopback_test(pj_pool_t *pool)
409{
410 pjmedia_vid_port *capture=NULL, *renderer=NULL;
411 pjmedia_vid_port_param param;
412 pjmedia_video_format_detail *vfd;
413 pj_status_t status;
414 int rc = 0;
415
416 PJ_LOG(3, (THIS_FILE, " loopback test"));
417
418 pjmedia_vid_port_param_default(&param);
419
420 /* Create capture, set it to active (master) */
421 status = pjmedia_vid_dev_default_param(pool,
422 PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
423// 3, /* Hard-coded capture device */
424 &param.vidparam);
425 if (status != PJ_SUCCESS) {
426 rc = 100; goto on_return;
427 }
428 param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
429 param.active = PJ_TRUE;
430
431 if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
432 rc = 103; goto on_return;
433 }
434
435 vfd = pjmedia_format_get_video_format_detail(&param.vidparam.fmt, PJ_TRUE);
436 if (vfd == NULL) {
437 rc = 105; goto on_return;
438 }
439
440 status = pjmedia_vid_port_create(pool, &param, &capture);
441 if (status != PJ_SUCCESS) {
442 rc = 110; goto on_return;
443 }
444
445 /* Create renderer, set it to passive (slave) */
446 param.active = PJ_FALSE;
447 param.vidparam.dir = PJMEDIA_DIR_RENDER;
448 param.vidparam.rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
449// param.vidparam.rend_id = 6; /* Hard-coded render device */
450 param.vidparam.disp_size = vfd->size;
451
452 status = pjmedia_vid_port_create(pool, &param, &renderer);
453 if (status != PJ_SUCCESS) {
454 rc = 130; goto on_return;
455 }
456
457 /* Connect capture to renderer */
458 status = pjmedia_vid_port_connect(capture,
459 pjmedia_vid_port_get_passive_port(renderer),
460 PJ_FALSE);
461 if (status != PJ_SUCCESS) {
462 rc = 140; goto on_return;
463 }
464
465 /* Start streaming.. */
466 status = pjmedia_vid_port_start(renderer);
467 if (status != PJ_SUCCESS) {
468 rc = 150; goto on_return;
469 }
470 status = pjmedia_vid_port_start(capture);
471 if (status != PJ_SUCCESS) {
472 rc = 160; goto on_return;
473 }
474
475 /* Sleep while the webcam is being displayed... */
476 pj_thread_sleep(20000);
477
478on_return:
479 PJ_PERROR(3, (THIS_FILE, status, " error"));
480 if (capture)
481 pjmedia_vid_port_destroy(capture);
482 if (renderer)
483 pjmedia_vid_port_destroy(renderer);
484
485 return rc;
486}
487
488int vid_dev_test(void)
489{
490 pj_pool_t *pool;
491 int rc = 0;
492 pj_status_t status;
493
494 PJ_LOG(3, (THIS_FILE, "Video device tests.."));
495
496 pool = pj_pool_create(mem, "Viddev test", 256, 256, 0);
497
498 status = pjmedia_vid_subsys_init(mem);
499 if (status != PJ_SUCCESS)
500 return -10;
501
502 status = pjmedia_aud_subsys_init(mem);
503 if (status != PJ_SUCCESS) {
504 return -20;
505 }
506
507 rc = enum_devs();
508 if (rc != 0)
509 goto on_return;
510
511 rc = aviplay_test(pool);
512 //if (rc != 0)
513 // goto on_return;
514 // Ignore error
515 rc = 0;
516
517 rc = loopback_test(pool);
518 if (rc != 0)
519 goto on_return;
520
521on_return:
522 pjmedia_aud_subsys_shutdown();
523 pjmedia_vid_subsys_shutdown();
524 pj_pool_release(pool);
525
526 return rc;
527}
528
529