Пример #1
0
static pj_uint32_t match_format_id(pj_uint32_t req_id,
				   pj_uint32_t sup_id)
{
    const pjmedia_video_format_info *req_fmt_info, *sup_fmt_info;

    if (req_id == sup_id)
	return FMT_MATCH;

    req_fmt_info = pjmedia_get_video_format_info( 
					pjmedia_video_format_mgr_instance(),
					req_id);

    sup_fmt_info = pjmedia_get_video_format_info( 
					pjmedia_video_format_mgr_instance(),
					sup_id);

    if ((req_fmt_info == NULL) || (sup_fmt_info == NULL)) {
	return FMT_DIFF_COLOR_SPACE;
    }

    if (req_fmt_info->color_model == sup_fmt_info->color_model) {
	return FMT_SAME_COLOR_SPACE;
    }

    return FMT_DIFF_COLOR_SPACE;
}
Пример #2
0
void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, const char *title)
{
    char capnames[120];
    char formats[200];
    const char *dirname;
    unsigned i;
    int st_len;

    if (vdi->dir == PJMEDIA_DIR_CAPTURE_RENDER) {
	dirname = "capture, render";
    } else if (vdi->dir == PJMEDIA_DIR_CAPTURE) {
	dirname = "capture";
    } else {
	dirname = "render";
    }


    capnames[0] = '\0';
    st_len = 0;
    for (i=0; i<sizeof(int)*8 && (1 << i) < PJMEDIA_VID_DEV_CAP_MAX; ++i) {
	if (vdi->caps & (1 << i)) {
	    const char *capname = pjmedia_vid_dev_cap_name(1 << i, NULL);
	    if (capname) {
		int tmp_len = (int)strlen(capname);
		if ((int)sizeof(capnames) - st_len <= tmp_len)
		    break;

		st_len += (tmp_len + 2);
		if (*capnames)
		    strcat(capnames, ", ");
		strcat(capnames, capname);
	    }
	}
    }

    formats[0] = '\0';
    st_len = 0;
    for (i=0; i<vdi->fmt_cnt; ++i) {
	const pjmedia_video_format_info *vfi =
		pjmedia_get_video_format_info(NULL, vdi->fmt[i].id);
	if (vfi) {
	    int tmp_len = (int)strlen(vfi->name);
	    if ((int)sizeof(formats) - st_len <= tmp_len) {
		st_len = -1;
		break;
	    }

	    st_len += (tmp_len + 2);
	    if (*formats)
		strcat(formats, ", ");
	    strcat(formats, vfi->name);
	}
    }

    PJ_LOG(3,(THIS_FILE, "%3d %s [%s][%s] %s", id, vdi->name, vdi->driver,
	      dirname, title));
    PJ_LOG(3,(THIS_FILE, "    Supported capabilities: %s", capnames));
    PJ_LOG(3,(THIS_FILE, "    Supported formats: %s%s", formats,
			      (st_len<0? " ..." : "")));
}
Пример #3
0
/* API: create stream */
static pj_status_t
opengl_factory_create_stream(pjmedia_vid_dev_factory *f,
                             pjmedia_vid_dev_param *param,
                             const pjmedia_vid_dev_cb *cb,
                             void *user_data,
                             pjmedia_vid_dev_stream **p_vid_strm)
{
    struct opengl_factory *qf = (struct opengl_factory*)f;
    pj_pool_t *pool;
    const pjmedia_video_format_info *vfi;
    
    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
    PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
		     param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
                     (param->dir == PJMEDIA_DIR_CAPTURE ||
                      param->dir == PJMEDIA_DIR_RENDER),
		     PJ_EINVAL);
    
    vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
    if (!vfi)
        return PJMEDIA_EVID_BADFORMAT;
    
    /* Create and Initialize stream descriptor */
    pool = pj_pool_create(qf->pf, "opengl-dev", 4000, 4000, NULL);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    return pjmedia_vid_dev_opengl_imp_create_stream(pool, param, cb,
                                                    user_data, p_vid_strm);
}
Пример #4
0
/*
 * Add a destination media port to the video tee. Create a converter if
 * necessary.
 */
pj_status_t pjmedia_vid_tee_add_dst_port2(pjmedia_port *vid_tee,
						  unsigned option,
						  pjmedia_port *port)
{
    vid_tee_port *tee = (vid_tee_port*)vid_tee;
    pjmedia_video_format_detail *vfd;
    
    PJ_ASSERT_RETURN(vid_tee && vid_tee->info.signature==TEE_PORT_SIGN,
		     PJ_EINVAL);
    
    if (tee->dst_port_cnt >= tee->dst_port_maxcnt)
	return PJ_ETOOMANY;
    
    pj_bzero(&tee->tee_conv[tee->dst_port_cnt], sizeof(tee->tee_conv[0]));
    
    /* Check if we need to create a converter. */
    vfd = pjmedia_format_get_video_format_detail(&port->info.fmt, PJ_TRUE);
    if (vid_tee->info.fmt.id != port->info.fmt.id ||
        vfd->size.w != vid_tee->info.fmt.det.vid.size.w ||
	vfd->size.h != vid_tee->info.fmt.det.vid.size.h)
    {
        const pjmedia_video_format_info *vfi;
        pjmedia_video_apply_fmt_param vafp;
        pjmedia_conversion_param conv_param;
        pj_status_t status;

        vfi = pjmedia_get_video_format_info(NULL, port->info.fmt.id);
        if (vfi == NULL)
            return PJMEDIA_EBADFMT;

        pj_bzero(&vafp, sizeof(vafp));
        vafp.size = port->info.fmt.det.vid.size;
        status = vfi->apply_fmt(vfi, &vafp);
        if (status != PJ_SUCCESS)
            return status;
        
        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)?
                    2: 1, vafp.framebytes);
        
        pjmedia_format_copy(&conv_param.src, &vid_tee->info.fmt);
	pjmedia_format_copy(&conv_param.dst, &port->info.fmt);
        
        status = pjmedia_converter_create(
                     NULL, tee->pool, &conv_param,
                     &tee->tee_conv[tee->dst_port_cnt].conv);
        if (status != PJ_SUCCESS)
            return status;
        
        tee->tee_conv[tee->dst_port_cnt].conv_buf_size = vafp.framebytes;
    } else {
        realloc_buf(tee, (option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC)?
                    1: 0, tee->buf_size);        
    }
    
    tee->dst_ports[tee->dst_port_cnt].dst = port;
    tee->dst_ports[tee->dst_port_cnt].option = option;
    ++tee->dst_port_cnt;
    
    return PJ_SUCCESS;
}
Пример #5
0
static pj_status_t check_decode_result(pjmedia_vid_codec *codec,
                                       const vpx_image_t *img,
                                       const pj_timestamp *ts) {
    vpx_private *vpx = (vpx_private*) codec->codec_data;
    pjmedia_video_apply_fmt_param *vafp = &vpx->dec_vafp;
    pjmedia_event event;
    int res, reference_updates = 0;

    /* Check for format change.
     */
    if (img->d_w != (int) vafp->size.w || img->d_h != (int) vafp->size.h) {
        pj_status_t status;

        /* Update decoder format in param */
        vpx->param.dec_fmt.det.vid.size.w = img->d_w;
        vpx->param.dec_fmt.det.vid.size.h = img->d_h;

        /* Re-init format info and apply-param of decoder */
        vpx->dec_vfi = pjmedia_get_video_format_info(NULL, vpx->param.dec_fmt.id);
        if (!vpx->dec_vfi)
            return PJ_ENOTSUP;
        pj_bzero(&vpx->dec_vafp, sizeof(vpx->dec_vafp));
        vpx->dec_vafp.size = vpx->param.dec_fmt.det.vid.size;
        vpx->dec_vafp.buffer = NULL;
        status = (*vpx->dec_vfi->apply_fmt)(vpx->dec_vfi, &vpx->dec_vafp);
        if (status != PJ_SUCCESS)
            return status;

        /* Realloc buffer if necessary */
	if (vpx->dec_vafp.framebytes > vpx->dec_buf_size) {
	    PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u",
		       (unsigned)vpx->dec_buf_size,
		       (unsigned)vpx->dec_vafp.framebytes));
	    vpx->dec_buf_size = (unsigned)vpx->dec_vafp.framebytes;
	    vpx->dec_buf = pj_pool_alloc(vpx->pool, vpx->dec_buf_size);
	}

        /* Broadcast format changed event */
        pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
        event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
        pj_memcpy(&event.data.fmt_changed.new_fmt, &vpx->param.dec_fmt, sizeof(vpx->param.dec_fmt));
        pjmedia_event_publish(NULL, codec, &event, 0);
    }

    /* Check for found keyframe */
    res = vpx_codec_control(&vpx->decoder, VP8D_GET_LAST_REF_UPDATES, &reference_updates);
    if (res == VPX_CODEC_OK) {
        pj_bool_t got_keyframe = (reference_updates & VP8_GOLD_FRAME);
        if (got_keyframe) {
            pj_get_timestamp(&vpx->last_dec_keyframe_ts);

            /* Broadcast keyframe event */
            pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
            pjmedia_event_publish(NULL, codec, &event, 0);
        }
    }

    return PJ_SUCCESS;
}
Пример #6
0
static pj_status_t create_converter(pjmedia_vid_port *vp)
{
    if (vp->conv.conv) {
        pjmedia_converter_destroy(vp->conv.conv);
	vp->conv.conv = NULL;
    }

    /* Instantiate converter if necessary */
    if (vp->conv.conv_param.src.id != vp->conv.conv_param.dst.id ||
	(vp->conv.conv_param.src.det.vid.size.w !=
         vp->conv.conv_param.dst.det.vid.size.w) ||
	(vp->conv.conv_param.src.det.vid.size.h !=
         vp->conv.conv_param.dst.det.vid.size.h))
    {
	pj_status_t status;

	/* Yes, we need converter */
	status = pjmedia_converter_create(NULL, vp->pool, &vp->conv.conv_param,
					  &vp->conv.conv);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error creating converter"));
	    return status;
	}
    }

    if (vp->conv.conv ||
        (vp->role==ROLE_ACTIVE && (vp->dir & PJMEDIA_DIR_ENCODING)))
    {
	pj_status_t status;
	const pjmedia_video_format_info *vfi;
	pjmedia_video_apply_fmt_param vafp;

	/* Allocate buffer for conversion */
	vfi = pjmedia_get_video_format_info(NULL, vp->conv.conv_param.dst.id);
	if (!vfi)
	    return PJMEDIA_EBADFMT;

	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = vp->conv.conv_param.dst.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    return PJMEDIA_EBADFMT;

	if (vafp.framebytes > vp->conv.conv_buf_size) {
	    vp->conv.conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes);
	    vp->conv.conv_buf_size = vafp.framebytes;
	}
    }

    vp->conv.usec_ctr = 0;
    vp->conv.usec_src = PJMEDIA_PTIME(&vp->conv.conv_param.src.det.vid.fps);
    vp->conv.usec_dst = PJMEDIA_PTIME(&vp->conv.conv_param.dst.det.vid.fps);

    return PJ_SUCCESS;
}
Пример #7
0
static pj_status_t create_converter(pjmedia_vid_port *vp)
{
    /* Instantiate converter if necessary */
    if (vp->conv_param.src.id != vp->conv_param.dst.id ||
	vp->conv_param.src.det.vid.size.w != vp->conv_param.dst.det.vid.size.w ||
	vp->conv_param.src.det.vid.size.h != vp->conv_param.dst.det.vid.size.h)
    {
	pj_status_t status;

	/* Yes, we need converter */
	const pjmedia_video_format_info *vfi;
	pjmedia_video_apply_fmt_param vafp;

	if (vp->conv) {
	    pjmedia_converter_destroy(vp->conv);
	    vp->conv = NULL;
	}

	status = pjmedia_converter_create(NULL, vp->pool, &vp->conv_param,
					  &vp->conv);
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(THIS_FILE, status, "Error creating converter"));
	    return status;
	}

	/* Allocate buffer for conversion */
	vfi = pjmedia_get_video_format_info(NULL, vp->conv_param.dst.id);
	if (!vfi)
	    return PJMEDIA_EBADFMT;

	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = vp->conv_param.dst.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    return PJMEDIA_EBADFMT;

	if (vafp.framebytes > vp->conv_buf_size) {
	    vp->conv_buf = pj_pool_alloc(vp->pool, vafp.framebytes);
	    vp->conv_buf_size = vafp.framebytes;
	}
    }

    return PJ_SUCCESS;
}
Пример #8
0
/* API: create stream */
static pj_status_t and_factory_create_stream(
					pjmedia_vid_dev_factory *ff,
					pjmedia_vid_dev_param *param,
					const pjmedia_vid_dev_cb *cb,
					void *user_data,
					pjmedia_vid_dev_stream **p_vid_strm)
{
    and_factory *f = (and_factory*)ff;
    pj_pool_t *pool;
    and_stream *strm;
    and_dev_info *adi;
    const pjmedia_video_format_detail *vfd;
    const pjmedia_video_format_info *vfi;
    pjmedia_video_apply_fmt_param vafp;
    pj_uint32_t and_fmt;
    unsigned convert_to_i420 = 0;
    pj_status_t status = PJ_SUCCESS;

    JNIEnv *jni_env;
    pj_bool_t with_attach;
    jobject jcam;

    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
    PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
		     param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
                     param->dir == PJMEDIA_DIR_CAPTURE,
		     PJ_EINVAL);

    pj_bzero(&vafp, sizeof(vafp));
    adi = &f->dev_info[param->cap_id];
    vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);
    vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);

    if (param->fmt.id == PJMEDIA_FORMAT_I420 && adi->forced_i420) {
	/* Not really support I420, need to convert it from YV12/NV21 */
	if (adi->has_nv21) {
	    and_fmt = pj_fmt_to_and(PJMEDIA_FORMAT_NV21);
	    convert_to_i420 = 1;
	} else if (adi->has_yv12) {
	    and_fmt = pj_fmt_to_and(PJMEDIA_FORMAT_YV12);
	    convert_to_i420 = 2;
	} else
	    pj_assert(!"Bug!");
    } else {
	and_fmt = pj_fmt_to_and(param->fmt.id);
    }
    if (!vfi || !and_fmt)
        return PJMEDIA_EVID_BADFORMAT;

    vafp.size = vfd->size;
    if (vfi->apply_fmt(vfi, &vafp) != PJ_SUCCESS)
        return PJMEDIA_EVID_BADFORMAT;

    /* Create and Initialize stream descriptor */
    pool = pj_pool_create(f->pf, "and-dev", 512, 512, NULL);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    strm = PJ_POOL_ZALLOC_T(pool, and_stream);
    pj_memcpy(&strm->param, param, sizeof(*param));
    strm->pool = pool;
    strm->factory = f;
    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
    strm->user_data = user_data;
    pj_memcpy(&strm->vafp, &vafp, sizeof(vafp));
    strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);

    /* Allocate buffer for YV12 -> I420 conversion */
    if (convert_to_i420) {
	pj_assert(vfi->plane_cnt > 1);
	strm->convert_to_i420 = convert_to_i420;
	strm->convert_buf = pj_pool_alloc(pool, vafp.plane_bytes[1]);
    }

    /* Native preview */
    if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW) {
    }

    with_attach = jni_get_env(&jni_env);

    /* Instantiate PjCamera */
    strm->cam_size.w = (vfd->size.w > vfd->size.h? vfd->size.w: vfd->size.h);
    strm->cam_size.h = (vfd->size.w > vfd->size.h? vfd->size.h: vfd->size.w);
    jcam = (*jni_env)->NewObject(jni_env, jobjs.cam.cls, jobjs.cam.m_init,
				 adi->dev_idx,		/* idx */
				 strm->cam_size.w,	/* w */
				 strm->cam_size.h,	/* h */
				 and_fmt,		/* fmt */
				 vfd->fps.num*1000/
				 vfd->fps.denum,	/* fps */
				 (jlong)(intptr_t)strm,	/* user data */
				 NULL			/* SurfaceView */
				 );	   
    if (jcam == NULL) {
        PJ_LOG(3, (THIS_FILE, "Unable to create PjCamera instance"));
        status = PJMEDIA_EVID_SYSERR;
	goto on_return;
    }
    strm->jcam = (jobject)(*jni_env)->NewGlobalRef(jni_env, jcam);
    (*jni_env)->DeleteLocalRef(jni_env, jcam);
    if (strm->jcam == NULL) {
        PJ_LOG(3, (THIS_FILE, "Unable to create global ref to PjCamera"));
        status = PJMEDIA_EVID_SYSERR;
	goto on_return;
    }
    
    /* Video orientation.
     * If we send in portrait, we need to set up orientation converter
     * as well.
     */
    if ((param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) ||
        (vfd->size.h > vfd->size.w))
    {
        if (param->orient == PJMEDIA_ORIENT_UNKNOWN)
    	    param->orient = PJMEDIA_ORIENT_NATURAL;
        and_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION,
    		           &param->orient);
    }

