1
/* $Id: vid_codec_test.c 4537 2013-06-19 06:47:43Z riza $ */
3
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
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.
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.
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
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>
26
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
29
#define THIS_FILE "vid_codec.c"
32
* Capture device setting:
34
* -2 = any non-colorbar capture device (first found)
35
* x = specified capture device id
37
#define CAPTURE_DEV -1
40
typedef struct codec_port_data_t
42
pjmedia_vid_codec *codec;
43
pjmedia_vid_port *rdr_port;
45
pj_size_t enc_buf_size;
47
pj_size_t pack_buf_size;
50
static pj_status_t codec_on_event(pjmedia_event *event,
53
codec_port_data_t *port_data = (codec_port_data_t*)user_data;
55
if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
56
pjmedia_vid_codec *codec = port_data->codec;
57
pjmedia_vid_codec_param codec_param;
60
status = pjmedia_vid_codec_get_param(codec, &codec_param);
61
if (status != PJ_SUCCESS)
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)
75
static pj_status_t codec_put_frame(pjmedia_port *port,
78
enum { MAX_PACKETS = 50 };
79
codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
81
pjmedia_vid_codec *codec = port_data->codec;
84
unsigned enc_size_left;
85
pjmedia_frame enc_frames[MAX_PACKETS];
86
pj_bool_t has_more = PJ_FALSE;
88
enc_buf = port_data->enc_buf;
89
enc_size_left = (unsigned)port_data->enc_buf_size;
94
enc_frames[enc_cnt].buf = enc_buf;
95
enc_frames[enc_cnt].size = enc_size_left;
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;
101
enc_buf += enc_frames[enc_cnt].size;
102
enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
106
enc_frames[enc_cnt].buf = enc_buf;
107
enc_frames[enc_cnt].size = enc_size_left;
109
status = pjmedia_vid_codec_encode_more(codec, enc_size_left,
110
&enc_frames[enc_cnt],
112
if (status != PJ_SUCCESS)
115
enc_buf += enc_frames[enc_cnt].size;
116
enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
120
if (enc_cnt >= MAX_PACKETS) {
121
assert(!"Too many packets!");
129
status = pjmedia_vid_codec_decode(codec, enc_cnt, enc_frames,
130
(unsigned)frame->size, frame);
131
if (status != PJ_SUCCESS) goto on_error;
134
status = pjmedia_port_put_frame(
135
pjmedia_vid_port_get_passive_port(port_data->rdr_port),
137
if (status != PJ_SUCCESS) goto on_error;
142
pj_perror(3, THIS_FILE, status, "codec_put_frame() error");
146
static const char* dump_codec_info(const pjmedia_vid_codec_info *info)
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);
163
static int enum_codecs()
166
pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
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)
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])));
186
static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
187
pjmedia_vid_packing packing)
189
const pj_str_t port_name = {"codec", 5};
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;
206
case PJMEDIA_VID_PACKING_PACKETS:
207
packing_name = "framed";
209
case PJMEDIA_VID_PACKING_WHOLE:
210
packing_name = "whole";
213
packing_name = "unknown";
217
PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s",
218
codec_id, packing_name));
222
pj_str_t codec_id_st;
223
unsigned info_cnt = 1;
226
pj_cstr(&codec_id_st, codec_id);
227
status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
230
if (status != PJ_SUCCESS) {
231
rc = 205; goto on_return;
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;
242
#elif CAPTURE_DEV == -2
243
/* Lookup any first non-colorbar source */
246
pjmedia_vid_dev_info info;
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;
255
if (info.dir & PJMEDIA_DIR_CAPTURE &&
256
pj_ansi_stricmp(info.driver, "Colorbar"))
264
status = PJ_ENOTFOUND;
265
rc = 206; goto on_return;
269
cap_idx = CAPTURE_DEV;
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;
280
pj_str_t codec_id_st;
281
unsigned info_cnt = 1;
282
const pjmedia_vid_codec_info *codec_info;
285
pj_cstr(&codec_id_st, codec_id);
286
status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
289
if (status != PJ_SUCCESS) {
290
rc = 245; goto on_return;
292
status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
294
if (status != PJ_SUCCESS) {
295
rc = 246; goto on_return;
298
codec_param.packing = packing;
301
status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
303
if (status != PJ_SUCCESS) {
304
rc = 250; goto on_return;
307
status = pjmedia_vid_codec_init(codec, pool);
308
if (status != PJ_SUCCESS) {
309
rc = 251; goto on_return;
312
status = pjmedia_vid_codec_open(codec, &codec_param);
313
if (status != PJ_SUCCESS) {
314
rc = 252; goto on_return;
317
/* After opened, codec will update the param, let's sync encoder &
318
* decoder format detail.
320
codec_param.dec_fmt.det = codec_param.enc_fmt.det;
322
/* Subscribe to codec events */
323
pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data,
327
pjmedia_vid_port_param_default(&vport_param);
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;
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;
339
if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
340
rc = 221; goto on_return;
343
vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
346
rc = 225; goto on_return;
349
status = pjmedia_vid_port_create(pool, &vport_param, &capture);
350
if (status != PJ_SUCCESS) {
351
rc = 226; goto on_return;
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;
360
status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
361
if (status != PJ_SUCCESS) {
362
rc = 230; goto on_return;
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;
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);
384
codec_port.put_frame = &codec_put_frame;
385
codec_port.port_data.pdata = &codec_port_data;
387
/* Connect capture to codec port */
388
status = pjmedia_vid_port_connect(capture,
391
if (status != PJ_SUCCESS) {
392
rc = 270; goto on_return;
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
403
/* Start streaming.. */
404
status = pjmedia_vid_port_start(renderer);
405
if (status != PJ_SUCCESS) {
406
rc = 275; goto on_return;
408
status = pjmedia_vid_port_start(capture);
409
if (status != PJ_SUCCESS) {
410
rc = 280; goto on_return;
413
/* Sleep while the video is being displayed... */
414
pj_thread_sleep(10000);
417
if (status != PJ_SUCCESS) {
418
PJ_PERROR(3, (THIS_FILE, status, " error"));
421
pjmedia_vid_port_stop(capture);
423
pjmedia_vid_port_stop(renderer);
425
pjmedia_vid_port_destroy(capture);
427
pjmedia_vid_port_destroy(renderer);
429
pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
431
pjmedia_vid_codec_close(codec);
432
pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
438
int vid_codec_test(void)
445
orig_log_level = pj_log_get_level();
448
PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
450
pool = pj_pool_create(mem, "Vid codec test", 256, 256, 0);
452
status = pjmedia_vid_dev_subsys_init(mem);
453
if (status != PJ_SUCCESS)
456
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
457
status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
458
if (status != PJ_SUCCESS)
466
rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_WHOLE);
470
rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_PACKETS);
475
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
476
pjmedia_codec_ffmpeg_vid_deinit();
478
pjmedia_vid_dev_subsys_shutdown();
479
pj_pool_release(pool);
480
pj_log_set_level(orig_log_level);
486
#endif /* PJMEDIA_HAS_VIDEO */