blob: 87104126de680ecd68af22dd34ff382cdabc287b [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: vid_codec_test.c 4537 2013-06-19 06:47:43Z riza $ */
2/*
3 * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "test.h"
20#include <pjmedia-codec/ffmpeg_vid_codecs.h>
21#include <pjmedia-videodev/videodev.h>
22#include <pjmedia/vid_codec.h>
23#include <pjmedia/port.h>
24
25
26#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
27
28
29#define THIS_FILE "vid_codec.c"
30
31/*
32 * Capture device setting:
33 * -1 = colorbar,
34 * -2 = any non-colorbar capture device (first found)
35 * x = specified capture device id
36 */
37#define CAPTURE_DEV -1
38
39
40typedef struct codec_port_data_t
41{
42 pjmedia_vid_codec *codec;
43 pjmedia_vid_port *rdr_port;
44 pj_uint8_t *enc_buf;
45 pj_size_t enc_buf_size;
46 pj_uint8_t *pack_buf;
47 pj_size_t pack_buf_size;
48} codec_port_data_t;
49
50static pj_status_t codec_on_event(pjmedia_event *event,
51 void *user_data)
52{
53 codec_port_data_t *port_data = (codec_port_data_t*)user_data;
54
55 if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
56 pjmedia_vid_codec *codec = port_data->codec;
57 pjmedia_vid_codec_param codec_param;
58 pj_status_t status;
59
60 status = pjmedia_vid_codec_get_param(codec, &codec_param);
61 if (status != PJ_SUCCESS)
62 return status;
63
64 status = pjmedia_vid_dev_stream_set_cap(
65 pjmedia_vid_port_get_stream(port_data->rdr_port),
66 PJMEDIA_VID_DEV_CAP_FORMAT,
67 &codec_param.dec_fmt);
68 if (status != PJ_SUCCESS)
69 return status;
70 }
71
72 return PJ_SUCCESS;
73}
74
75static pj_status_t codec_put_frame(pjmedia_port *port,
76 pjmedia_frame *frame)
77{
78 enum { MAX_PACKETS = 50 };
79 codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
80 pj_status_t status;
81 pjmedia_vid_codec *codec = port_data->codec;
82 unsigned enc_cnt = 0;
83 pj_uint8_t *enc_buf;
84 unsigned enc_size_left;
85 pjmedia_frame enc_frames[MAX_PACKETS];
86 pj_bool_t has_more = PJ_FALSE;
87
88 enc_buf = port_data->enc_buf;
89 enc_size_left = (unsigned)port_data->enc_buf_size;
90
91 /*
92 * Encode
93 */
94 enc_frames[enc_cnt].buf = enc_buf;
95 enc_frames[enc_cnt].size = enc_size_left;
96
97 status = pjmedia_vid_codec_encode_begin(codec, NULL, frame, enc_size_left,
98 &enc_frames[enc_cnt], &has_more);
99 if (status != PJ_SUCCESS) goto on_error;
100
101 enc_buf += enc_frames[enc_cnt].size;
102 enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
103
104 ++enc_cnt;
105 while (has_more) {
106 enc_frames[enc_cnt].buf = enc_buf;
107 enc_frames[enc_cnt].size = enc_size_left;
108
109 status = pjmedia_vid_codec_encode_more(codec, enc_size_left,
110 &enc_frames[enc_cnt],
111 &has_more);
112 if (status != PJ_SUCCESS)
113 break;
114
115 enc_buf += enc_frames[enc_cnt].size;
116 enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
117
118 ++enc_cnt;
119
120 if (enc_cnt >= MAX_PACKETS) {
121 assert(!"Too many packets!");
122 break;
123 }
124 }
125
126 /*
127 * Decode
128 */
129 status = pjmedia_vid_codec_decode(codec, enc_cnt, enc_frames,
130 (unsigned)frame->size, frame);
131 if (status != PJ_SUCCESS) goto on_error;
132
133 /* Display */
134 status = pjmedia_port_put_frame(
135 pjmedia_vid_port_get_passive_port(port_data->rdr_port),
136 frame);
137 if (status != PJ_SUCCESS) goto on_error;
138
139 return PJ_SUCCESS;
140
141on_error:
142 pj_perror(3, THIS_FILE, status, "codec_put_frame() error");
143 return status;
144}
145
146static const char* dump_codec_info(const pjmedia_vid_codec_info *info)
147{
148 static char str[80];
149 unsigned i;
150 char *p = str;
151
152 /* Raw format ids */
153 for (i=0; (i<info->dec_fmt_id_cnt) && (p-str+5<sizeof(str)); ++i) {
154 pj_memcpy(p, &info->dec_fmt_id[i], 4);
155 p += 4;
156 *p++ = ' ';
157 }
158 *p = '\0';
159
160 return str;
161}
162
163static int enum_codecs()
164{
165 unsigned i, cnt;
166 pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
167 pj_status_t status;
168
169 PJ_LOG(3, (THIS_FILE, " codec enums"));
170 cnt = PJ_ARRAY_SIZE(info);
171 status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, info, NULL);
172 if (status != PJ_SUCCESS)
173 return 100;
174
175 for (i = 0; i < cnt; ++i) {
176 PJ_LOG(3, (THIS_FILE, " %-16.*s %c%c %s",
177 info[i].encoding_name.slen, info[i].encoding_name.ptr,
178 (info[i].dir & PJMEDIA_DIR_ENCODING? 'E' : ' '),
179 (info[i].dir & PJMEDIA_DIR_DECODING? 'D' : ' '),
180 dump_codec_info(&info[i])));
181 }
182
183 return PJ_SUCCESS;
184}
185
186static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
187 pjmedia_vid_packing packing)
188{
189 const pj_str_t port_name = {"codec", 5};
190
191 pjmedia_vid_codec *codec=NULL;
192 pjmedia_port codec_port;
193 codec_port_data_t codec_port_data;
194 pjmedia_vid_codec_param codec_param;
195 const pjmedia_vid_codec_info *codec_info;
196 const char *packing_name;
197 pjmedia_vid_dev_index cap_idx, rdr_idx;
198 pjmedia_vid_port *capture=NULL, *renderer=NULL;
199 pjmedia_vid_port_param vport_param;
200 pjmedia_video_format_detail *vfd;
201 char codec_name[5];
202 pj_status_t status;
203 int rc = 0;
204
205 switch (packing) {
206 case PJMEDIA_VID_PACKING_PACKETS:
207 packing_name = "framed";
208 break;
209 case PJMEDIA_VID_PACKING_WHOLE:
210 packing_name = "whole";
211 break;
212 default:
213 packing_name = "unknown";
214 break;
215 }
216
217 PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s",
218 codec_id, packing_name));
219
220 /* Lookup codec */
221 {
222 pj_str_t codec_id_st;
223 unsigned info_cnt = 1;
224
225 /* Lookup codec */
226 pj_cstr(&codec_id_st, codec_id);
227 status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
228 &info_cnt,
229 &codec_info, NULL);
230 if (status != PJ_SUCCESS) {
231 rc = 205; goto on_return;
232 }
233 }
234
235
236#if CAPTURE_DEV == -1
237 /* Lookup colorbar source */
238 status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx);
239 if (status != PJ_SUCCESS) {
240 rc = 206; goto on_return;
241 }
242#elif CAPTURE_DEV == -2
243 /* Lookup any first non-colorbar source */
244 {
245 unsigned i, cnt;
246 pjmedia_vid_dev_info info;
247
248 cap_idx = -1;
249 cnt = pjmedia_vid_dev_count();
250 for (i = 0; i < cnt; ++i) {
251 status = pjmedia_vid_dev_get_info(i, &info);
252 if (status != PJ_SUCCESS) {
253 rc = 206; goto on_return;
254 }
255 if (info.dir & PJMEDIA_DIR_CAPTURE &&
256 pj_ansi_stricmp(info.driver, "Colorbar"))
257 {
258 cap_idx = i;
259 break;
260 }
261 }
262
263 if (cap_idx == -1) {
264 status = PJ_ENOTFOUND;
265 rc = 206; goto on_return;
266 }
267 }
268#else
269 cap_idx = CAPTURE_DEV;
270#endif
271
272 /* Lookup SDL renderer */
273 status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx);
274 if (status != PJ_SUCCESS) {
275 rc = 207; goto on_return;
276 }
277
278 /* Prepare codec */
279 {
280 pj_str_t codec_id_st;
281 unsigned info_cnt = 1;
282 const pjmedia_vid_codec_info *codec_info;
283
284 /* Lookup codec */
285 pj_cstr(&codec_id_st, codec_id);
286 status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
287 &info_cnt,
288 &codec_info, NULL);
289 if (status != PJ_SUCCESS) {
290 rc = 245; goto on_return;
291 }
292 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
293 &codec_param);
294 if (status != PJ_SUCCESS) {
295 rc = 246; goto on_return;
296 }
297
298 codec_param.packing = packing;
299
300 /* Open codec */
301 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
302 &codec);
303 if (status != PJ_SUCCESS) {
304 rc = 250; goto on_return;
305 }
306
307 status = pjmedia_vid_codec_init(codec, pool);
308 if (status != PJ_SUCCESS) {
309 rc = 251; goto on_return;
310 }
311
312 status = pjmedia_vid_codec_open(codec, &codec_param);
313 if (status != PJ_SUCCESS) {
314 rc = 252; goto on_return;
315 }
316
317 /* After opened, codec will update the param, let's sync encoder &
318 * decoder format detail.
319 */
320 codec_param.dec_fmt.det = codec_param.enc_fmt.det;
321
322 /* Subscribe to codec events */
323 pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data,
324 codec);
325 }
326
327 pjmedia_vid_port_param_default(&vport_param);
328
329 /* Create capture, set it to active (master) */
330 status = pjmedia_vid_dev_default_param(pool, cap_idx,
331 &vport_param.vidparam);
332 if (status != PJ_SUCCESS) {
333 rc = 220; goto on_return;
334 }
335 pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt);
336 vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
337 vport_param.active = PJ_TRUE;
338
339 if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
340 rc = 221; goto on_return;
341 }
342
343 vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
344 PJ_TRUE);
345 if (vfd == NULL) {
346 rc = 225; goto on_return;
347 }
348
349 status = pjmedia_vid_port_create(pool, &vport_param, &capture);
350 if (status != PJ_SUCCESS) {
351 rc = 226; goto on_return;
352 }
353
354 /* Create renderer, set it to passive (slave) */
355 vport_param.active = PJ_FALSE;
356 vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
357 vport_param.vidparam.rend_id = rdr_idx;
358 vport_param.vidparam.disp_size = vfd->size;
359
360 status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
361 if (status != PJ_SUCCESS) {
362 rc = 230; goto on_return;
363 }
364
365 /* Init codec port */
366 pj_bzero(&codec_port, sizeof(codec_port));
367 status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
368 PJMEDIA_DIR_ENCODING,
369 &codec_param.dec_fmt);
370 if (status != PJ_SUCCESS) {
371 rc = 260; goto on_return;
372 }
373
374 codec_port_data.codec = codec;
375 codec_port_data.rdr_port = renderer;
376 codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
377 codec_param.dec_fmt.det.vid.size.h * 4;
378 codec_port_data.enc_buf = pj_pool_alloc(pool,
379 codec_port_data.enc_buf_size);
380 codec_port_data.pack_buf_size = codec_port_data.enc_buf_size;
381 codec_port_data.pack_buf = pj_pool_alloc(pool,
382 codec_port_data.pack_buf_size);
383
384 codec_port.put_frame = &codec_put_frame;
385 codec_port.port_data.pdata = &codec_port_data;
386
387 /* Connect capture to codec port */
388 status = pjmedia_vid_port_connect(capture,
389 &codec_port,
390 PJ_FALSE);
391 if (status != PJ_SUCCESS) {
392 rc = 270; goto on_return;
393 }
394
395 PJ_LOG(3, (THIS_FILE, " starting codec test: %s<->%.*s %dx%d",
396 pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name),
397 codec_info->encoding_name.slen,
398 codec_info->encoding_name.ptr,
399 codec_param.dec_fmt.det.vid.size.w,
400 codec_param.dec_fmt.det.vid.size.h
401 ));
402
403 /* Start streaming.. */
404 status = pjmedia_vid_port_start(renderer);
405 if (status != PJ_SUCCESS) {
406 rc = 275; goto on_return;
407 }
408 status = pjmedia_vid_port_start(capture);
409 if (status != PJ_SUCCESS) {
410 rc = 280; goto on_return;
411 }
412
413 /* Sleep while the video is being displayed... */
414 pj_thread_sleep(10000);
415
416on_return:
417 if (status != PJ_SUCCESS) {
418 PJ_PERROR(3, (THIS_FILE, status, " error"));
419 }
420 if (capture)
421 pjmedia_vid_port_stop(capture);
422 if (renderer)
423 pjmedia_vid_port_stop(renderer);
424 if (capture)
425 pjmedia_vid_port_destroy(capture);
426 if (renderer)
427 pjmedia_vid_port_destroy(renderer);
428 if (codec) {
429 pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
430 codec);
431 pjmedia_vid_codec_close(codec);
432 pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
433 }
434
435 return rc;
436}
437
438int vid_codec_test(void)
439{
440 pj_pool_t *pool;
441 int rc = 0;
442 pj_status_t status;
443 int orig_log_level;
444
445 orig_log_level = pj_log_get_level();
446 pj_log_set_level(3);
447
448 PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
449
450 pool = pj_pool_create(mem, "Vid codec test", 256, 256, 0);
451
452 status = pjmedia_vid_dev_subsys_init(mem);
453 if (status != PJ_SUCCESS)
454 return -10;
455
456#if PJMEDIA_HAS_FFMPEG_VID_CODEC
457 status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
458 if (status != PJ_SUCCESS)
459 return -20;
460#endif
461
462 rc = enum_codecs();
463 if (rc != 0)
464 goto on_return;
465
466 rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_WHOLE);
467 if (rc != 0)
468 goto on_return;
469
470 rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_PACKETS);
471 if (rc != 0)
472 goto on_return;
473
474on_return:
475#if PJMEDIA_HAS_FFMPEG_VID_CODEC
476 pjmedia_codec_ffmpeg_vid_deinit();
477#endif
478 pjmedia_vid_dev_subsys_shutdown();
479 pj_pool_release(pool);
480 pj_log_set_level(orig_log_level);
481
482 return rc;
483}
484
485
486#endif /* PJMEDIA_HAS_VIDEO */