on_return:
    jni_detach_env(with_attach);

    /* Success */
    if (status == PJ_SUCCESS) {
	strm->base.op = &stream_op;
	*p_vid_strm = &strm->base;
    }

    return status;
}
Пример #9
0
/* API: configure the AVI */
PJ_DEF(pj_status_t) pjmedia_avi_dev_alloc( pjmedia_vid_dev_factory *f,
                                           pjmedia_avi_dev_param *p,
                                           pjmedia_vid_dev_index *p_id)
{
    pjmedia_vid_dev_index id;
    struct avi_factory *cf = (struct avi_factory*)f;
    unsigned local_idx;
    struct avi_dev_info *adi = NULL;
    pjmedia_format avi_fmt;
    const pjmedia_video_format_info *vfi;
    pj_status_t status;

    PJ_ASSERT_RETURN(f && p && p_id, PJ_EINVAL);

    if (p_id)
	*p_id = PJMEDIA_VID_INVALID_DEV;

    /* Get a free dev */
    for (local_idx=0; local_idx<cf->dev_count; ++local_idx) {
	if (cf->dev_info[local_idx].avi == NULL) {
	    adi = &cf->dev_info[local_idx];
	    break;
	}
    }

    if (!adi)
	return PJ_ETOOMANY;

    /* Convert local ID to global id */
    status = pjmedia_vid_dev_get_global_index(&cf->base, local_idx, &id);
    if (status != PJ_SUCCESS)
	return status;

    /* Reset */
    if (adi->pool) {
	pj_pool_release(adi->pool);
    }
    pj_bzero(adi, sizeof(*adi));

    /* Reinit */
    PJ_ASSERT_RETURN(p->path.slen, PJ_EINVAL);
    adi->pool = pj_pool_create(cf->pf, "avidi%p", 512, 512, NULL);


    /* Open the AVI */
    pj_strdup_with_null(adi->pool, &adi->fpath, &p->path);
    status = pjmedia_avi_player_create_streams(adi->pool, adi->fpath.ptr, 0,
                                               &adi->avi);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    adi->vid = pjmedia_avi_streams_get_stream_by_media(adi->avi, 0,
                                                       PJMEDIA_TYPE_VIDEO);
    if (!adi->vid) {
	status = PJMEDIA_EVID_BADFORMAT;
	PJ_LOG(4,(THIS_FILE, "Error: cannot find video in AVI %s",
		adi->fpath.ptr));
	goto on_error;
    }

    pjmedia_format_copy(&avi_fmt, &adi->vid->info.fmt);
    vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
    /* Check whether the frame is encoded. */
    if (!vfi || vfi->bpp == 0) {
        /* Yes, prepare codec */
        const pjmedia_vid_codec_info *codec_info;
        pjmedia_vid_codec_param codec_param;
	pjmedia_video_apply_fmt_param vafp;

        /* Lookup codec */
        status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
                                                       avi_fmt.id,
                                                       &codec_info);
        if (status != PJ_SUCCESS || !codec_info)
            goto on_error;

        status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
                                                         &codec_param);
        if (status != PJ_SUCCESS)
            goto on_error;

        /* Open codec */
        status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
                                                   &adi->codec);
        if (status != PJ_SUCCESS)
            goto on_error;

        status = pjmedia_vid_codec_init(adi->codec, adi->pool);
        if (status != PJ_SUCCESS)
            goto on_error;

        codec_param.dir = PJMEDIA_DIR_DECODING;
        codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
        status = pjmedia_vid_codec_open(adi->codec, &codec_param);
        if (status != PJ_SUCCESS)
            goto on_error;

	/* Allocate buffer */
        avi_fmt.id = codec_info->dec_fmt_id[0];
        vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = avi_fmt.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    goto on_error;

	adi->enc_buf = pj_pool_alloc(adi->pool, vafp.framebytes);
	adi->enc_buf_size = vafp.framebytes;
    }

    /* Calculate title */
    if (p->title.slen) {
	pj_strdup_with_null(adi->pool, &adi->title, &p->title);
    } else {
	char *start = p->path.ptr + p->path.slen;
	pj_str_t tmp;

	while (start >= p->path.ptr) {
	    if (*start == '/' || *start == '\\')
		break;
	    --start;
	}
	tmp.ptr = start + 1;
	tmp.slen = p->path.ptr + p->path.slen - tmp.ptr;
	pj_strdup_with_null(adi->pool, &adi->title, &tmp);
    }

    /* Init device info */
    pj_ansi_strncpy(adi->info.name, adi->title.ptr, sizeof(adi->info.name)-1);
    pj_ansi_strncpy(adi->info.driver, DRIVER_NAME, sizeof(adi->info.driver)-1);
    adi->info.dir = PJMEDIA_DIR_CAPTURE;
    adi->info.has_callback = PJ_FALSE;

    adi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
    adi->info.fmt_cnt = 1;
    pjmedia_format_copy(&adi->info.fmt[0], &avi_fmt);

    /* Set out vars */
    if (p_id)
	*p_id = id;
    p->avi_streams = adi->avi;
    if (p->title.slen == 0)
	p->title = adi->title;

    return PJ_SUCCESS;

