From dbaa384af07319b4f7bffe6909e3d470a0e0b672 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Thu, 30 Jul 2015 06:23:35 +0000 Subject: Fixed #1861: Add support for video capture orientation on Android git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5138 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia-videodev/android_dev.c | 98 +++++++++++++++++++++++++++--- pjmedia/src/pjmedia-videodev/ios_dev.m | 4 +- pjmedia/src/pjmedia-videodev/util.c | 6 +- 3 files changed, 96 insertions(+), 12 deletions(-) (limited to 'pjmedia') diff --git a/pjmedia/src/pjmedia-videodev/android_dev.c b/pjmedia/src/pjmedia-videodev/android_dev.c index 4878b072..dca0d338 100644 --- a/pjmedia/src/pjmedia-videodev/android_dev.c +++ b/pjmedia/src/pjmedia-videodev/android_dev.c @@ -16,6 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "util.h" #include #include #include @@ -38,6 +39,10 @@ #define DEFAULT_FPS 15 #define ALIGN16(x) ((((x)+15) >> 4) << 4) +/* Define whether we should maintain the aspect ratio when rotating the image. + * For more details, please refer to util.h. + */ +#define MAINTAIN_ASPECT_RATIO PJ_TRUE /* Format map info */ typedef struct and_fmt_map @@ -118,6 +123,10 @@ typedef struct and_stream /** NV21/YV12 -> I420 Conversion buffer */ pj_uint8_t *convert_buf; + pjmedia_rect_size cam_size; + + /** Converter to rotate frame */ + pjmedia_vid_dev_conv conv; /** Frame format param for NV21/YV12 -> I420 conversion */ pjmedia_video_apply_fmt_param @@ -511,7 +520,8 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) vdi->id = f->dev_count; vdi->dir = PJMEDIA_DIR_CAPTURE; vdi->has_callback = PJ_TRUE; - vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH; + vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH | + PJMEDIA_VID_DEV_CAP_ORIENTATION; /* Set driver & name info */ pj_ansi_strncpy(vdi->driver, "Android", sizeof(vdi->driver)); @@ -578,13 +588,20 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) else if (fmt == PJMEDIA_FORMAT_NV21) adi->has_nv21 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && - vdi->fmt_cnt < max_fmt_cnt; k++) + vdi->fmt_cnt < max_fmt_cnt-1; k++) { + /* Landscape video */ pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], fmt, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); + /* Portrait video */ + pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], + fmt, + adi->sup_size[k].h, + adi->sup_size[k].w, + DEFAULT_FPS, 1); } } (*jni_env)->ReleaseIntArrayElements(jni_env, jiarray, fmts, @@ -598,13 +615,18 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) int k; adi->forced_i420 = PJ_TRUE; for (k = 0; k < adi->sup_size_cnt && - vdi->fmt_cnt < max_fmt_cnt; k++) + vdi->fmt_cnt < max_fmt_cnt-1; k++) { pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], PJMEDIA_FORMAT_I420, adi->sup_size[k].w, adi->sup_size[k].h, DEFAULT_FPS, 1); + pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++], + PJMEDIA_FORMAT_I420, + adi->sup_size[k].h, + adi->sup_size[k].w, + DEFAULT_FPS, 1); } } } else { @@ -636,7 +658,7 @@ static pj_status_t and_factory_refresh(pjmedia_vid_dev_factory *ff) f->dev_count)); for (i = 0; i < f->dev_count; i++) { and_dev_info *adi = &f->dev_info[i]; - char tmp_str[1024], *p; + char tmp_str[2048], *p; int j, plen, slen; PJ_LOG(4, (THIS_FILE, "%2d: %s", i, f->dev_info[i].info.name)); @@ -792,10 +814,12 @@ static pj_status_t and_factory_create_stream( 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 */ - vfd->size.w, /* w */ - vfd->size.h, /* h */ + strm->cam_size.w, /* w */ + strm->cam_size.h, /* h */ and_fmt, /* fmt */ vfd->fps.num*1000/ vfd->fps.denum, /* fps */ @@ -814,6 +838,19 @@ static pj_status_t and_factory_create_stream( 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, + ¶m->orient); + } on_return: jni_detach_env(with_attach); @@ -921,6 +958,40 @@ static pj_status_t and_stream_set_cap(pjmedia_vid_dev_stream *s, break; } + case PJMEDIA_VID_DEV_CAP_ORIENTATION: + { + pjmedia_orient orient = *(pjmedia_orient *)pval; + + pj_assert(orient >= PJMEDIA_ORIENT_UNKNOWN && + orient <= PJMEDIA_ORIENT_ROTATE_270DEG); + + if (orient == PJMEDIA_ORIENT_UNKNOWN) + return PJ_EINVAL; + + pj_memcpy(&strm->param.orient, pval, + sizeof(strm->param.orient)); + + if (!strm->conv.conv) { + status = pjmedia_vid_dev_conv_create_converter( + &strm->conv, strm->pool, + &strm->param.fmt, + strm->cam_size, + strm->param.fmt.det.vid.size, + PJ_TRUE, + MAINTAIN_ASPECT_RATIO); + + if (status != PJ_SUCCESS) + return status; + } + + pjmedia_vid_dev_conv_set_rotation(&strm->conv, strm->param.orient); + + PJ_LOG(4, (THIS_FILE, "Video capture orientation set to %d", + strm->param.orient)); + + break; + } + default: status = PJMEDIA_EVID_INVCAP; break; @@ -1005,6 +1076,8 @@ static pj_status_t and_stream_destroy(pjmedia_vid_dev_stream *s) jni_detach_env(with_attach); + pjmedia_vid_dev_conv_destroy_converter(&strm->conv); + if (strm->pool) pj_pool_release(strm->pool); @@ -1020,6 +1093,8 @@ static void JNICALL OnGetFrame(JNIEnv *env, jobject obj, and_stream *strm = *(and_stream**)&user_data; pjmedia_frame f; pj_uint8_t *Y, *U, *V; + pj_status_t status; + void *frame_buf, *data_buf; strm->frame_ts.u64 += strm->ts_inc; if (!strm->vid_cb.capture_cb) @@ -1039,7 +1114,7 @@ static void JNICALL OnGetFrame(JNIEnv *env, jobject obj, f.type = PJMEDIA_FRAME_TYPE_VIDEO; f.size = length; f.timestamp.u64 = strm->frame_ts.u64; - f.buf = (*env)->GetByteArrayElements(env, data, 0); + f.buf = data_buf = (*env)->GetByteArrayElements(env, data, 0); Y = (pj_uint8_t*)f.buf; U = Y + strm->vafp.plane_bytes[0]; @@ -1115,9 +1190,16 @@ static void JNICALL OnGetFrame(JNIEnv *env, jobject obj, } } + + status = pjmedia_vid_dev_conv_resize_and_rotate(&strm->conv, + f.buf, + &frame_buf); + if (status == PJ_SUCCESS) { + f.buf = frame_buf; + } (*strm->vid_cb.capture_cb)(&strm->base, strm->user_data, &f); - (*env)->ReleaseByteArrayElements(env, data, f.buf, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, data, data_buf, JNI_ABORT); } #endif /* PJMEDIA_VIDEO_DEV_HAS_ANDROID */ diff --git a/pjmedia/src/pjmedia-videodev/ios_dev.m b/pjmedia/src/pjmedia-videodev/ios_dev.m index ac4166c7..4ae06e70 100644 --- a/pjmedia/src/pjmedia-videodev/ios_dev.m +++ b/pjmedia/src/pjmedia-videodev/ios_dev.m @@ -39,9 +39,9 @@ #define DEFAULT_FPS 15 /* Define whether we should maintain the aspect ratio when rotating the image. - * For more details, please refer to vid_util.h. + * For more details, please refer to util.h. */ -#define MAINTAIN_ASPECT_RATIO PJ_TRUE +#define MAINTAIN_ASPECT_RATIO PJ_TRUE typedef struct ios_fmt_info { diff --git a/pjmedia/src/pjmedia-videodev/util.c b/pjmedia/src/pjmedia-videodev/util.c index d66a90a8..b86c22b0 100644 --- a/pjmedia/src/pjmedia-videodev/util.c +++ b/pjmedia/src/pjmedia-videodev/util.c @@ -168,11 +168,13 @@ pjmedia_vid_dev_conv_create_converter(pjmedia_vid_dev_conv *conv, pjmedia_vid_dev_conv_set_rotation(conv, PJMEDIA_ORIENT_NATURAL); - PJ_LOG(4, (THIS_FILE, "Orientation converter created: %dx%d to %dx%d", + 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)); + conv_param.dst.det.vid.size.h, + maintain_aspect_ratio? "yes": "no")); return PJ_SUCCESS; } -- cgit v1.2.3