123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /*
- * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
- *
- * 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 <pjmedia-codec.h>
- #include <pjmedia-videodev/videodev.h>
- #include <pjmedia/vid_codec.h>
- #include <pjmedia/port.h>
- #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
- #define THIS_FILE "vid_codec.c"
- /*
- * Capture device setting:
- * -1 = colorbar,
- * -2 = any non-colorbar capture device (first found)
- * x = specified capture device id
- */
- #define CAPTURE_DEV -1
- typedef struct codec_port_data_t
- {
- pjmedia_vid_codec *codec;
- pjmedia_vid_port *rdr_port;
- pj_uint8_t *enc_buf;
- pj_size_t enc_buf_size;
- pj_uint8_t *pack_buf;
- pj_size_t pack_buf_size;
- } codec_port_data_t;
- static pj_status_t codec_on_event(pjmedia_event *event,
- void *user_data)
- {
- codec_port_data_t *port_data = (codec_port_data_t*)user_data;
- if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
- pjmedia_vid_codec *codec = port_data->codec;
- pjmedia_vid_codec_param codec_param;
- pj_status_t status;
- status = pjmedia_vid_codec_get_param(codec, &codec_param);
- if (status != PJ_SUCCESS)
- return status;
- status = pjmedia_vid_dev_stream_set_cap(
- pjmedia_vid_port_get_stream(port_data->rdr_port),
- PJMEDIA_VID_DEV_CAP_FORMAT,
- &codec_param.dec_fmt);
- if (status != PJ_SUCCESS)
- return status;
- }
- return PJ_SUCCESS;
- }
- static pj_status_t codec_put_frame(pjmedia_port *port,
- pjmedia_frame *frame)
- {
- enum { MAX_PACKETS = 50 };
- codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
- pj_status_t status;
- pjmedia_vid_codec *codec = port_data->codec;
- unsigned enc_cnt = 0;
- pj_uint8_t *enc_buf;
- unsigned enc_size_left;
- pjmedia_frame enc_frames[MAX_PACKETS];
- pj_bool_t has_more = PJ_FALSE;
- enc_buf = port_data->enc_buf;
- enc_size_left = (unsigned)port_data->enc_buf_size;
- /*
- * Encode
- */
- enc_frames[enc_cnt].buf = enc_buf;
- enc_frames[enc_cnt].size = enc_size_left;
- status = pjmedia_vid_codec_encode_begin(codec, NULL, frame, enc_size_left,
- &enc_frames[enc_cnt], &has_more);
- if (status != PJ_SUCCESS) goto on_error;
- enc_buf += enc_frames[enc_cnt].size;
- enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
- ++enc_cnt;
- while (has_more) {
- enc_frames[enc_cnt].buf = enc_buf;
- enc_frames[enc_cnt].size = enc_size_left;
- status = pjmedia_vid_codec_encode_more(codec, enc_size_left,
- &enc_frames[enc_cnt],
- &has_more);
- if (status != PJ_SUCCESS)
- break;
- enc_buf += enc_frames[enc_cnt].size;
- enc_size_left -= (unsigned)enc_frames[enc_cnt].size;
- ++enc_cnt;
- if (enc_cnt >= MAX_PACKETS) {
- assert(!"Too many packets!");
- break;
- }
- }
- /*
- * Decode
- */
- status = pjmedia_vid_codec_decode(codec, enc_cnt, enc_frames,
- (unsigned)frame->size, frame);
- if (status != PJ_SUCCESS) goto on_error;
- /* Display */
- status = pjmedia_port_put_frame(
- pjmedia_vid_port_get_passive_port(port_data->rdr_port),
- frame);
- if (status != PJ_SUCCESS) goto on_error;
- return PJ_SUCCESS;
- on_error:
- pj_perror(3, THIS_FILE, status, "codec_put_frame() error");
- return status;
- }
- static const char* dump_codec_info(const pjmedia_vid_codec_info *info)
- {
- static char str[80];
- unsigned i;
- char *p = str;
- /* Raw format ids */
- for (i=0; (i<info->dec_fmt_id_cnt) && (p-str+5<(int)sizeof(str)); ++i) {
- pj_memcpy(p, &info->dec_fmt_id[i], 4);
- p += 4;
- *p++ = ' ';
- }
- *p = '\0';
- return str;
- }
- static int enum_codecs()
- {
- unsigned i, cnt;
- pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
- pj_status_t status;
- PJ_LOG(3, (THIS_FILE, " codec enums"));
- cnt = PJ_ARRAY_SIZE(info);
- status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, info, NULL);
- if (status != PJ_SUCCESS)
- return 100;
- for (i = 0; i < cnt; ++i) {
- PJ_LOG(3, (THIS_FILE, " %-16.*s %c%c %s",
- (int)info[i].encoding_name.slen, info[i].encoding_name.ptr,
- (info[i].dir & PJMEDIA_DIR_ENCODING? 'E' : ' '),
- (info[i].dir & PJMEDIA_DIR_DECODING? 'D' : ' '),
- dump_codec_info(&info[i])));
- }
- return PJ_SUCCESS;
- }
- static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
- pjmedia_vid_packing packing)
- {
- const pj_str_t port_name = {"codec", 5};
- pjmedia_vid_codec *codec=NULL;
- pjmedia_port codec_port;
- codec_port_data_t codec_port_data;
- pjmedia_vid_codec_param codec_param;
- const pjmedia_vid_codec_info *codec_info;
- const char *packing_name;
- pjmedia_vid_dev_index cap_idx, rdr_idx;
- pjmedia_vid_port *capture=NULL, *renderer=NULL;
- pjmedia_vid_port_param vport_param;
- pjmedia_video_format_detail *vfd;
- char codec_name[5];
- pj_status_t status;
- int rc = 0;
- switch (packing) {
- case PJMEDIA_VID_PACKING_PACKETS:
- packing_name = "framed";
- break;
- case PJMEDIA_VID_PACKING_WHOLE:
- packing_name = "whole";
- break;
- default:
- packing_name = "unknown";
- break;
- }
- PJ_LOG(3, (THIS_FILE, " encode decode test: codec=%s, packing=%s",
- codec_id, packing_name));
- /* Lookup codec */
- {
- pj_str_t codec_id_st;
- unsigned info_cnt = 1;
- /* Lookup codec */
- pj_cstr(&codec_id_st, codec_id);
- status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
- &info_cnt,
- &codec_info, NULL);
- if (status != PJ_SUCCESS) {
- rc = 205; goto on_return;
- }
- }
- #if CAPTURE_DEV == -1
- /* Lookup colorbar source */
- status = pjmedia_vid_dev_lookup("Colorbar", "Colorbar generator", &cap_idx);
- if (status != PJ_SUCCESS) {
- rc = 206; goto on_return;
- }
- #elif CAPTURE_DEV == -2
- /* Lookup any first non-colorbar source */
- {
- unsigned i, cnt;
- pjmedia_vid_dev_info info;
- cap_idx = -1;
- cnt = pjmedia_vid_dev_count();
- for (i = 0; i < cnt; ++i) {
- status = pjmedia_vid_dev_get_info(i, &info);
- if (status != PJ_SUCCESS) {
- rc = 206; goto on_return;
- }
- if (info.dir & PJMEDIA_DIR_CAPTURE &&
- pj_ansi_stricmp(info.driver, "Colorbar"))
- {
- cap_idx = i;
- break;
- }
- }
- if (cap_idx == -1) {
- status = PJ_ENOTFOUND;
- rc = 206; goto on_return;
- }
- }
- #else
- cap_idx = CAPTURE_DEV;
- #endif
- /* Lookup SDL renderer */
- status = pjmedia_vid_dev_lookup("SDL", "SDL renderer", &rdr_idx);
- if (status != PJ_SUCCESS) {
- rc = 207; goto on_return;
- }
- /* Prepare codec */
- {
- pj_str_t codec_id_st;
- unsigned info_cnt = 1;
- /* Lookup codec */
- pj_cstr(&codec_id_st, codec_id);
- status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, &codec_id_st,
- &info_cnt,
- &codec_info, NULL);
- if (status != PJ_SUCCESS) {
- rc = 245; goto on_return;
- }
- status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
- &codec_param);
- if (status != PJ_SUCCESS) {
- rc = 246; goto on_return;
- }
- codec_param.packing = packing;
- /* Don't apply SDP fmtp */
- codec_param.ignore_fmtp = PJ_TRUE;
- /* Open codec */
- status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
- &codec);
- if (status != PJ_SUCCESS) {
- rc = 250; goto on_return;
- }
- status = pjmedia_vid_codec_init(codec, pool);
- if (status != PJ_SUCCESS) {
- rc = 251; goto on_return;
- }
- status = pjmedia_vid_codec_open(codec, &codec_param);
- if (status != PJ_SUCCESS) {
- rc = 252; goto on_return;
- }
- /* After opened, codec will update the param, let's sync encoder &
- * decoder format detail.
- */
- codec_param.dec_fmt.det = codec_param.enc_fmt.det;
- /* Subscribe to codec events */
- pjmedia_event_subscribe(NULL, &codec_on_event, &codec_port_data,
- codec);
- }
- pjmedia_vid_port_param_default(&vport_param);
- /* Create capture, set it to active (master) */
- status = pjmedia_vid_dev_default_param(pool, cap_idx,
- &vport_param.vidparam);
- if (status != PJ_SUCCESS) {
- rc = 220; goto on_return;
- }
- pjmedia_format_copy(&vport_param.vidparam.fmt, &codec_param.dec_fmt);
- vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
- vport_param.active = PJ_TRUE;
- if (vport_param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
- rc = 221; goto on_return;
- }
- vfd = pjmedia_format_get_video_format_detail(&vport_param.vidparam.fmt,
- PJ_TRUE);
- if (vfd == NULL) {
- rc = 225; goto on_return;
- }
- status = pjmedia_vid_port_create(pool, &vport_param, &capture);
- if (status != PJ_SUCCESS) {
- rc = 226; goto on_return;
- }
- /* Create renderer, set it to passive (slave) */
- vport_param.active = PJ_FALSE;
- vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
- vport_param.vidparam.rend_id = rdr_idx;
- vport_param.vidparam.disp_size = vfd->size;
- status = pjmedia_vid_port_create(pool, &vport_param, &renderer);
- if (status != PJ_SUCCESS) {
- rc = 230; goto on_return;
- }
- /* Init codec port */
- pj_bzero(&codec_port, sizeof(codec_port));
- status = pjmedia_port_info_init2(&codec_port.info, &port_name, 0x1234,
- PJMEDIA_DIR_ENCODING,
- &codec_param.dec_fmt);
- if (status != PJ_SUCCESS) {
- rc = 260; goto on_return;
- }
- codec_port_data.codec = codec;
- codec_port_data.rdr_port = renderer;
- codec_port_data.enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
- codec_param.dec_fmt.det.vid.size.h * 4;
- codec_port_data.enc_buf = pj_pool_alloc(pool,
- codec_port_data.enc_buf_size);
- codec_port_data.pack_buf_size = codec_port_data.enc_buf_size;
- codec_port_data.pack_buf = pj_pool_alloc(pool,
- codec_port_data.pack_buf_size);
- codec_port.put_frame = &codec_put_frame;
- codec_port.port_data.pdata = &codec_port_data;
- /* Connect capture to codec port */
- status = pjmedia_vid_port_connect(capture,
- &codec_port,
- PJ_FALSE);
- if (status != PJ_SUCCESS) {
- rc = 270; goto on_return;
- }
- PJ_LOG(3, (THIS_FILE, " starting codec test: %s<->%.*s %dx%d",
- pjmedia_fourcc_name(codec_param.dec_fmt.id, codec_name),
- (int)codec_info->encoding_name.slen,
- codec_info->encoding_name.ptr,
- codec_param.dec_fmt.det.vid.size.w,
- codec_param.dec_fmt.det.vid.size.h
- ));
- /* Start streaming.. */
- status = pjmedia_vid_port_start(renderer);
- if (status != PJ_SUCCESS) {
- rc = 275; goto on_return;
- }
- status = pjmedia_vid_port_start(capture);
- if (status != PJ_SUCCESS) {
- rc = 280; goto on_return;
- }
- /* Sleep while the video is being displayed... */
- pj_thread_sleep(10000);
- 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_vid_port_destroy(renderer);
- if (codec) {
- pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
- codec);
- pjmedia_vid_codec_close(codec);
- pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
- }
- return rc;
- }
- int vid_codec_test(void)
- {
- pj_pool_t *pool;
- int rc = 0;
- pj_status_t status;
- int orig_log_level;
-
- orig_log_level = pj_log_get_level();
- pj_log_set_level(3);
- PJ_LOG(3, (THIS_FILE, "Performing video codec tests.."));
- pool = pj_pool_create(mem, "Vid codec test", 256, 256, 0);
- status = pjmedia_vid_dev_subsys_init(mem);
- if (status != PJ_SUCCESS)
- return -10;
- #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_OPENH264_CODEC
- status = pjmedia_codec_openh264_vid_init(NULL, mem);
- if (status != PJ_SUCCESS) {
- return -22;
- }
- #endif
- #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
- status = pjmedia_codec_vid_toolbox_init(NULL, mem);
- if (status != PJ_SUCCESS) {
- return -23;
- }
- #endif
- #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VPX_CODEC
- status = pjmedia_codec_vpx_vid_init(NULL, mem);
- if (status != PJ_SUCCESS) {
- return -22;
- }
- #endif
- #if PJMEDIA_HAS_FFMPEG_VID_CODEC
- status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
- if (status != PJ_SUCCESS)
- return -20;
- #endif
- rc = enum_codecs();
- if (rc != 0)
- goto on_return;
- #if PJMEDIA_HAS_FFMPEG_VID_CODEC
- rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_WHOLE);
- if (rc != 0)
- goto on_return;
- rc = encode_decode_test(pool, "h263-1998", PJMEDIA_VID_PACKING_PACKETS);
- if (rc != 0)
- goto on_return;
- #endif
- #if PJMEDIA_HAS_FFMPEG_VID_CODEC || PJMEDIA_HAS_OPENH264_CODEC || \
- PJMEDIA_HAS_VID_TOOLBOX_CODEC
- rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_WHOLE);
- if (rc != 0)
- goto on_return;
- rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_PACKETS);
- if (rc != 0)
- goto on_return;
- #endif
- #if PJMEDIA_HAS_VPX_CODEC && PJMEDIA_HAS_VPX_CODEC_VP8
- rc = encode_decode_test(pool, "vp8", PJMEDIA_VID_PACKING_WHOLE);
- if (rc != 0)
- goto on_return;
- rc = encode_decode_test(pool, "vp8", PJMEDIA_VID_PACKING_PACKETS);
- if (rc != 0)
- goto on_return;
- #endif
- #if PJMEDIA_HAS_VPX_CODEC && PJMEDIA_HAS_VPX_CODEC_VP9
- rc = encode_decode_test(pool, "vp9", PJMEDIA_VID_PACKING_WHOLE);
- if (rc != 0)
- goto on_return;
- rc = encode_decode_test(pool, "vp9", PJMEDIA_VID_PACKING_PACKETS);
- if (rc != 0)
- goto on_return;
- #endif
- on_return:
- #if PJMEDIA_HAS_FFMPEG_VID_CODEC
- pjmedia_codec_ffmpeg_vid_deinit();
- #endif
- #if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
- pjmedia_codec_openh264_vid_deinit();
- #endif
- #if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
- pjmedia_codec_vid_toolbox_deinit();
- #endif
- #if defined(PJMEDIA_HAS_VPX_CODEC) && PJMEDIA_HAS_VPX_CODEC != 0
- pjmedia_codec_vpx_vid_deinit();
- #endif
- pjmedia_vid_dev_subsys_shutdown();
- pj_pool_release(pool);
- pj_log_set_level(orig_log_level);
- /* Avoid compile warning */
- PJ_UNUSED_ARG(encode_decode_test);
- return rc;
- }
- #endif /* PJMEDIA_HAS_VIDEO */
|