on_error:
    if (adi->codec) {
        pjmedia_vid_codec_close(adi->codec);
        adi->codec = NULL;
    }
    if (adi->pool) {
	pj_pool_release(adi->pool);
	adi->pool = NULL;
    }
    pjmedia_avi_dev_free(id);
    return status;
}
Пример #10
0
static int capture_render_loopback(pj_bool_t active,
				   int cap_dev_id, int rend_dev_id,
                                   const pjmedia_format *fmt)
{
    pj_pool_t *pool;
    pjmedia_vid_port *capture=NULL, *renderer=NULL;
    pjmedia_vid_dev_info cdi, rdi;
    pjmedia_vid_port_param param;
    pjmedia_video_format_detail *vfd;
    pj_status_t status;
    int rc = 0, i;

    pool = pj_pool_create(mem, "vidportloop", 1000, 1000, NULL);

    status = pjmedia_vid_dev_get_info(cap_dev_id, &cdi);
    if (status != PJ_SUCCESS)
	goto on_return;

    status = pjmedia_vid_dev_get_info(rend_dev_id, &rdi);
    if (status != PJ_SUCCESS)
	goto on_return;

    PJ_LOG(3,(THIS_FILE,
	      "  %s (%s) ===> %s (%s)\t%s\t%dx%d\t@%d:%d fps",
	      cdi.name, cdi.driver, rdi.name, rdi.driver,
	      pjmedia_get_video_format_info(NULL, fmt->id)->name,
	      fmt->det.vid.size.w, fmt->det.vid.size.h,
	      fmt->det.vid.fps.num, fmt->det.vid.fps.denum));

    pjmedia_vid_port_param_default(&param);

    /* Create capture, set it to active (master) */
    status = pjmedia_vid_dev_default_param(pool, cap_dev_id,
					   &param.vidparam);
    if (status != PJ_SUCCESS) {
	rc = 100; goto on_return;
    }
    param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
    param.vidparam.fmt = *fmt;
    param.active = (active? PJ_TRUE: PJ_FALSE);

    if (param.vidparam.fmt.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO) {
	rc = 103; goto on_return;
    }

    vfd = pjmedia_format_get_video_format_detail(&param.vidparam.fmt, PJ_TRUE);
    if (vfd == NULL) {
	rc = 105; goto on_return;
    }

    status = pjmedia_vid_port_create(pool, &param, &capture);
    if (status != PJ_SUCCESS) {
	rc = 110; goto on_return;
    }

    /* Create renderer, set it to passive (slave)  */
    status = pjmedia_vid_dev_default_param(pool, rend_dev_id,
					   &param.vidparam);
    if (status != PJ_SUCCESS) {
	rc = 120; goto on_return;
    }

    param.active = (active? PJ_FALSE: PJ_TRUE);
    param.vidparam.dir = PJMEDIA_DIR_RENDER;
    param.vidparam.rend_id = rend_dev_id;
    param.vidparam.fmt = *fmt;
    param.vidparam.disp_size = vfd->size;

    status = pjmedia_vid_port_create(pool, &param, &renderer);
    if (status != PJ_SUCCESS) {
	rc = 130; goto on_return;
    }

    /* Set event handler */
    pjmedia_event_subscribe(NULL, &vid_event_cb, NULL, renderer);

    /* Connect capture to renderer */
    status = pjmedia_vid_port_connect(
	         (active? capture: renderer),
		 pjmedia_vid_port_get_passive_port(active? renderer: capture),
		 PJ_FALSE);
    if (status != PJ_SUCCESS) {
	rc = 140; goto on_return;
    }

    /* Start streaming.. */
    status = pjmedia_vid_port_start(renderer);
    if (status != PJ_SUCCESS) {
	rc = 150; goto on_return;
    }
    status = pjmedia_vid_port_start(capture);
    if (status != PJ_SUCCESS) {
	rc = 160; goto on_return;
    }

    /* Sleep while the webcam is being displayed... */
    for (i = 0; i < LOOP_DURATION*10 && (!is_quitting); i++) {
        pj_thread_sleep(100);
    }

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_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer);
	pjmedia_vid_port_destroy(renderer);
    }

    pj_pool_release(pool);
    return rc;
}
Пример #11
0
/*
 * Open codec.
 */
static pj_status_t pj_vpx_codec_open(pjmedia_vid_codec *codec, pjmedia_vid_codec_param *attr) {
    vpx_private *vpx;
    pj_status_t status;

    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
    vpx = (vpx_private*) codec->codec_data;

    pj_memcpy(&vpx->param, attr, sizeof(*attr));

    /* Normalize encoding MTU in codec param */
    if (attr->enc_mtu > PJMEDIA_MAX_VID_PAYLOAD_SIZE) {
        attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
    }

    /* Init format info and apply-param of decoder */
    vpx->dec_vfi = pjmedia_get_video_format_info(NULL, vpx->param.dec_fmt.id);
    if (!vpx->dec_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&vpx->dec_vafp, sizeof(vpx->dec_vafp));
    vpx->dec_vafp.size = vpx->param.dec_fmt.det.vid.size;
    vpx->dec_vafp.buffer = NULL;
    status = (*vpx->dec_vfi->apply_fmt)(vpx->dec_vfi, &vpx->dec_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Init format info and apply-param of encoder */
    vpx->enc_vfi = pjmedia_get_video_format_info(NULL, vpx->param.dec_fmt.id);
    if (!vpx->enc_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&vpx->enc_vafp, sizeof(vpx->enc_vafp));
    vpx->enc_vafp.size = vpx->param.enc_fmt.det.vid.size;
    vpx->enc_vafp.buffer = NULL;
    status = (*vpx->enc_vfi->apply_fmt)(vpx->enc_vfi, &vpx->enc_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Open the encoder */
    TRACE_((THIS_FILE, "Open vpx version : %s build : %s", vpx_codec_version_str(), vpx_codec_build_config()));

    if (vpx->param.dir & PJMEDIA_DIR_ENCODING) {
        status = pj_vpx_encoder_open(vpx);
        if (status != PJ_SUCCESS) {
            goto on_error;
        }
    }
    if (vpx->param.dir & PJMEDIA_DIR_DECODING) {
        status = pj_vpx_decoder_open(vpx);
        if (status != PJ_SUCCESS) {
            goto on_error;
        }
    }


    /* Update codec attributes, e.g: encoding format may be changed by
     * SDP fmtp negotiation.
     */
    pj_memcpy(attr, &vpx->param, sizeof(*attr));

    return PJ_SUCCESS;

on_error:
    pj_vpx_codec_close(codec);
    return status;
}
Пример #12
0
/*
 * Create a video tee port with the specified source media port.
 */
pj_status_t pjmedia_vid_tee_create( pj_pool_t *pool,
					    const pjmedia_format *fmt,
					    unsigned max_dst_cnt,
					    pjmedia_port **p_vid_tee)
{
    vid_tee_port *tee;
    pj_str_t name_st;
    const pjmedia_video_format_info *vfi;
    pjmedia_video_apply_fmt_param vafp;
    pj_status_t status;

    PJ_ASSERT_RETURN(pool && fmt && p_vid_tee, PJ_EINVAL);
    PJ_ASSERT_RETURN(fmt->type == PJMEDIA_TYPE_VIDEO, PJ_EINVAL);

    /* Allocate video tee structure */
    tee = PJ_POOL_ZALLOC_T(pool, vid_tee_port);
    tee->pf = pool->factory;
    tee->pool = pj_pool_create(tee->pf, "video tee", 500, 500, NULL);

    /* Initialize video tee structure */
    tee->dst_port_maxcnt = max_dst_cnt;
    tee->dst_ports = (vid_tee_dst_port*)
                     pj_pool_calloc(pool, max_dst_cnt,
                                    sizeof(vid_tee_dst_port));
    tee->tee_conv = (struct vid_tee_conv_t *)
                    pj_pool_calloc(pool, max_dst_cnt,
                                   sizeof(struct vid_tee_conv_t));
    tee->put_frm_flag = (pj_uint8_t*)
			pj_pool_calloc(pool, max_dst_cnt,
				       sizeof(tee->put_frm_flag[0]));

    /* Initialize video tee buffer, its size is one frame */
    vfi = pjmedia_get_video_format_info(NULL, fmt->id);
    if (vfi == NULL)
	return PJMEDIA_EBADFMT;

    pj_bzero(&vafp, sizeof(vafp));
    vafp.size = fmt->det.vid.size;
    status = vfi->apply_fmt(vfi, &vafp);
    if (status != PJ_SUCCESS)
	return status;

    tee->buf_size = vafp.framebytes;

    /* Initialize video tee port */
    status = pjmedia_port_info_init2(&tee->base.info,
				     pj_strset2(&name_st, (char*)TEE_PORT_NAME),
				     TEE_PORT_SIGN,
				     PJMEDIA_DIR_ENCODING,
				     fmt);
    if (status != PJ_SUCCESS)
	return status;

    tee->base.get_frame = &tee_get_frame;
    tee->base.put_frame = &tee_put_frame;
    tee->base.on_destroy = &tee_destroy;

    /* Done */
    *p_vid_tee = &tee->base;

    return PJ_SUCCESS;
}
Пример #13
0
/*
 * main()
 */
int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    pj_pool_t *pool;
    pjmedia_vid_stream *stream = NULL;
    pjmedia_port *enc_port, *dec_port;
    pj_status_t status; 

    pjmedia_vid_port *capture=NULL, *renderer=NULL;
    pjmedia_vid_port_param vpp;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP variables */
    pj_bool_t use_srtp = PJ_FALSE;
    char tmp_tx_key[64];
    char tmp_rx_key[64];
    pj_str_t  srtp_tx_key = {NULL, 0};
    pj_str_t  srtp_rx_key = {NULL, 0};
    pj_str_t  srtp_crypto_suite = {NULL, 0};
    int	tmp_key_len;
#endif

    /* Default values */
    const pjmedia_vid_codec_info *codec_info;
    pjmedia_vid_codec_param codec_param;
    pjmedia_dir dir = PJMEDIA_DIR_DECODING;
    pj_sockaddr_in remote_addr;
    pj_uint16_t local_port = 4000;
    char *codec_id = NULL;
    pjmedia_rect_size tx_size = {0};
    pj_int8_t rx_pt = -1, tx_pt = -1;

    play_file_data play_file = { NULL };
    pjmedia_port *play_port = NULL;
    pjmedia_vid_codec *play_decoder = NULL;
    pjmedia_clock *play_clock = NULL;

    enum {
	OPT_CODEC	= 'c',
	OPT_LOCAL_PORT	= 'p',
	OPT_REMOTE	= 'r',
	OPT_PLAY_FILE	= 'f',
	OPT_SEND_RECV	= 'b',
	OPT_SEND_ONLY	= 's',
	OPT_RECV_ONLY	= 'i',
	OPT_SEND_WIDTH	= 'W',
	OPT_SEND_HEIGHT	= 'H',
	OPT_RECV_PT	= 't',
	OPT_SEND_PT	= 'T',
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	OPT_USE_SRTP	= 'S',
#endif
	OPT_SRTP_TX_KEY	= 'x',
	OPT_SRTP_RX_KEY	= 'y',
	OPT_HELP	= 'h',
    };

    struct pj_getopt_option long_options[] = {
	{ "codec",	    1, 0, OPT_CODEC },
	{ "local-port",	    1, 0, OPT_LOCAL_PORT },
	{ "remote",	    1, 0, OPT_REMOTE },
	{ "play-file",	    1, 0, OPT_PLAY_FILE },
	{ "send-recv",      0, 0, OPT_SEND_RECV },
	{ "send-only",      0, 0, OPT_SEND_ONLY },
	{ "recv-only",      0, 0, OPT_RECV_ONLY },
	{ "send-width",     1, 0, OPT_SEND_WIDTH },
	{ "send-height",    1, 0, OPT_SEND_HEIGHT },
	{ "recv-pt",        1, 0, OPT_RECV_PT },
	{ "send-pt",        1, 0, OPT_SEND_PT },
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	{ "use-srtp",	    2, 0, OPT_USE_SRTP },
	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
#endif
	{ "help",	    0, 0, OPT_HELP },
	{ NULL, 0, 0, 0 },
    };

    int c;
    int option_index;


    pj_bzero(&remote_addr, sizeof(remote_addr));


    /* init PJLIB : */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Parse arguments */
    pj_optind = 0;
    while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
    {
	switch (c) {
	case OPT_CODEC:
	    codec_id = pj_optarg;
	    break;

	case OPT_LOCAL_PORT:
	    local_port = (pj_uint16_t) atoi(pj_optarg);
	    if (local_port < 1) {
		printf("Error: invalid local port %s\n", pj_optarg);
		return 1;
	    }
	    break;

	case OPT_REMOTE:
	    {
		pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
		pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));

		status = pj_sockaddr_in_init(&remote_addr, &ip, port);
		if (status != PJ_SUCCESS) {
		    app_perror(THIS_FILE, "Invalid remote address", status);
		    return 1;
		}
	    }
	    break;

	case OPT_PLAY_FILE:
	    play_file.file_name = pj_optarg;
	    break;

	case OPT_SEND_RECV:
	    dir = PJMEDIA_DIR_ENCODING_DECODING;
	    break;

	case OPT_SEND_ONLY:
	    dir = PJMEDIA_DIR_ENCODING;
	    break;

	case OPT_RECV_ONLY:
	    dir = PJMEDIA_DIR_DECODING;
	    break;

	case OPT_SEND_WIDTH:
	    tx_size.w = (unsigned)atoi(pj_optarg);
	    break;

	case OPT_SEND_HEIGHT:
	    tx_size.h = (unsigned)atoi(pj_optarg);
	    break;

	case OPT_RECV_PT:
	    rx_pt = (pj_int8_t)atoi(pj_optarg);
	    break;

	case OPT_SEND_PT:
	    tx_pt = (pj_int8_t)atoi(pj_optarg);
	    break;

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
	case OPT_USE_SRTP:
	    use_srtp = PJ_TRUE;
	    if (pj_optarg) {
		pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
	    } else {
		srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
	    }
	    break;

	case OPT_SRTP_TX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, 
						     strlen(pj_optarg));
	    pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
	    break;

	case OPT_SRTP_RX_KEY:
	    tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
						     strlen(pj_optarg));
	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
	    break;
#endif

	case OPT_HELP:
	    usage();
	    return 1;

	default:
	    printf("Invalid options %s\n", argv[pj_optind]);
	    return 1;
	}

    }


    /* Verify arguments. */
    if (dir & PJMEDIA_DIR_ENCODING) {
	if (remote_addr.sin_addr.s_addr == 0) {
	    printf("Error: remote address must be set\n");
	    return 1;
	}
    }

    if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
	printf("Direction is set to --send-only because of --play-file\n");
	dir = PJMEDIA_DIR_ENCODING;
    }

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* SRTP validation */
    if (use_srtp) {
	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
	{
	    printf("Error: Key for each SRTP stream direction must be set\n");
	    return 1;
	}
    }
#endif

    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Create memory pool for application purpose */
    pool = pj_pool_create( &cp.factory,	    /* pool factory	    */
			   "app",	    /* pool name.	    */
			   4000,	    /* init size	    */
			   4000,	    /* increment size	    */
			   NULL		    /* callback on error    */
			   );

    /* Init video format manager */
    pjmedia_video_format_mgr_create(pool, 64, 0, NULL);

    /* Init video converter manager */
    pjmedia_converter_mgr_create(pool, NULL);

    /* Init event manager */
    pjmedia_event_mgr_create(pool, 0, NULL);

    /* Init video codec manager */
    pjmedia_vid_codec_mgr_create(pool, NULL);

    /* Init video subsystem */
    pjmedia_vid_dev_subsys_init(&cp.factory);

    /* Register all supported codecs */
    status = init_codecs(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Find which codec to use. */
    if (codec_id) {
	unsigned count = 1;
	pj_str_t str_codec_id = pj_str(codec_id);

        status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
						         &str_codec_id, &count,
						         &codec_info, NULL);
	if (status != PJ_SUCCESS) {
	    printf("Error: unable to find codec %s\n", codec_id);
	    return 1;
	}
    } else {
        static pjmedia_vid_codec_info info[1];
        unsigned count = PJ_ARRAY_SIZE(info);

	/* Default to first codec */
	pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
        codec_info = &info[0];
    }

    /* Get codec default param for info */
    status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info, 
				                     &codec_param);
    pj_assert(status == PJ_SUCCESS);
    
    /* Set outgoing video size */
    if (tx_size.w && tx_size.h)
        codec_param.enc_fmt.det.vid.size = tx_size;

#if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
    /* Set incoming video size */
    if (DEF_RENDERER_WIDTH > codec_param.dec_fmt.det.vid.size.w)
	codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
    if (DEF_RENDERER_HEIGHT > codec_param.dec_fmt.det.vid.size.h)
	codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
#endif

    if (play_file.file_name) {
	pjmedia_video_format_detail *file_vfd;
        pjmedia_clock_param clock_param;
        char fmt_name[5];

	/* Create file player */
	status = create_file_player(pool, play_file.file_name, &play_port);
	if (status != PJ_SUCCESS)
	    goto on_exit;

	/* Collect format info */
	file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
							  PJ_TRUE);
	PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %s @%.2ffps",
		   file_vfd->size.w, file_vfd->size.h,
		   pjmedia_fourcc_name(play_port->info.fmt.id, fmt_name),
		   (1.0*file_vfd->fps.num/file_vfd->fps.denum)));

	/* Allocate file read buffer */
	play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
	play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);

	/* Create decoder, if the file and the stream uses different codec */
	if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
	    const pjmedia_video_format_info *dec_vfi;
	    pjmedia_video_apply_fmt_param dec_vafp = {0};
	    const pjmedia_vid_codec_info *codec_info2;
	    pjmedia_vid_codec_param codec_param2;

	    /* Find decoder */
	    status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
							   play_port->info.fmt.id,
							   &codec_info2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Init decoder */
	    status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
						       &play_decoder);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    status = play_decoder->op->init(play_decoder, pool);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Open decoder */
	    status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
							     &codec_param2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    codec_param2.dir = PJMEDIA_DIR_DECODING;
	    status = play_decoder->op->open(play_decoder, &codec_param2);
	    if (status != PJ_SUCCESS)
		goto on_exit;

	    /* Get decoder format info and apply param */
	    dec_vfi = pjmedia_get_video_format_info(NULL,
						    codec_info2->dec_fmt_id[0]);
	    if (!dec_vfi || !dec_vfi->apply_fmt) {
		status = PJ_ENOTSUP;
		goto on_exit;
	    }
	    dec_vafp.size = file_vfd->size;
	    (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);

	    /* Allocate buffer to receive decoder output */
	    play_file.dec_buf_size = dec_vafp.framebytes;
	    play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
	}

	/* Create player clock */
        clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
        clock_param.clock_rate = codec_info->clock_rate;
	status = pjmedia_clock_create2(pool, &clock_param,
				       PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
				       &clock_cb, &play_file, &play_clock);
	if (status != PJ_SUCCESS)
	    goto on_exit;

	/* Override stream codec param for encoding direction */
	codec_param.enc_fmt.det.vid.size = file_vfd->size;
	codec_param.enc_fmt.det.vid.fps  = file_vfd->fps;

    } else {
        pjmedia_vid_port_param_default(&vpp);

        /* Set as active for all video devices */
        vpp.active = PJ_TRUE;

	/* Create video device port. */
        if (dir & PJMEDIA_DIR_ENCODING) {
            /* Create capture */
            status = pjmedia_vid_dev_default_param(
					pool,
					PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
					&vpp.vidparam);
            if (status != PJ_SUCCESS)
	        goto on_exit;

            pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
	    vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
            vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
            
            status = pjmedia_vid_port_create(pool, &vpp, &capture);
            if (status != PJ_SUCCESS)
	        goto on_exit;
        }
	
        if (dir & PJMEDIA_DIR_DECODING) {
            /* Create renderer */
            status = pjmedia_vid_dev_default_param(
					pool,
					PJMEDIA_VID_DEFAULT_RENDER_DEV,
					&vpp.vidparam);
            if (status != PJ_SUCCESS)
	        goto on_exit;

            pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
            vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
            vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
	    vpp.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
	    vpp.vidparam.window_flags = PJMEDIA_VID_DEV_WND_BORDER |
					PJMEDIA_VID_DEV_WND_RESIZABLE;

            status = pjmedia_vid_port_create(pool, &vpp, &renderer);
            if (status != PJ_SUCCESS)
	        goto on_exit;
        }
    }

    /* Set to ignore fmtp */
    codec_param.ignore_fmtp = PJ_TRUE;

    /* Create stream based on program arguments */
    status = create_stream(pool, med_endpt, codec_info, &codec_param,
                           dir, rx_pt, tx_pt, local_port, &remote_addr, 
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
			   use_srtp, &srtp_crypto_suite, 
			   &srtp_tx_key, &srtp_rx_key,
#endif
			   &stream);
    if (status != PJ_SUCCESS)
	goto on_exit;

    /* Get the port interface of the stream */
    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
				         &enc_port);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
				         &dec_port);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Start streaming */
    status = pjmedia_vid_stream_start(stream);
    if (status != PJ_SUCCESS)
        goto on_exit;

    /* Start renderer */
    if (renderer) {
        status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS)
            goto on_exit;
    }

    /* Start capture */
    if (capture) {
        status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(capture);
        if (status != PJ_SUCCESS)
            goto on_exit;
    }

    /* Start playing file */
    if (play_file.file_name) {

#if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
        /* Create local renderer */
        pjmedia_vid_port_param_default(&vpp);
        vpp.active = PJ_FALSE;
        status = pjmedia_vid_dev_default_param(
				pool,
				PJMEDIA_VID_DEFAULT_RENDER_DEV,
				&vpp.vidparam);
        if (status != PJ_SUCCESS)
	    goto on_exit;

        vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
        pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
	vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
	vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
        vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;

	status = pjmedia_vid_port_create(pool, &vpp, &renderer);
        if (status != PJ_SUCCESS)
	    goto on_exit;
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS)
            goto on_exit;
#endif

	/* Init play file data */
	play_file.play_port = play_port;
	play_file.stream_port = enc_port;
	play_file.decoder = play_decoder;
	if (renderer) {
	    play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
	}

	status = pjmedia_clock_start(play_clock);
	if (status != PJ_SUCCESS)
	    goto on_exit;
    }

    /* Done */

    if (dir == PJMEDIA_DIR_DECODING)
	printf("Stream is active, dir is recv-only, local port is %d\n",
	       local_port);
    else if (dir == PJMEDIA_DIR_ENCODING)
	printf("Stream is active, dir is send-only, sending to %s:%d\n",
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));
    else
	printf("Stream is active, send/recv, local port is %d, "
	       "sending to %s:%d\n",
	       local_port,
	       pj_inet_ntoa(remote_addr.sin_addr),
	       pj_ntohs(remote_addr.sin_port));

    if (dir & PJMEDIA_DIR_ENCODING)
	PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
		   codec_param.enc_fmt.det.vid.size.w,
		   codec_param.enc_fmt.det.vid.size.h,
		   codec_info->encoding_name.slen,
		   codec_info->encoding_name.ptr,
		   (1.0*codec_param.enc_fmt.det.vid.fps.num/
		    codec_param.enc_fmt.det.vid.fps.denum)));

    for (;;) {
	char tmp[10];

	puts("");
	puts("Commands:");
	puts("  q     Quit");
	puts("");

	printf("Command: "); fflush(stdout);

	if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
	    puts("EOF while reading stdin, will quit now..");
	    break;
	}

	if (tmp[0] == 'q')
	    break;

    }



    /* Start deinitialization: */
on_exit:

    /* Stop and destroy file clock */
    if (play_clock) {
	pjmedia_clock_stop(play_clock);
	pjmedia_clock_destroy(play_clock);
    }

    /* Destroy file reader/player */
    if (play_port)
	pjmedia_port_destroy(play_port);

    /* Destroy file decoder */
    if (play_decoder) {
	play_decoder->op->close(play_decoder);
	pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
    }

    /* Destroy video devices */
    if (capture)
	pjmedia_vid_port_destroy(capture);
    if (renderer)
	pjmedia_vid_port_destroy(renderer);

    /* Destroy stream */
    if (stream) {
	pjmedia_transport *tp;

	tp = pjmedia_vid_stream_get_transport(stream);
	pjmedia_vid_stream_destroy(stream);
	
	pjmedia_transport_close(tp);
    }

    /* Deinit codecs */
    deinit_codecs();

    /* Shutdown video subsystem */
    pjmedia_vid_dev_subsys_shutdown();

    /* Destroy event manager */
    pjmedia_event_mgr_destroy(NULL);

    /* Release application pool */
    pj_pool_release( pool );

    /* Destroy media endpoint. */
    pjmedia_endpt_destroy( med_endpt );

    /* Destroy pool factory */
    pj_caching_pool_destroy( &cp );

    /* Shutdown PJLIB */
    pj_shutdown();

    return (status == PJ_SUCCESS) ? 0 : 1;
}
/* API: create stream */
static pj_status_t vid4lin_factory_create_stream(pjmedia_vid_dev_factory *f,
				      pjmedia_vid_dev_param *param,
				      const pjmedia_vid_dev_cb *cb,
				      void *user_data,
				      pjmedia_vid_dev_stream **p_vid_strm)
{
    vid4lin_factory *cf = (vid4lin_factory*)f;
    pj_pool_t *pool;
    vid4lin_stream *stream;
    vid4lin_dev_info *vdi;
    const vid4lin_fmt_map *fmt_map;
    const pjmedia_video_format_info *fmt_info;
    pjmedia_video_format_detail *vfd;
    pj_status_t status = PJ_SUCCESS;


    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
    PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
		     param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
                     param->dir == PJMEDIA_DIR_CAPTURE,
		     PJ_EINVAL);
    PJ_ASSERT_RETURN(param->cap_id >= 0 && param->cap_id < cf->dev_count,
		     PJMEDIA_EVID_INVDEV);

    fmt_info = pjmedia_get_video_format_info(NULL, param->fmt.id);
    if (!fmt_info || (fmt_map=get_v4l2_format_info(param->fmt.id))==NULL)
        return PJMEDIA_EVID_BADFORMAT;

    vdi = &cf->dev_info[param->cap_id];
    vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);

    /* Create and Initialize stream descriptor */
    pool = pj_pool_create(cf->pf, vdi->info.name, 512, 512, NULL);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    stream = PJ_POOL_ZALLOC_T(pool, vid4lin_stream);
    pj_memcpy(&stream->param, param, sizeof(*param));
    stream->pool = pool;
    pj_memcpy(&stream->vid_cb, cb, sizeof(*cb));
    strncpy(stream->name, vdi->info.name, sizeof(stream->name));
    stream->name[sizeof(stream->name)-1] = '\0';
    stream->user_data = user_data;
    stream->fd = INVALID_FD;

    stream->fd = v4l2_open(vdi->dev_name, O_RDWR, 0);
    if (stream->fd < 0)
	goto on_error;

    status = vid4lin_stream_init_fmt(stream, param, fmt_map->v4l2_fmt_id);
    if (status != PJ_SUCCESS)
	goto on_error;

    if (vdi->v4l2_cap.capabilities & V4L2_CAP_STREAMING)
	status = vid4lin_stream_init_streaming(stream);

    if (status!=PJ_SUCCESS && vdi->v4l2_cap.capabilities & V4L2_CAP_STREAMING)
	status = vid4lin_stream_init_streaming_user(stream);

    if (status!=PJ_SUCCESS && vdi->v4l2_cap.capabilities & V4L2_CAP_READWRITE)
	status = vid4lin_stream_init_read_write(stream);

    if (status != PJ_SUCCESS) {
	PJ_LOG(1,(THIS_FILE, "Error: unable to initiate I/O on %s",
		  stream->name));
	goto on_error;
    }

    /* Done */
    stream->base.op = &stream_op;
    *p_vid_strm = &stream->base;

    return PJ_SUCCESS;

on_error:
    if (status == PJ_SUCCESS)
	status = PJ_RETURN_OS_ERROR(errno);

    vid4lin_stream_destroy(&stream->base);
    return status;
}
Пример #15
0
/* API: set capability */
static pj_status_t andgl_stream_set_cap(pjmedia_vid_dev_stream *s,
                                        pjmedia_vid_dev_cap cap,
                                        const void *pval)
{
    struct andgl_stream *strm = (struct andgl_stream*)s;
    
    PJ_UNUSED_ARG(strm);
    
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
    
    if (cap==PJMEDIA_VID_DEV_CAP_FORMAT) {
        const pjmedia_video_format_info *vfi;
        pjmedia_video_format_detail *vfd;
        pjmedia_format *fmt = (pjmedia_format *)pval;
        andgl_fmt_info *ifi;
        
        if (!(ifi = get_andgl_format_info(fmt->id)))
            return PJMEDIA_EVID_BADFORMAT;
        
        vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
                                            fmt->id);
        if (!vfi)
            return PJMEDIA_EVID_BADFORMAT;
        
        pjmedia_format_copy(&strm->param.fmt, fmt);
        
        vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
        pj_memcpy(&strm->vid_size, &vfd->size, sizeof(vfd->size));
        if (strm->param.disp_size.w == 0 || strm->param.disp_size.h == 0)
            pj_memcpy(&strm->param.disp_size, &vfd->size, sizeof(vfd->size));
        
	return PJ_SUCCESS;
    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
        pj_bool_t is_running = strm->is_running;
        pj_status_t status = PJ_SUCCESS;
        pjmedia_vid_dev_hwnd *wnd = (pjmedia_vid_dev_hwnd *)pval;
        ANativeWindow *native_wnd = (ANativeWindow *)wnd->info.android.window;

        if (strm->window == native_wnd)
            return PJ_SUCCESS;
        
        /* Stop the stream and re-init OpenGL */
    	andgl_stream_stop(s);
        job_queue_post_job(strm->jq, deinit_opengl, strm, 0, NULL);

        strm->window = strm->param.window.info.android.window = native_wnd;
        if (strm->window) {
            job_queue_post_job(strm->jq, init_opengl, strm, 0, &status);
        }

        PJ_LOG(3, (THIS_FILE, "Re-initializing OpenGL with window %p: %s",
        		      strm->window,
                              (status == PJ_SUCCESS? "success": "failed")));
        
        if (is_running)
	    andgl_stream_start(s);

        return status;
    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) {
        pj_memcpy(&strm->param.disp_size, pval, sizeof(strm->param.disp_size));
        return PJ_SUCCESS;
    } else if (cap == PJMEDIA_VID_DEV_CAP_ORIENTATION) {
        pj_memcpy(&strm->param.orient, pval, sizeof(strm->param.orient));
        if (strm->param.orient == PJMEDIA_ORIENT_UNKNOWN)
            return PJ_SUCCESS;
        return PJ_SUCCESS;
    }
    
    return PJMEDIA_EVID_INVCAP;
}
Пример #16
0
PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
					     const pjmedia_vid_port_param *prm,
					     pjmedia_vid_port **p_vid_port)
{
    pjmedia_vid_port *vp;
    const pjmedia_video_format_detail *vfd;
    char dev_name[64];
    char fmt_name[5];
    pjmedia_vid_dev_cb vid_cb;
    pj_bool_t need_frame_buf = PJ_FALSE;
    pj_status_t status;
    unsigned ptime_usec;
    pjmedia_vid_dev_param vparam;
    pjmedia_vid_dev_info di;
    unsigned i;

    PJ_ASSERT_RETURN(pool && prm && p_vid_port, PJ_EINVAL);
    PJ_ASSERT_RETURN(prm->vidparam.fmt.type == PJMEDIA_TYPE_VIDEO &&
                     prm->vidparam.dir != PJMEDIA_DIR_NONE &&
                     prm->vidparam.dir != PJMEDIA_DIR_CAPTURE_RENDER,
		     PJ_EINVAL);

    /* Retrieve the video format detail */
    vfd = pjmedia_format_get_video_format_detail(&prm->vidparam.fmt, PJ_TRUE);
    if (!vfd)
	return PJ_EINVAL;

    PJ_ASSERT_RETURN(vfd->fps.num, PJ_EINVAL);

    /* Allocate videoport */
    vp = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_port);
    vp->pool = pj_pool_create(pool->factory, "video port", 500, 500, NULL);
    vp->role = prm->active ? ROLE_ACTIVE : ROLE_PASSIVE;
    vp->dir = prm->vidparam.dir;
//    vp->cap_size = vfd->size;

    vparam = prm->vidparam;
    dev_name[0] = '\0';

    /* Get device info */
    if (vp->dir & PJMEDIA_DIR_CAPTURE)
        status = pjmedia_vid_dev_get_info(prm->vidparam.cap_id, &di);
    else
        status = pjmedia_vid_dev_get_info(prm->vidparam.rend_id, &di);
    if (status != PJ_SUCCESS)
        return status;

    pj_ansi_snprintf(dev_name, sizeof(dev_name), "%s [%s]",
                     di.name, di.driver);

    for (i = 0; i < di.fmt_cnt; ++i) {
        if (prm->vidparam.fmt.id == di.fmt[i].id)
            break;
    }

    if (i == di.fmt_cnt) {
        /* The device has no no matching format. Pick one from
         * the supported formats, and later use converter to
         * convert it to the required format.
         */
        pj_assert(di.fmt_cnt != 0);
        vparam.fmt.id = di.fmt[0].id;
    }

    pj_strdup2_with_null(pool, &vp->dev_name, di.name);
    vp->stream_role = di.has_callback ? ROLE_ACTIVE : ROLE_PASSIVE;

    pjmedia_fourcc_name(vparam.fmt.id, fmt_name);

    PJ_LOG(4,(THIS_FILE,
	      "Opening device %s for %s: format=%s, size=%dx%d @%d:%d fps",
	      dev_name,
	      vid_dir_name(prm->vidparam.dir), fmt_name,
	      vfd->size.w, vfd->size.h,
	      vfd->fps.num, vfd->fps.denum));

    ptime_usec = PJMEDIA_PTIME(&vfd->fps);
    pjmedia_clock_src_init(&vp->clocksrc, PJMEDIA_TYPE_VIDEO,
                           prm->vidparam.clock_rate, ptime_usec);
    vp->sync_clocksrc.max_sync_ticks = 
        PJMEDIA_CLOCK_SYNC_MAX_RESYNC_DURATION *
        1000 / vp->clocksrc.ptime_usec;

    /* Create the video stream */
    pj_bzero(&vid_cb, sizeof(vid_cb));
    vid_cb.capture_cb = &vidstream_cap_cb;
    vid_cb.render_cb = &vidstream_render_cb;

    status = pjmedia_vid_dev_stream_create(&vparam, &vid_cb, vp,
				           &vp->strm);
    if (status != PJ_SUCCESS)
	goto on_error;

    PJ_LOG(4,(THIS_FILE,
	      "Device %s opened: format=%s, size=%dx%d @%d:%d fps",
	      dev_name, fmt_name,
	      vparam.fmt.det.vid.size.w, vparam.fmt.det.vid.size.h,
	      vparam.fmt.det.vid.fps.num, vparam.fmt.det.vid.fps.denum));

    /* Subscribe to device's events */
    pjmedia_event_subscribe(NULL, &vidstream_event_cb,
                            vp, vp->strm);

    if (vp->dir & PJMEDIA_DIR_CAPTURE) {
	pjmedia_format_copy(&vp->conv.conv_param.src, &vparam.fmt);
	pjmedia_format_copy(&vp->conv.conv_param.dst, &prm->vidparam.fmt);
    } else {
	pjmedia_format_copy(&vp->conv.conv_param.src, &prm->vidparam.fmt);
	pjmedia_format_copy(&vp->conv.conv_param.dst, &vparam.fmt);
    }

    status = create_converter(vp);
    if (status != PJ_SUCCESS)
	goto on_error;

    if (vp->role==ROLE_ACTIVE &&
        ((vp->dir & PJMEDIA_DIR_ENCODING) || vp->stream_role==ROLE_PASSIVE))
    {
        pjmedia_clock_param param;

	/* Active role is wanted, but our device is passive, so create
	 * master clocks to run the media flow. For encoding direction,
         * we also want to create our own clock since the device's clock
         * may run at a different rate.
	 */
	need_frame_buf = PJ_TRUE;
            
        param.usec_interval = PJMEDIA_PTIME(&vfd->fps);
        param.clock_rate = prm->vidparam.clock_rate;
        status = pjmedia_clock_create2(pool, &param,
                                       PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
                                       (vp->dir & PJMEDIA_DIR_ENCODING) ?
                                       &enc_clock_cb: &dec_clock_cb,
                                       vp, &vp->clock);
        if (status != PJ_SUCCESS)
            goto on_error;

    } else if (vp->role==ROLE_PASSIVE) {
	vid_pasv_port *pp;

	/* Always need to create media port for passive role */
	vp->pasv_port = pp = PJ_POOL_ZALLOC_T(pool, vid_pasv_port);
	pp->vp = vp;
	pp->base.get_frame = &vid_pasv_port_get_frame;
	pp->base.put_frame = &vid_pasv_port_put_frame;
	pjmedia_port_info_init2(&pp->base.info, &vp->dev_name,
	                        PJMEDIA_SIG_VID_PORT,
			        prm->vidparam.dir, &prm->vidparam.fmt);

        need_frame_buf = PJ_TRUE;
    }

    if (need_frame_buf) {
	const pjmedia_video_format_info *vfi;
	pjmedia_video_apply_fmt_param vafp;

	vfi = pjmedia_get_video_format_info(NULL, vparam.fmt.id);
	if (!vfi) {
	    status = PJ_ENOTFOUND;
	    goto on_error;
	}

	pj_bzero(&vafp, sizeof(vafp));
	vafp.size = vparam.fmt.det.vid.size;
	status = vfi->apply_fmt(vfi, &vafp);
	if (status != PJ_SUCCESS)
	    goto on_error;

        vp->frm_buf = PJ_POOL_ZALLOC_T(pool, pjmedia_frame);
        vp->frm_buf_size = vafp.framebytes;
        vp->frm_buf->buf = pj_pool_alloc(pool, vafp.framebytes);
        vp->frm_buf->size = vp->frm_buf_size;
        vp->frm_buf->type = PJMEDIA_FRAME_TYPE_NONE;

        status = pj_mutex_create_simple(pool, vp->dev_name.ptr,
                                        &vp->frm_mutex);
        if (status != PJ_SUCCESS)
            goto on_error;
    }

    *p_vid_port = vp;

    return PJ_SUCCESS;

on_error:
    pjmedia_vid_port_destroy(vp);
    return status;
}
Пример #17
0
static pj_status_t check_decode_result(pjmedia_vid_codec *codec,
				       const pj_timestamp *ts,
				       pj_bool_t got_keyframe)
{
    ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
    pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
    pjmedia_event event;

    /* Check for format change.
     * Decoder output format is set by libavcodec, in case it is different
     * to the configured param.
     */
    if (ff->dec_ctx->pix_fmt != ff->expected_dec_fmt ||
	ff->dec_ctx->width != (int)vafp->size.w ||
	ff->dec_ctx->height != (int)vafp->size.h)
    {
	pjmedia_format_id new_fmt_id;
	pj_status_t status;

	/* Get current raw format id from ffmpeg decoder context */
	status = PixelFormat_to_pjmedia_format_id(ff->dec_ctx->pix_fmt, 
						  &new_fmt_id);
	if (status != PJ_SUCCESS)
	    return status;

	/* Update decoder format in param */
		ff->param.dec_fmt.id = new_fmt_id;
	ff->param.dec_fmt.det.vid.size.w = ff->dec_ctx->width;
	ff->param.dec_fmt.det.vid.size.h = ff->dec_ctx->height;
	ff->expected_dec_fmt = ff->dec_ctx->pix_fmt;

	/* Re-init format info and apply-param of decoder */
	ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
	if (!ff->dec_vfi)
	    return PJ_ENOTSUP;
	pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
	ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
	ff->dec_vafp.buffer = NULL;
	status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
	if (status != PJ_SUCCESS)
	    return status;

	/* Realloc buffer if necessary */
	if (ff->dec_vafp.framebytes > ff->dec_buf_size) {
	    PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u",
		       (unsigned)ff->dec_buf_size,
		       (unsigned)ff->dec_vafp.framebytes));
	    ff->dec_buf_size = ff->dec_vafp.framebytes;
	    ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
	}

	/* Broadcast format changed event */
	pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
	event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
	pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param.dec_fmt,
		  sizeof(ff->param.dec_fmt));
	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    /* Check for missing/found keyframe */
    if (got_keyframe) {
	pj_get_timestamp(&ff->last_dec_keyframe_ts);

	/* Broadcast keyframe event */
        pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
        pjmedia_event_publish(NULL, codec, &event, 0);
    } else if (ff->last_dec_keyframe_ts.u64 == 0) {
	/* Broadcast missing keyframe event */
	pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, ts, codec);
	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    return PJ_SUCCESS;
}
Пример #18
0
static int aviplay(pj_pool_t *pool, const char *fname)
{
    pjmedia_vid_port *renderer=NULL;
    pjmedia_vid_port_param param;
    const pjmedia_video_format_info *vfi;
    pjmedia_video_format_detail *vfd;
    pjmedia_snd_port *snd_port = NULL;
    pj_status_t status;
    int rc = 0;
    pjmedia_avi_streams *avi_streams;
    pjmedia_avi_stream *vid_stream, *aud_stream;
    pjmedia_port *vid_port = NULL, *aud_port = NULL;
    pjmedia_vid_codec *codec=NULL;
    avi_port_t avi_port;

    pj_bzero(&avi_port, sizeof(avi_port));

    status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
    if (status != PJ_SUCCESS) {
        PJ_PERROR(2,("", status, "    Error playing %s", fname));
        rc = 210;
        goto on_return;
    }

    vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_VIDEO);
    vid_port = pjmedia_avi_stream_get_port(vid_stream);

    if (vid_port) {
        pjmedia_vid_port_param_default(&param);

        status = pjmedia_vid_dev_default_param(pool,
                                               PJMEDIA_VID_DEFAULT_RENDER_DEV,
                                               &param.vidparam);
        if (status != PJ_SUCCESS) {
            rc = 220;
            goto on_return;
        }

        /* Create renderer, set it to active  */
        param.active = PJ_TRUE;
        param.vidparam.dir = PJMEDIA_DIR_RENDER;
        vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
                PJ_TRUE);
        pjmedia_format_init_video(&param.vidparam.fmt,
                                  vid_port->info.fmt.id,
                                  vfd->size.w, vfd->size.h,
                                  vfd->fps.num, vfd->fps.denum);

        vfi = pjmedia_get_video_format_info(
                  pjmedia_video_format_mgr_instance(),
                  vid_port->info.fmt.id);
        /* Check whether the frame is encoded */
        if (!vfi || vfi->bpp == 0) {
            /* Yes, prepare codec */
            pj_str_t codec_id_st;
            unsigned info_cnt = 1, i, k;
            const pjmedia_vid_codec_info *codec_info;
            pj_str_t port_name = {"codec", 5};
            pj_uint8_t *enc_buf = NULL;
            pj_size_t enc_buf_size = 0;
            pjmedia_vid_dev_info rdr_info;
            pjmedia_port codec_port;
            codec_port_data_t codec_port_data;
            pjmedia_vid_codec_param codec_param;
            struct codec_fmt *codecp = NULL;

            /* Lookup codec */
            for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
                if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
                    codecp = &codec_fmts[i];
                    break;
                }
            }
            if (!codecp) {
                rc = 242;
                goto on_return;
            }
            pj_cstr(&codec_id_st, codecp->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;
            }

            pjmedia_format_copy(&codec_param.enc_fmt, &param.vidparam.fmt);

            pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
            for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
                for (k=0; k<rdr_info.fmt_cnt; ++k) {
                    if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
                    {
                        param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
                        i = codec_info->dec_fmt_id_cnt;
                        break;
                    }
                }
            }

            /* 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;
            }

            pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
            codec_param.dir = PJMEDIA_DIR_DECODING;
            codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
            status = pjmedia_vid_codec_open(codec, &codec_param);
            if (status != PJ_SUCCESS) {
                rc = 252;
                goto on_return;
            }

            /* Alloc encoding buffer */
            enc_buf_size =  codec_param.dec_fmt.det.vid.size.w *
                            codec_param.dec_fmt.det.vid.size.h * 4
                            + 16; /*< padding, just in case */
            enc_buf = pj_pool_alloc(pool,enc_buf_size);

            /* 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;
            }
            pj_bzero(&codec_port_data, sizeof(codec_port_data));
            codec_port_data.codec = codec;
            codec_port_data.src_port = vid_port;
            codec_port_data.enc_buf = enc_buf;
            codec_port_data.enc_buf_size = enc_buf_size;

            codec_port.get_frame = &codec_get_frame;
            codec_port.port_data.pdata = &codec_port_data;

            /* Check whether we need to convert the decoded frame */
            if (codecp->need_conversion) {
                pjmedia_conversion_param conv_param;

                pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
                pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
                conv_param.dst.id = codecp->dst_fmt;
                param.vidparam.fmt.id = conv_param.dst.id;

                status = pjmedia_converter_create(NULL, pool, &conv_param,
                                                  &codec_port_data.conv);
                if (status != PJ_SUCCESS) {
                    rc = 270;
                    goto on_return;
                }
            }

            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            status = pjmedia_vid_port_connect(renderer, &codec_port,
                                              PJ_FALSE);
        } else {
            status = pjmedia_vid_port_create(pool, &param, &renderer);
            if (status != PJ_SUCCESS) {
                rc = 230;
                goto on_return;
            }

            /* Connect avi port to renderer */
            status = pjmedia_vid_port_connect(renderer, vid_port,
                                              PJ_FALSE);
        }

        if (status != PJ_SUCCESS) {
            rc = 240;
            goto on_return;
        }
    }

    aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
                 0,
                 PJMEDIA_TYPE_AUDIO);
    aud_port = pjmedia_avi_stream_get_port(aud_stream);

    if (aud_port) {
        /* Create sound player port. */
        status = pjmedia_snd_port_create_player(
                     pool,				    /* pool		    */
                     -1,				    /* use default dev.	    */
                     PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate.	    */
                     PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels.	    */
                     PJMEDIA_PIA_SPF(&aud_port->info),  /* samples per frame.   */
                     PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample.	    */
                     0,				    /* options		    */
                     &snd_port			    /* returned port	    */
                 );
        if (status != PJ_SUCCESS) {
            rc = 310;
            goto on_return;
        }

        /* Connect file port to the sound player.
         * Stream playing will commence immediately.
         */
        status = pjmedia_snd_port_connect(snd_port, aud_port);
        if (status != PJ_SUCCESS) {
            rc = 330;
            goto on_return;
        }
    }

    if (vid_port) {
        pjmedia_vid_dev_cb cb;

        pj_bzero(&cb, sizeof(cb));
        avi_port.snd_port = snd_port;
        avi_port.vid_port = renderer;
        avi_port.is_running = PJ_TRUE;
        pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);

        /* subscribe events */
        pjmedia_event_subscribe(NULL, &avi_event_cb, &avi_port,
                                renderer);

        if (snd_port) {
            /* Synchronize video rendering and audio playback */
            pjmedia_vid_port_set_clock_src(
                renderer,
                pjmedia_snd_port_get_clock_src(
                    snd_port, PJMEDIA_DIR_PLAYBACK));
        }


        /* Start video streaming.. */
        status = pjmedia_vid_port_start(renderer);
        if (status != PJ_SUCCESS) {
            rc = 270;
            goto on_return;
        }
    }

    while (!avi_port.is_quitting) {
        pj_thread_sleep(100);
    }

on_return:
    if (snd_port) {
        pjmedia_snd_port_disconnect(snd_port);
        /* Without this sleep, Windows/DirectSound will repeteadly
         * play the last frame during destroy.
         */
        pj_thread_sleep(100);
        pjmedia_snd_port_destroy(snd_port);
    }
    if (renderer) {
        pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port,
                                  renderer);
        pjmedia_vid_port_destroy(renderer);
    }
    if (aud_port)
        pjmedia_port_destroy(aud_port);
    if (vid_port)
        pjmedia_port_destroy(vid_port);
    if (codec) {
        pjmedia_vid_codec_close(codec);
        pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
    }

    return rc;
}
Пример #19
0
/*
 * Open codec.
 */
static pj_status_t openh264_codec_open( pjmedia_vid_codec *codec, 
				      pjmedia_vid_codec_param *attr )
{
    openh264_private *ff;
    pj_status_t status;
    pj_mutex_t *ff_mutex;
	pjmedia_rect_size enc_rect = { 176, 144 };	

    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
    ff = (openh264_private*)codec->codec_data;

    pj_memcpy(&ff->param, attr, sizeof(*attr));

	if (ff->param.dir == PJMEDIA_DIR_ENCODING)
	{
		ff->enc_expected_size = enc_rect;
		ff->enc_expected_bitrate = 160 * 1000;
		ff->enc_frame_count = 0;
	}

    /* Normalize encoding MTU in codec param */
    if (attr->enc_mtu > PJMEDIA_MAX_VID_PAYLOAD_SIZE)
		attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;

    /* Open the codec */
    ff_mutex = ((struct openh264_factory*)codec->factory)->mutex;
    status = open_openh264_codec(ff, ff_mutex);
    if (status != PJ_SUCCESS)
        goto on_error;

    /* Init format info and apply-param of decoder */
    ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
    if (!ff->dec_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
    ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
    ff->dec_vafp.buffer = NULL;
    status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Init format info and apply-param of encoder */
    ff->enc_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
    if (!ff->enc_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&ff->enc_vafp, sizeof(ff->enc_vafp));
    ff->enc_vafp.size = ff->param.enc_fmt.det.vid.size;
    ff->enc_vafp.buffer = NULL;
    status = (*ff->enc_vfi->apply_fmt)(ff->enc_vfi, &ff->enc_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Alloc buffers if needed */
    ff->whole = (ff->param.packing == PJMEDIA_VID_PACKING_WHOLE);
    if (!ff->whole) {
		ff->enc_buf_size = ff->enc_vafp.framebytes;
		ff->enc_buf = pj_pool_alloc(ff->pool, ff->enc_buf_size);

		ff->dec_buf_size = ff->dec_vafp.framebytes;
		ff->unaligned_dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
		ff->dec_buf = align_buffer_16(ff->unaligned_dec_buf);
    }

    /* Update codec attributes, e.g: encoding format may be changed by
     * SDP fmtp negotiation.
     */
    pj_memcpy(attr, &ff->param, sizeof(*attr));
    return PJ_SUCCESS;

on_error:
    openh264_codec_close(codec);
    return status;
}
Пример #20
0
static pj_status_t check_new_decode_result(pjmedia_vid_codec *codec,
				       SBufferInfo *bufferInfo,
					   const pj_timestamp *ts,
				       pj_bool_t got_keyframe)
{
    openh264_private *ff = (openh264_private*)codec->codec_data;
    pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
    pjmedia_event event;

    /* Check for format change.
     * Decoder output format is set by libavcodec, in case it is different
     * to the configured param.
     */
    if (bufferInfo->UsrData.sSystemBuffer.iWidth != (int)vafp->size.w ||
		bufferInfo->UsrData.sSystemBuffer.iHeight != (int)vafp->size.h)
	{
		pj_status_t status;

		/* Update decoder format in param */
		ff->param.dec_fmt.id = PJMEDIA_FORMAT_I420;
		ff->param.dec_fmt.det.vid.size.w = bufferInfo->UsrData.sSystemBuffer.iWidth;
		ff->param.dec_fmt.det.vid.size.h = bufferInfo->UsrData.sSystemBuffer.iHeight;

		/* Re-init format info and apply-param of decoder */
		ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
		if (!ff->dec_vfi)
			return PJ_ENOTSUP;
		pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
		ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
		ff->dec_vafp.buffer = NULL;
		status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
		if (status != PJ_SUCCESS)
			return status;

		/* Realloc buffer if necessary */
		if (ff->dec_vafp.framebytes > ff->dec_buf_size) {
			PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u",
				   (unsigned)ff->dec_buf_size,
				   (unsigned)ff->dec_vafp.framebytes));
			ff->dec_buf_size = ff->dec_vafp.framebytes;
			ff->unaligned_dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
			ff->dec_buf = align_buffer_16(ff->unaligned_dec_buf);
		}

		/* Broadcast format changed event */
		pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
		event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
		pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param.dec_fmt,
			  sizeof(ff->param.dec_fmt));
		pjmedia_event_publish(NULL, codec, &event, 0);
    }

    /* Check for missing/found keyframe */
    if (got_keyframe) {
		pj_get_timestamp(&ff->last_dec_keyframe_ts);

	/* Broadcast keyframe event */
        pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
        pjmedia_event_publish(NULL, codec, &event, 0);
    } else if (ff->last_dec_keyframe_ts.u64 == 0) {
	/* Broadcast missing keyframe event */
// 	pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, ts, codec);
// 	pjmedia_event_publish(NULL, codec, &event, 0);
    }

    return PJ_SUCCESS;
}
Пример #21
0
/* API: set capability */
static pj_status_t andgl_stream_set_cap(pjmedia_vid_dev_stream *s,
                                        pjmedia_vid_dev_cap cap,
                                        const void *pval)
{
    struct andgl_stream *strm = (struct andgl_stream*)s;
    
    PJ_UNUSED_ARG(strm);
    
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
    
    if (cap==PJMEDIA_VID_DEV_CAP_FORMAT) {
        const pjmedia_video_format_info *vfi;
        pjmedia_video_format_detail *vfd;
        pjmedia_format *fmt = (pjmedia_format *)pval;
        andgl_fmt_info *ifi;
        
        if (!(ifi = get_andgl_format_info(fmt->id)))
            return PJMEDIA_EVID_BADFORMAT;
        
        vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
                                            fmt->id);
        if (!vfi)
            return PJMEDIA_EVID_BADFORMAT;
        
        /* Re-init OpenGL */
        if (strm->window)
            job_queue_post_job(strm->jq, deinit_opengl, strm, 0, NULL);

        pjmedia_format_copy(&strm->param.fmt, fmt);

        vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
        pj_memcpy(&strm->vid_size, &vfd->size, sizeof(vfd->size));
        pj_memcpy(&strm->param.disp_size, &vfd->size, sizeof(vfd->size));
        
	if (strm->window)
	    job_queue_post_job(strm->jq, init_opengl, strm, 0, NULL);
	    
	PJ_LOG(4, (THIS_FILE, "Re-initializing OpenGL due to format change"));
        
	return PJ_SUCCESS;
    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
        pj_status_t status = PJ_SUCCESS;
        pjmedia_vid_dev_hwnd *wnd = (pjmedia_vid_dev_hwnd *)pval;
        ANativeWindow *native_wnd = (ANativeWindow *)wnd->info.android.window;

        if (strm->window == native_wnd)
            return PJ_SUCCESS;
        
        /* Re-init OpenGL */
        job_queue_post_job(strm->jq, deinit_opengl, strm, 0, NULL);
        if (strm->window)
            ANativeWindow_release(strm->window);

        strm->window = strm->param.window.info.android.window = native_wnd;
        if (strm->window) {
            job_queue_post_job(strm->jq, init_opengl, strm, 0, &status);
        }

        PJ_LOG(4, (THIS_FILE, "Re-initializing OpenGL with native window"
        		      " %p: %s", strm->window,
                              (status == PJ_SUCCESS? "success": "failed")));
        
        return status;
    }
    
    return PJMEDIA_EVID_INVCAP;
}
Пример #22
0
pj_status_t
pjmedia_vid_dev_conv_create_converter(pjmedia_vid_dev_conv *conv,
				      pj_pool_t *pool,
				      pjmedia_format *fmt,
				      pjmedia_rect_size src_size,
				      pjmedia_rect_size dst_size,
				      pj_bool_t handle_rotation,
				      pj_bool_t maintain_aspect_ratio)
{
    pj_status_t status;
    pjmedia_conversion_param conv_param;
    const pjmedia_video_format_info *vfi;	

    pj_assert((src_size.w == dst_size.w || src_size.h == dst_size.h) ||
              (src_size.w == dst_size.h || src_size.h == dst_size.w));
              
    if (conv->conv)
        return PJ_SUCCESS;
        
    if (fmt->id != PJMEDIA_FORMAT_I420 && fmt->id != PJMEDIA_FORMAT_BGRA)
        return PJ_EINVAL;
        
    /* Currently, for BGRA format, device must handle the rotation. */
    if (fmt->id == PJMEDIA_FORMAT_BGRA && handle_rotation)
        return PJ_ENOTSUP;

    if (handle_rotation) {
#if !HAS_ROTATION
	return PJ_ENOTSUP;
#endif
    }
    
    conv->src_size = src_size;
    conv->dst_size = dst_size;
    conv->handle_rotation = handle_rotation;
    pjmedia_format_copy(&conv->fmt, fmt);
    pjmedia_format_copy(&conv_param.src, fmt);
    pjmedia_format_copy(&conv_param.dst, fmt);

    /* If we do the rotation, the conversion's source size must be the same
     * as the device's original size. Otherwise, frames that require conversion
     * are the ones of which orientation differ by 90 or 270 degrees from the
     * destination size.
     */
    if (handle_rotation) {
        conv_param.src.det.vid.size = src_size;
    } else {
        conv_param.src.det.vid.size.w = dst_size.h;
        conv_param.src.det.vid.size.h = dst_size.w;
    }

    /* Maintaining aspect ratio requires filling the left&right /
     * top&bottom area with black color.
     * Currently it is only supported for I420.
     * TODO: support BGRA as well
     */
    if (fmt->id != PJMEDIA_FORMAT_I420)
        maintain_aspect_ratio = PJ_FALSE;

    /* Calculate the size after rotation.
     * If aspect ratio doesn't need to be maintained, rot_size is simply equal
     * to the destination size. Otherwise, we need to fit the rotated frame
     * to height or to width.
     */
    conv->maintain_aspect_ratio = maintain_aspect_ratio;
    if (maintain_aspect_ratio) {
        conv->fit_to_h = (dst_size.w >= dst_size.h? PJ_TRUE: PJ_FALSE);
	if (conv->fit_to_h) {	/* Fit to height */
	    conv->rot_size.h = dst_size.h;
	    conv->rot_size.w = dst_size.h * dst_size.h / dst_size.w;
	    /* Make sure the width difference is divisible by four
	     * so we can have equal padding left and right.
	     */
	    conv->rot_size.w += (dst_size.w - conv->rot_size.w) % 4;
	    conv->pad = (conv->dst_size.w - conv->rot_size.w) / 2;
	} else { 			/* Fit to width */
	    conv->rot_size.w = dst_size.w;
	    conv->rot_size.h = dst_size.w * dst_size.w / dst_size.h;
	    conv->rot_size.h += (dst_size.h - conv->rot_size.h) % 4;
	    conv->pad = (conv->dst_size.h - conv->rot_size.h) / 2;
	}
    } else {
        conv->rot_size = dst_size;
    }
    
    /* Calculate the size after resizing. */
    if (handle_rotation) {
        /* If we do the rotation, conversion is done before rotation. */
        if (maintain_aspect_ratio) {
            /* Since aspect ratio is maintained, the long side after
             * conversion must be the same as before conversion.
             * For example: 352x288 will be converted to 288x236
             */
            pj_size_t long_s  = (conv->rot_size.h > conv->rot_size.w?
            			 conv->rot_size.h: conv->rot_size.w);
            pj_size_t short_s = (conv->rot_size.h > conv->rot_size.w?
            			 conv->rot_size.w: conv->rot_size.h);
            if (src_size.w > src_size.h) {
                conv->res_size.w = long_s;
                conv->res_size.h = short_s;
             } else {
                conv->res_size.w = short_s;
                conv->res_size.h = long_s;
             }
        } else {
            /* We don't need to maintain aspect ratio,
             * so just swap the width and height.
             * For example: 352x288 will be resized to 288x352
             */
            conv->res_size.w = src_size.h;
            conv->res_size.h = src_size.w;
        }
        conv_param.dst.det.vid.size = conv->res_size;
    } else {
        conv->res_size = conv->rot_size;
    	conv_param.dst.det.vid.size = conv->rot_size;
    }

    status = pjmedia_converter_create(NULL, pool, &conv_param,
				      &conv->conv);
    if (status != PJ_SUCCESS) {
	PJ_LOG(3, (THIS_FILE, "Error creating converter"));
	return status;
    }

    vfi = pjmedia_get_video_format_info(NULL, fmt->id);
    pj_assert(vfi);
    
    conv->wxh = conv->dst_size.w * conv->dst_size.h;
    conv->src_frame_size = dst_size.w * dst_size.h * vfi->bpp / 8;
    conv->conv_frame_size = conv->rot_size.w * conv->rot_size.h;
    conv->conv_frame_size *= vfi->bpp / 8;
    conv->conv_buf = pj_pool_alloc(pool, conv->src_frame_size);
    
    pjmedia_vid_dev_conv_set_rotation(conv, PJMEDIA_ORIENT_NATURAL);

    PJ_LOG(4, (THIS_FILE, "Orientation converter created: %dx%d to %dx%d, "
    			  "maintain aspect ratio=%s",
			  conv_param.src.det.vid.size.w,
			  conv_param.src.det.vid.size.h,
			  conv_param.dst.det.vid.size.w,
			  conv_param.dst.det.vid.size.h,
			  maintain_aspect_ratio? "yes": "no"));
			  
    return PJ_SUCCESS;
}
Пример #23
0
/*
 * Open codec.
 */
static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec, 
				      pjmedia_vid_codec_param *attr )
{
    ffmpeg_private *ff;
    pj_status_t status;
    pj_mutex_t *ff_mutex;

    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
    ff = (ffmpeg_private*)codec->codec_data;

    pj_memcpy(&ff->param, attr, sizeof(*attr));

    /* Open the codec */
    ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;
    status = open_ffmpeg_codec(ff, ff_mutex);
    if (status != PJ_SUCCESS)
        goto on_error;

    /* Init format info and apply-param of decoder */
    ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
    if (!ff->dec_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
    ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
    ff->dec_vafp.buffer = NULL;
    status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Init format info and apply-param of encoder */
    ff->enc_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
    if (!ff->enc_vfi) {
        status = PJ_EINVAL;
        goto on_error;
    }
    pj_bzero(&ff->enc_vafp, sizeof(ff->enc_vafp));
    ff->enc_vafp.size = ff->param.enc_fmt.det.vid.size;
    ff->enc_vafp.buffer = NULL;
    status = (*ff->enc_vfi->apply_fmt)(ff->enc_vfi, &ff->enc_vafp);
    if (status != PJ_SUCCESS) {
        goto on_error;
    }

    /* Alloc buffers if needed */
    ff->whole = (ff->param.packing == PJMEDIA_VID_PACKING_WHOLE);
    if (!ff->whole) {
	ff->enc_buf_size = ff->enc_vafp.framebytes;
	ff->enc_buf = pj_pool_alloc(ff->pool, ff->enc_buf_size);

	ff->dec_buf_size = ff->dec_vafp.framebytes;
	ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
    }

    /* Update codec attributes, e.g: encoding format may be changed by
     * SDP fmtp negotiation.
     */
    pj_memcpy(attr, &ff->param, sizeof(*attr));

    return PJ_SUCCESS;

on_error:
    ffmpeg_codec_close(codec);
    return status;
}